From 5c14754cebfdaef167da5fb53ae28cbfc9a7d275 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Fri, 9 Nov 2012 10:52:48 -0500 Subject: [PATCH] LP#1268619: websocket JS Signed-off-by: Bill Erickson --- src/javascript/opensrf.js | 21 ++++++-- src/javascript/opensrf_ws.js | 111 ++++++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 44 deletions(-) diff --git a/src/javascript/opensrf.js b/src/javascript/opensrf.js index 4287a57..c4ccd2e 100644 --- a/src/javascript/opensrf.js +++ b/src/javascript/opensrf.js @@ -237,9 +237,14 @@ OpenSRF.Session.prototype.send_xhr = function(osrf_msg, args) { }; OpenSRF.Session.prototype.send_ws = function(osrf_msg, args) { - new OpenSRF.WSRequest( - this, args, function(wsreq) { - wsreq.send(osrf_msg); + new OpenSRF.WebSocketRequest( + this, { + onopen : function(wsreq) { wsreq.send(osrf_msg) }, + onresponse : args.onresponse, + oncomplete : args.oncomplete, + onerror : args.onerror, + onmethoderror : args.onmethoderror, + ontransporterror : args.ontransporterror, } ); }; @@ -255,9 +260,9 @@ OpenSRF.ClientSession = function(service) { this.remote_id = null; this.locale = OpenSRF.locale || 'en-US'; this.last_id = 0; - this.thread = Math.random() + '' + new Date().getTime(); this.requests = []; this.onconnect = null; + this.thread = Math.random() + '' + new Date().getTime(); OpenSRF.Session.cache[this.thread] = this; }; OpenSRF.set_subclass('OpenSRF.ClientSession', 'OpenSRF.Session'); @@ -437,6 +442,11 @@ OpenSRF.Stack.push = function(net_msg, callbacks, ses) { try { osrf_msgs = JSON2js(net_msg.body); + if (OpenSRF.Session.transport == OSRF_TRANSPORT_TYPE_WS) { + // WebSocketRequests wrap the content + osrf_msgs = osrf_msgs.osrf_msg; + } + } catch(E) { log('Error parsing OpenSRF message body as JSON: ' + net_msg.body + '\n' + E); @@ -510,8 +520,9 @@ OpenSRF.Stack.handle_message = function(ses, osrf_msg, callbacks) { req = ses.find_request(osrf_msg.threadTrace()); if(req) { req.response_queue.push(osrf_msg.payload()); - if(callbacks.onresponse) + if(callbacks.onresponse) { return callbacks.onresponse(req); + } } } }; diff --git a/src/javascript/opensrf_ws.js b/src/javascript/opensrf_ws.js index 808e10c..79c80f4 100644 --- a/src/javascript/opensrf_ws.js +++ b/src/javascript/opensrf_ws.js @@ -13,16 +13,16 @@ * GNU General Public License for more details. * ----------------------------------------------------------------------- */ +// opensrf defaults var WEBSOCKET_URL_PATH = '/osrf-websocket-translator'; var WEBSOCKET_PORT = 7680; var WEBSOCKET_PORT_SSL = 7682; -var wsConnections = {}; // Create the websocket and connect to the server // args.onopen is required // if args.default is true, use the default handle inst -OpenSRF.WebSocketConnection = function(handlers, connectArgs) { +OpenSRF.WebSocketConnection = function(connectArgs, handlers) { connectArgs = connectArgs || {}; this.handlers = handlers; @@ -30,10 +30,18 @@ OpenSRF.WebSocketConnection = function(handlers, connectArgs) { var path = connectArgs.path || WEBSOCKET_URL_PATH; var port = connectArgs.port || (secure ? WEBSOCKET_PORT_SSL : WEBSOCKET_PORT); var host = connectArgs.host || location.host; + var proto = (secure) ? 'wss' : 'ws'; this.path = proto + '://' + host + ':' + port + path; this.setupSocket(); - wsConnection[connectArgs.name] = this; + OpenSRF.WebSocketConnection.pool[connectArgs.name] = this; +}; + +// global pool of connection objects; name => connection map +OpenSRF.WebSocketConnection.pool = {}; + +OpenSRF.WebSocketConnection.defaultConnection = function() { + return OpenSRF.WebSocketConnection.pool['default']; } /** @@ -53,14 +61,13 @@ OpenSRF.WebSocketConnection.prototype.setupSocket = function() { this.socket.onmessage = this.handlers.onmessage; this.socket.onerror = this.handlers.onerror; this.socket.onclose = this.handlers.onclose; -} +}; /** shut it down */ OpenSRF.WebSocketConnection.prototype.destroy = function() { - if (this.socket.readyState == this.socket.OPEN) { - this.socket.close(); - delete wsConnections[this.name]; -} + this.socket.close(); + delete OpenSRF.WebSocketConnection.pool[this.name]; +}; /** * Creates the request object, but does not connect or send anything @@ -74,43 +81,61 @@ OpenSRF.WebSocketRequest = function(session, handlers, connectionArgs) { } OpenSRF.WebSocketRequest.prototype.setupConnection = function(connectionArgs) { + var self = this; var cname = connectionArgs.name || 'default'; - this.wsc = wsConnections[cname]; + this.wsc = OpenSRF.WebSocketConnection.pool[cname]; if (this.wsc) { // we have a WebSocketConnection. - if (this.wsc.socket.readyState == this.wsc.socket.CLOSED) { - // reset the connection - this.wsc.setupSocket(); - - } else { - - if (this.handlers.onopen) { - // socket is already open, but the user is expecting an onopen event + console.log('socket readySate = ' + this.wsc.socket.readyState); + switch (this.wsc.socket.readyState) { + + case this.wsc.socket.CONNECTING: + // replace the original onopen handler with a new combined handler + var orig_open = this.wsc.socket.onopen; + this.wsc.socket.onopen = function() { + console.log('combined onopen'); + orig_open(); + console.log('combined onopen 2'); + self.handlers.onopen(self); + console.log('combined onopen ' + self.handlers.onopen); + }; + break; + + case this.wsc.socket.OPEN: + // user is expecting an onopen event. socket is + // already open, so we have to manufacture one. this.handlers.onopen(this); - } + break; + + default: + console.log('WebSocket is no longer connecting; reconnecting'); + this.wsc.setupSocket(); } } else { // no connection found if (cname == 'default' || connectionArgs.useDefaultHandlers) { // create the default handle - this.wsc = new OpenSRF.WebSocketConnection(cname, { - onopen : function(evt) { - if (self.handlers.onopen) - self.handlers.onopen(self); - }, - onmessage : function(evt) { - self.core_handler(evt.data); - }, - onerror : function(evt) { - self.transport_error_handler(evt.data); - }, - onclose : function(evt) { - if (self.onclose) self.onclose(self); - } - }); + this.wsc = new OpenSRF.WebSocketConnection( + {name : cname}, { + onopen : function(evt) { + if (self.handlers.onopen) + self.handlers.onopen(self); + }, + onmessage : function(evt) { + self.core_handler(evt.data); + }, + onerror : function(evt) { + self.transport_error_handler(evt.data); + }, + onclose : function(evt) { + if (self.handlers.onclose) + self.handlers.onclose(self); + } + } + ); } else { throw new Error("No such WebSocketConnection '" + cname + "'"); @@ -120,24 +145,32 @@ OpenSRF.WebSocketRequest.prototype.setupConnection = function(connectionArgs) { OpenSRF.WebSocketRequest.prototype.send = function(message) { - console.log('sending: ' + js2JSON([message.serialize()])); this.last_message = message; - this.wsc.socket.send(js2JSON([message.serialize()])); + + var wrapper = { + service : this.session.service, + thread : this.session.thread, + osrf_msg : [message.serialize()] + }; + + var json = js2JSON(wrapper); + console.log('sending: ' + json); + + // drop it on the wire + this.wsc.socket.send(json); return this; }; OpenSRF.WebSocketRequest.prototype.core_handler = function(json) { - console.log('received: ' + json); - OpenSRF.Stack.push( - new OpenSRF.NetMessage(null, null, '', json), + new OpenSRF.NetMessage(null, null, this.session.thread, json), { onresponse : this.handlers.onresponse, oncomplete : this.handlers.oncomplete, onerror : this.handlers.onerror, onmethoderror : this.method_error_handler() }, - this.handlers.session + this.session ); }; -- 2.11.0