| |
| /* |
| * 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 |
| |
| //----------------------------------------------------------------------------- |
| class MessageDispatcher(url) |
| this._url = url |
| |
| 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._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 |
| this._opening = false |
| this._opened = true |
| |
| 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") |
| } |