blob: c207e0109fa410c1447a2a680fcf8e7e82c4d9f5 [file] [log] [blame]
/*
* weinre is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2010, 2011 IBM Corporation
*/
requireClass ./Weinre
requireClass ./WebSocketXhr
requireClass ./IDLTools
requireClass ./Binding
requireClass ./Ex
requireClass ./Callback
//-----------------------------------------------------------------------------
class MessageDispatcher(url, id)
if (!id) {
id = "anonymous"
}
this._url = url
this._id = id
this.error = null
this._opening = false
this._opened = false
this._closed = false
this._interfaces = {}
this._open()
//-----------------------------------------------------------------------------
init
var Verbose = false
var InspectorBackend
//-----------------------------------------------------------------------------
static method setInspectorBackend(inspectorBackend)
InspectorBackend = inspectorBackend
//-----------------------------------------------------------------------------
static method verbose(value)
if (arguments.length >= 1) {
Verbose = !!value
}
return Verbose
//-----------------------------------------------------------------------------
method _open
if (this._opened || this._opening) return
if (this._closed) throw new Ex(arguments, "socket has already been closed")
this._opening = true
this._socket = new WebSocketXhr(this._url, this._id)
this._socket.addEventListener("open", Binding(this, "_handleOpen"))
this._socket.addEventListener("error", Binding(this, "_handleError"))
this._socket.addEventListener("message", Binding(this, "_handleMessage"))
this._socket.addEventListener("close", Binding(this, "_handleClose"))
//-----------------------------------------------------------------------------
method close
if (this._closed) return
this._opened = false
this._closed = true
this._socket.close()
//-----------------------------------------------------------------------------
method send(data)
this._socket.send(data)
//-----------------------------------------------------------------------------
method getWebSocket
return this._socket
//-----------------------------------------------------------------------------
method registerInterface(intfName, intf, validate)
if (validate) IDLTools.validateAgainstIDL(intf.constructor, intfName)
if (this._interfaces[intfName]) throw new Ex(arguments, "interface " + intfName + " has already been registered")
this._interfaces[intfName] = intf
//-----------------------------------------------------------------------------
method createProxy(intfName)
var proxy = {}
IDLTools.buildProxyForIDL(proxy, intfName)
var self = this
proxy.__invoke = function __invoke(intfName, methodName, args) {
self._sendMethodInvocation(intfName, methodName, args)
}
return proxy
//-----------------------------------------------------------------------------
method _sendMethodInvocation(intfName, methodName, args)
if (typeof intfName != "string") throw new Ex(arguments, "expecting intf parameter to be a string")
if (typeof methodName != "string") throw new Ex(arguments, "expecting method parameter to be a string")
var data = {
"interface": intfName,
"method": methodName,
"args": args
}
data = JSON.stringify(data)
this._socket.send(data)
if (Verbose) {
Weinre.logDebug(this.constructor.name + "[" + this._url + "]: send " + intfName + "." + methodName + "(" + JSON.stringify(args) + ")")
}
//-----------------------------------------------------------------------------
method getState
if (this._opening) return "opening"
if (this._opened) return "opened"
if (this._closed) return "closed"
return "unknown"
//-----------------------------------------------------------------------------
method isOpen
return this._opened == true
//-----------------------------------------------------------------------------
method _handleOpen(event)
this._opening = false
this._opened = true
this.channel = event.channel
Callback.setConnectorChannel(this.channel)
if (Verbose) {
Weinre.logDebug(this.constructor.name + "[" + this._url + "]: opened")
}
//-----------------------------------------------------------------------------
method _handleError(message)
this.error = message
this.close()
if (Verbose) {
Weinre.logDebug(this.constructor.name + "[" + this._url + "]: error: " + message)
}
//-----------------------------------------------------------------------------
method _handleMessage(message)
var data
try {
data = JSON.parse(message.data)
}
catch (e) {
throw new Ex(arguments, "invalid JSON data received: " + e + ": '" + message.data + "'")
}
var intfName = data["interface"]
var methodName = data.method
var args = data.args
var methodSignature = intfName + "." + methodName + "()"
var intf = this._interfaces.hasOwnProperty(intfName) && this._interfaces[intfName]
if (!intf && InspectorBackend && intfName.match(/.*Notify/)) {
intf = InspectorBackend.getRegisteredDomainDispatcher(intfName.substr(0,intfName.length-6))
}
if (!intf) {
Weinre.logWarning("weinre: request for non-registered interface:" + methodSignature)
return
}
methodSignature = intf.constructor.name + "." + methodName + "()"
var method = intf[methodName]
if (typeof method != "function") {
Weinre.notImplemented(methodSignature)
return
}
try {
method.apply(intf, args)
}
catch (e) {
Weinre.logError("weinre: invocation exception on " + methodSignature + ": " + e)
}
if (Verbose) {
Weinre.logDebug(this.constructor.name + "[" + this._url + "]: recv " + intfName + "." + methodName + "(" + JSON.stringify(args) + ")")
}
//-----------------------------------------------------------------------------
method _handleClose
this._reallyClosed = true
if (Verbose) {
Weinre.logDebug(this.constructor.name + "[" + this._url + "]: closed")
}