From 1dafbe7512f086a58212fcc66c07e348647f31ad Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Thu, 20 Sep 2012 15:55:04 -0400 Subject: [PATCH] LP#1268619: OpenSRF JS websockets plugin Adds an opensrf_ws.js handler. Requries some small modifications to opensrf.js. Load opensrf_ws.js in DojoSRF. For now, to use, add to script: OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS; Signed-off-by: Bill Erickson Signed-off-by: Galen Charlton --- src/javascript/DojoSRF.js | 1 + src/javascript/opensrf.js | 68 +++++++++++++++++++++------- src/javascript/opensrf_ws.js | 104 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 src/javascript/opensrf_ws.js diff --git a/src/javascript/DojoSRF.js b/src/javascript/DojoSRF.js index 42578f8..7e3e5c8 100644 --- a/src/javascript/DojoSRF.js +++ b/src/javascript/DojoSRF.js @@ -10,6 +10,7 @@ if(!dojo._hasResource['DojoSRF']){ dojo.require('opensrf.JSON_v1', true); dojo.require('opensrf.opensrf', true); dojo.require('opensrf.opensrf_xhr', true); + dojo.require('opensrf.opensrf_ws', true); OpenSRF.session_cache = {}; OpenSRF.CachedClientSession = function ( app ) { diff --git a/src/javascript/opensrf.js b/src/javascript/opensrf.js index c0e454c..408f0af 100644 --- a/src/javascript/opensrf.js +++ b/src/javascript/opensrf.js @@ -21,6 +21,7 @@ var OSRF_APP_SESSION_DISCONNECTED = 2; /* types of transport layers */ var OSRF_TRANSPORT_TYPE_XHR = 1; var OSRF_TRANSPORT_TYPE_XMPP = 2; +var OSRF_TRANSPORT_TYPE_WS = 3; /* message types */ var OSRF_MESSAGE_TYPE_REQUEST = 'REQUEST'; @@ -205,7 +206,10 @@ OpenSRF.Session = function() { this.state = OSRF_APP_SESSION_DISCONNECTED; }; -OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_XHR; /* default to XHR */ +OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS; +if (true || typeof WebSocket == 'undefined') + OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_XHR; + OpenSRF.Session.cache = {}; OpenSRF.Session.find_session = function(thread_trace) { return OpenSRF.Session.cache[thread_trace]; @@ -217,6 +221,8 @@ OpenSRF.Session.prototype.cleanup = function() { OpenSRF.Session.prototype.send = function(osrf_msg, args) { args = (args) ? args : {}; switch(OpenSRF.Session.transport) { + case OSRF_TRANSPORT_TYPE_WS: + return this.send_ws(osrf_msg, args); case OSRF_TRANSPORT_TYPE_XHR: return this.send_xhr(osrf_msg, args); case OSRF_TRANSPORT_TYPE_XMPP: @@ -231,8 +237,22 @@ OpenSRF.Session.prototype.send_xhr = function(osrf_msg, args) { new OpenSRF.XHRequest(osrf_msg, args).send(); }; +OpenSRF.Session.prototype.send_ws = function(osrf_msg, args) { + args.session = this; + if (this.websocket) { + this.websocket.args = args; // callbacks + this.websocket.send(osrf_msg); + } else { + this.websocket = new OpenSRF.WSRequest( + this, args, function(wsreq) { + wsreq.send(osrf_msg); + } + ); + } +}; + OpenSRF.Session.prototype.send_xmpp = function(osrf_msg, args) { - alert('xmpp transport not yet implemented'); + alert('xmpp transport not implemented'); }; @@ -254,15 +274,21 @@ OpenSRF.ClientSession.prototype.connect = function(args) { args = (args) ? args : {}; this.remote_id = null; - if(args.onconnect) + if (this.state == OSRF_APP_SESSION_CONNECTED) { + if (args.onconnect) args.onconnect(); + return true; + } + + if(args.onconnect) { this.onconnect = args.onconnect; - /* if no handler is provided, make this a synchronous call */ - if(!this.onconnect) + } else { + /* if no handler is provided, make this a synchronous call */ this.timeout = (args.timeout) ? args.timeout : 5; + } message = new osrfMessage({ - 'threadTrace' : this.reqid, + 'threadTrace' : this.last_id++, 'type' : OSRF_MESSAGE_TYPE_CONNECT }); @@ -270,17 +296,28 @@ OpenSRF.ClientSession.prototype.connect = function(args) { if(this.onconnect || this.state == OSRF_APP_SESSION_CONNECTED) return true; + return false; }; OpenSRF.ClientSession.prototype.disconnect = function(args) { - this.send( - new osrfMessage({ - 'threadTrace' : this.reqid, - 'type' : OSRF_MESSAGE_TYPE_DISCONNECT - }) - ); + + if (this.state == OSRF_APP_SESSION_CONNECTED) { + this.send( + new osrfMessage({ + 'threadTrace' : this.last_id++, + 'type' : OSRF_MESSAGE_TYPE_DISCONNECT + }) + ); + } + this.remote_id = null; + this.state = OSRF_APP_SESSION_DISCONNECTED; + + if (this.websocket) { + this.websocket.close(); + delete this.websocket; + } }; @@ -397,9 +434,10 @@ function log(msg) { } } -OpenSRF.Stack.push = function(net_msg, callbacks) { - var ses = OpenSRF.Session.find_session(net_msg.thread); - if(!ses) return; +// ses may be passed to us by the network handler +OpenSRF.Stack.push = function(net_msg, callbacks, ses) { + if (!ses) ses = OpenSRF.Session.find_session(net_msg.thread); + if (!ses) return; ses.remote_id = net_msg.from; osrf_msgs = []; diff --git a/src/javascript/opensrf_ws.js b/src/javascript/opensrf_ws.js new file mode 100644 index 0000000..d522834 --- /dev/null +++ b/src/javascript/opensrf_ws.js @@ -0,0 +1,104 @@ +/* ----------------------------------------------------------------------- + * Copyright (C) 2012 Equinox Software, Inc. + * Bill Erickson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * ----------------------------------------------------------------------- */ + +var WS_PATH = '/osrf-websocket'; + +/** + * onopen is required. no data can be sent + * until the async connection dance completes. + */ +OpenSRF.WSRequest = function(session, args, onopen) { + this.session = session; + this.args = args; + + var proto = location.protocol == 'https' ? 'wss' : 'ws'; + + var path = proto + '://' + location.host + + WS_PATH + '?service=' + this.session.service; + + try { + this.ws = new WebSocket(path); + } catch(e) { + throw new Error("WebSocket() not supported in this browser " + e); + } + + var self = this; + + this.ws.onopen = function(evt) { + onopen(self); + } + + this.ws.onmessage = function(evt) { + self.core_handler(evt.data); + } + + this.ws.onerror = function(evt) { + self.transport_error_handler(evt.data); + } + + this.ws.onclose = function(evt) { + } +}; + +OpenSRF.WSRequest.prototype.send = function(message) { + //console.log('sending: ' + js2JSON([message.serialize()])); + this.last_message = message; + this.ws.send(js2JSON([message.serialize()])); + return this; +}; + +OpenSRF.WSRequest.prototype.close = function() { + try { this.ws.close(); } catch(e) {} +} + +OpenSRF.WSRequest.prototype.core_handler = function(json) { + //console.log('received: ' + json); + + OpenSRF.Stack.push( + new OpenSRF.NetMessage(null, null, '', json), + { + onresponse : this.args.onresponse, + oncomplete : this.args.oncomplete, + onerror : this.args.onerror, + onmethoderror : this.method_error_handler() + }, + this.args.session + ); +}; + + +OpenSRF.WSRequest.prototype.method_error_handler = function() { + var self = this; + return function(req, status, status_text) { + if(self.args.onmethoderror) + self.args.onmethoderror(req, status, status_text); + + if(self.args.onerror) { + self.args.onerror( + self.last_message, self.session.service, ''); + } + }; +}; + +OpenSRF.WSRequest.prototype.transport_error_handler = function(msg) { + if(this.args.ontransporterror) { + this.args.ontransporterror(msg); + } + if(this.args.onerror) { + this.args.onerror(msg, this.session.service, ''); + } +}; + + -- 2.11.0