blob: b25d17f7726aca15d311359b61968d2537757e77 [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
*/
require ./Weinre
require ./WebSocketXhr
require ./IDLTools
require ./Binding
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class Socket(url)
this._url = url
this.error = null
this._opening = false
this._opened = false
this._closed = false
this._interfaces = {}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static
var Verbose = false
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
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 Error("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 Error("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 Error("expecting intf parameter to be a string")
if (typeof methodName != "string") throw new Error("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) {
console.log(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) {
console.log(this.constructor.name + "[" + this._url + "]: opened")
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
method _handleError(message)
this.error = message
this.close()
if (Verbose) {
console.log(this.constructor.name + "[" + this._url + "]: error: " + message)
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
method _handleMessage(message)
var data
try {
data = JSON.parse(message.data)
}
catch (e) {
throw new Error("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[intfName]
if (!intf) throw new Error("request for non-registered interface:" + methodSignature)
var method = intf[methodName]
if (typeof method != "function") throw new Error("request for unknown method on interface: " + methodSignature)
try {
method.apply(intf, args)
}
catch (e) {
console.log("Weinre.Socket._handleMessage() invocation exception: " + e)
}
if (Verbose) {
console.log(this.constructor.name + "[" + this._url + "]: recv " + intfName + "." + methodName + "(" + JSON.stringify(args) + ")")
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
method _handleClose
this._reallyClosed = true
if (Verbose) {
console.log(this.constructor.name + "[" + this._url + "]: closed")
}