[Pkg-javascript-commits] [sockjs-client] 18/434: Support for eventstream transport.

Tonnerre Lombard tonnerre-guest at moszumanska.debian.org
Wed Jan 8 00:46:58 UTC 2014


This is an automated email from the git hooks/post-receive script.

tonnerre-guest pushed a commit to branch master
in repository sockjs-client.

commit c6e1ed152fe2b267a9c8ca8bb625d48dc710397a
Author: Marek Majkowski <majek04 at gmail.com>
Date:   Sun Jul 24 20:37:56 2011 +0100

    Support for eventstream transport.
---
 lib/main.js                     |  5 +++
 lib/sockjs.js                   |  4 +-
 lib/trans-iframe-eventsource.js | 44 ++++++++++++++++++++
 lib/trans-iframe-within.js      | 59 ++++++++++++++++++++++++++
 lib/trans-iframe.js             | 91 +++++++++++++++++++++++++++++++++++++++++
 lib/trans-jsonp-sender.js       | 73 +++++++++++++++++++++++++++++++++
 lib/trans-jsonp.js              | 88 ++++++++-------------------------------
 lib/utils.js                    | 29 -------------
 tests-src/test-run.coffee       |  2 +-
 9 files changed, 292 insertions(+), 103 deletions(-)

diff --git a/lib/main.js b/lib/main.js
index aac4e45..4533a47 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -7,6 +7,11 @@ SockJS = (function(){
 <!-- include lib/utils.js -->
 <!-- include lib/sockjs.js -->
 <!-- include lib/trans-ws.js -->
+<!-- include lib/trans-jsonp-sender.js -->
 <!-- include lib/trans-jsonp.js -->
+<!-- include lib/trans-iframe.js -->
+<!-- include lib/trans-iframe-within.js -->
+<!-- include lib/trans-iframe-eventsource.js -->
                   return SockJS;
           })();
+if ('_sockjs_onload' in window) setTimeout(function(){_sockjs_onload();}, 0);
diff --git a/lib/sockjs.js b/lib/sockjs.js
index 567b852..afca090 100644
--- a/lib/sockjs.js
+++ b/lib/sockjs.js
@@ -5,10 +5,10 @@ var SockJS = function(url, protocols, options) {
         utils.objectExtend(this._options, options);
     }
     this._base_url = url;
-    this._server = utils.random_number_string(1000);
+    this._server = this._options.server || utils.random_number_string(1000);
     this._connid = utils.random_string(8);
     this._trans_url = this._base_url + '/' + this._server + '/' + this._connid;
-    this._protocols = ['ws', 'jsonp'];
+    this._protocols = ['ws', 'iframe-eventsource', 'jsonp'];
     switch(typeof protocols) {
     case 'undefined': break;
     case 'string': this._protocols = [protocols]; break;
diff --git a/lib/trans-iframe-eventsource.js b/lib/trans-iframe-eventsource.js
new file mode 100644
index 0000000..9539f05
--- /dev/null
+++ b/lib/trans-iframe-eventsource.js
@@ -0,0 +1,44 @@
+var EventSourceIframeTransport = SockJS['iframe-eventsource'] = function () {
+    var that = this;
+    that.protocol = 'w-iframe-eventsource';
+    that.i_constructor.apply(this, arguments);
+};
+// Inheritance.
+EventSourceIframeTransport.prototype = new IframeTransport();
+EventSourceIframeTransport.enabled = function () {
+    return (typeof EventSource === 'function') && IframeTransport.enabled();
+};
+
+
+var EventSourceTransport = FacadeJS['w-iframe-eventsource'] = function (ri, trans_url) {
+    var that = this;
+    that.ri = ri;
+    that.trans_url = trans_url;
+    var url = trans_url + '/eventsource';
+    var es = that.es = new EventSource(url);
+    es.onopen = function(e){that.ri._didOpen();};
+    es.onmessage = function(e){that.ri._didMessage(unescape(e.data.slice(1)));};
+    es.onerror = function(e){
+        // EventSource reconnects automatically.
+        that.cleanup();
+        that.ri._didClose(1001, "Socket closed.");
+    };
+    that.send_constructor(jsonPGenericSender);
+};
+// Inheritnace
+EventSourceTransport.prototype = new BufferedSender();
+
+EventSourceTransport.prototype.cleanup = function() {
+    this.es.onopen = this.es.onmessage = this.es.onerror = null;
+    this.es.close();
+    this.es = null;
+};
+
+EventSourceTransport.prototype.doClose = function(data) {
+    var that = this;
+    that.cleanup();
+    // Send didClose out of band.
+    setTimeout(function(){that.ri._didClose(1001, "Socket closed.");}, 0);
+};
+
+
diff --git a/lib/trans-iframe-within.js b/lib/trans-iframe-within.js
new file mode 100644
index 0000000..866c913
--- /dev/null
+++ b/lib/trans-iframe-within.js
@@ -0,0 +1,59 @@
+var postMessage = function (type, messages) {
+    var msg = JSON.stringify(messages);
+    if(parent !== _window) parent.postMessage(type + msg, '*');
+};
+
+var FacadeJS = function() {};
+FacadeJS.prototype._debug = function () {};
+FacadeJS.prototype._didOpen = function () {
+    postMessage('o', []);
+};
+FacadeJS.prototype._didClose = function (status, reason) {
+    postMessage('c', [''+status, reason]);
+};
+FacadeJS.prototype._didMessage = function (data) {
+    postMessage('m', [data]);
+};
+FacadeJS.prototype.send = function (data) {
+    this._transport.doSend(data);
+};
+FacadeJS.prototype.close = function () {
+    this._transport.doClose();
+};
+
+SockJS.bootstrap_iframe = function() {
+    var facade;
+    var onMessage = function(e) {
+        if(e.source !== parent) return;
+        var type = e.data.slice(0, 1);
+        var messages = JSON.parse(e.data.slice(1));
+        switch(type) {
+        case 's':
+            var version = messages[0];
+            var protocol = messages[1];
+            var trans_url = messages[2];
+            if (version !== SockJS.version) {
+                if ('console' in _window && console.error) {
+                    console.error("Incompatibile SockJS! Main site uses:" +
+                                  " \"" + version + "\", the iframe:" +
+                                  " \"" + SockJS.version + "\".");
+                }
+            }
+            facade = new FacadeJS();
+            facade._transport = new FacadeJS[protocol](facade, trans_url);
+            break;
+        case 'm':
+            facade.send(messages[0]);
+            break;
+        case 'c':
+            facade.close();
+            facade = null;
+            break;
+        }
+    };
+    utils.attachMessage(onMessage);
+
+    // Start
+    postMessage('s', []);
+};
+
diff --git a/lib/trans-iframe.js b/lib/trans-iframe.js
new file mode 100644
index 0000000..577b68c
--- /dev/null
+++ b/lib/trans-iframe.js
@@ -0,0 +1,91 @@
+// Few cool transports do work only for same-origin. In order to make
+// them working cross-domain we shall use iframe, served form the
+// remote domain. New browsers, have capabilities to communicate with
+// cross domain iframe, using postMessage(). In IE it was implemented
+// from IE 8+, but of course, IE got some details wrong:
+//    http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx
+//    http://stevesouders.com/misc/test-postmessage.php
+
+var IframeTransport = function() {};
+
+IframeTransport.prototype.i_constructor = function(ri, trans_url, base_url) {
+    var that = this;
+    that.ri = ri;
+    that.origin = utils.getOrigin(base_url);
+    that.trans_url = trans_url;
+
+    var iframe_url = base_url + '/iframe-' + SockJS.version + '.html';
+
+    var iframe = that.iframe = _document.createElement('iframe');
+    iframe.src = iframe_url;
+    iframe.style.display = 'none';
+    iframe.style.position = 'absolute';
+    iframe.onerror = function() {
+        that.cleanup();
+        that.ri._didClose(1001, "Can't load iframe");
+    };
+    iframe.onload = function() {
+        // `onload` is triggered before scripts on the iframe are
+        // executed. Give it few seconds to actually load stuff.
+        setTimeout(function() {
+                       if (that.iframe && that.iframe.onerror) that.iframe.onerror();
+                   }, 5000);
+    };
+    that.onmessage_cb = function(e){that.onmessage(e);};
+    utils.attachMessage(that.onmessage_cb);
+    _document.body.appendChild(iframe);
+};
+
+IframeTransport.prototype.cleanup = function() {
+    var that = this;
+    if (that.iframe) {
+        that.iframe.onload = that.iframe.onerror = null;
+        that.iframe.parentNode.removeChild(that.iframe);
+        utils.detachMessage(that.onmessage_cb);
+        that.onmessage_cb  = that.iframe = undefined;
+    }
+};
+
+IframeTransport.prototype.onmessage = function(e) {
+    var that = this;
+    if (e.origin !== that.origin ||
+        e.source !== that.iframe.contentWindow) return;
+    var type = e.data.slice(0, 1);
+    var msg = JSON.parse(e.data.slice(1));
+    switch(type) {
+    case 'x':
+        that.iframe.onload = that.iframe.onerror = null;
+        break;
+    case 's':
+        that.iframe.onload = that.iframe.onerror = null;
+        that.postMessage('s', [SockJS.version, that.protocol, that.trans_url]);
+        break;
+    case 'o':
+        that.ri._didOpen();
+        break;
+    case 'm':
+        that.ri._didMessage(msg[0]);
+        break;
+    case 'c':
+        that.cleanup();
+        that.ri._didClose(Number(msg[0]), msg[1]);
+        break;
+    }
+};
+
+IframeTransport.prototype.postMessage = function(type, messages) {
+    var that = this;
+    var msg = JSON.stringify(messages);
+    that.iframe.contentWindow.postMessage(type + msg, that.origin);
+};
+
+IframeTransport.prototype.doSend = function (message) {
+    this.postMessage('m', [message]);
+};
+IframeTransport.prototype.doClose = function () {
+    this.postMessage('c', []);
+};
+
+IframeTransport.enabled = function() {
+    return (typeof _window.postMessage === 'function');
+};
diff --git a/lib/trans-jsonp-sender.js b/lib/trans-jsonp-sender.js
new file mode 100644
index 0000000..e3ce6b0
--- /dev/null
+++ b/lib/trans-jsonp-sender.js
@@ -0,0 +1,73 @@
+var BufferedSender = function() {};
+BufferedSender.prototype.send_constructor = function(sender) {
+    var that = this;
+    that.send_buffer = [];
+    that.sender = sender;
+};
+BufferedSender.prototype.doSend = function(message) {
+    var that = this;
+    that.send_buffer.push(message);
+    if (typeof that.send_stop === 'undefined') {
+        that.send_schedule();
+    }
+};
+
+BufferedSender.prototype.send_schedule = function(message) {
+    var that = this;
+    if (that.send_buffer.length > 0) {
+        that.send_stop = that.sender(that.trans_url+'/send', that.send_buffer,
+                                     function() {
+                                         that.send_stop = undefined;
+                                         that.send_schedule();
+                                     });
+        that.send_buffer = [];
+    }
+};
+
+var jsonPGenericSender = function(url, messages, callback) {
+    var that = this;
+    if (!('_send_form' in that)) {
+        var form = that._send_form = _document.createElement('form');
+        var area = _document.createElement('textarea');
+        area.name = 'd';
+        form.style.display = 'none';
+        form.style.position = 'absolute';
+        form.method = 'POST';
+        form.enctype = 'application/x-www-form-urlencoded';
+        form.acceptCharset = "UTF-8";
+        form.appendChild(area);
+        _document.body.appendChild(form);
+    }
+    var form = that._send_form;
+    var id = 'a' + utils.random_string(8);
+    form.target = id;
+    form.action = url + '?i=' + id;
+
+    var iframe;
+    try {
+        // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
+        iframe = _document.createElement('<iframe name="'+ id +'">');
+    } catch(x) {
+        iframe = _document.createElement('iframe');
+        iframe.name = id;
+    }
+    iframe.id = id;
+    form.appendChild(iframe);
+    form.d.value = JSON.stringify(messages);
+    form.submit();
+
+    var completed = function() {
+        form.removeChild(iframe);
+        iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
+        iframe = undefined;
+        form.d.value = undefined;
+        form.target = undefined;
+        form.reset();
+        callback();
+    };
+    iframe.onerror = iframe.onload = completed;
+    iframe.onreadystatechange = function(e) {
+        if (iframe.readyState == 'complete') completed();
+    };
+    return completed;
+};
diff --git a/lib/trans-jsonp.js b/lib/trans-jsonp.js
index 88066af..def66cd 100644
--- a/lib/trans-jsonp.js
+++ b/lib/trans-jsonp.js
@@ -1,14 +1,26 @@
+// The simplest and most robust transport, using the well-know cross
+// domain hack - JSONP. This transport is quite inefficient - one
+// mssage could use up to one http request. But at least it works almost
+// everywhere.
+// Known limitations:
+//   o you will get a spinning cursor
+//   o for Konqueror a dumb timer is needed to detect network error
+
 var JsonPrefix = '_jp';
 
 var JsonPTransport = SockJS.jsonp = function(ri, trans_url){
     // Unavoidable namespace pollution.
     if (!(JsonPrefix in _window)) {_window[JsonPrefix] = {};}
-    this.ri = ri;
-    this.url = trans_url;
-    this._send_buffer = [];
-    this._schedule_recv();
+    var that = this;
+    that.ri = ri;
+    that.trans_url = trans_url;
+    that.send_constructor(jsonPGenericSender);
+    that._schedule_recv();
 };
 
+// Inheritnace
+JsonPTransport.prototype = new BufferedSender();
+
 JsonPTransport.prototype._schedule_recv = function() {
     var that = this;
     var callback = function(e, t) {
@@ -38,7 +50,7 @@ JsonPTransport.prototype._schedule_recv = function() {
             that._schedule_recv();
         }
     };
-    that._recv_stop = jsonPReceiverWrapper(this.url + '/jsonp',
+    that._recv_stop = jsonPReceiverWrapper(that.trans_url + '/jsonp',
                                            jsonPGenericReceiver, callback);
 };
 
@@ -54,24 +66,6 @@ JsonPTransport.prototype.doClose = function(status, reason) {
     this.ri._didClose(1001, "User requested");
 };
 
-JsonPTransport.prototype.doSend = function(message) {
-    var that = this;
-    that._send_buffer.push(message);
-    var _schedule_send = function () {
-        if (that._send_buffer.length > 0) {
-            that._send_stop = jsonPGenericSender(that.url+'/send', that._send_buffer,
-                                                 function() {
-                                                     that._send_stop = undefined;
-                                                     _schedule_send();
-                                                 });
-            that._send_buffer = [];
-        }
-    };
-    if (typeof that._send_stop === 'undefined') {
-        _schedule_send();
-    }
-};
-
 JsonPTransport.enabled = function() {
     return true;
 };
@@ -187,51 +181,3 @@ var jsonPGenericReceiver = function(url, callback) {
     }
     return close_script;
 };
-
-var jsonPGenericSender = function(url, messages, callback) {
-    var that = this;
-    if (!('_send_form' in that)) {
-        var form = that._send_form = _document.createElement('form');
-        var area = _document.createElement('textarea');
-        area.name = 'd';
-        form.style.display = 'none';
-        form.style.position = 'absolute';
-        form.method = 'POST';
-        form.enctype = 'application/x-www-form-urlencoded';
-        form.acceptCharset = "UTF-8";
-        form.appendChild(area);
-        _document.body.appendChild(form);
-    }
-    var form = that._send_form;
-    var id = 'a' + utils.random_string(8);
-    form.target = id;
-    form.action = url + '?i=' + id;
-
-    var iframe;
-    try {
-        // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
-        iframe = _document.createElement('<iframe name="'+ id +'">');
-    } catch(x) {
-        iframe = _document.createElement('iframe');
-        iframe.name = id;
-    }
-    iframe.id = id;
-    form.appendChild(iframe);
-    form.d.value = utils.stringsQuote(messages);
-    form.submit();
-
-    var completed = function() {
-        form.removeChild(iframe);
-        iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
-        iframe = undefined;
-        form.d.value = undefined;
-        form.target = undefined;
-        form.reset();
-        callback();
-    };
-    iframe.onerror = iframe.onload = completed;
-    iframe.onreadystatechange = function(e) {
-        if (iframe.readyState == 'complete') completed();
-    };
-    return completed;
-};
diff --git a/lib/utils.js b/lib/utils.js
index aff955a..2236efa 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -54,32 +54,3 @@ utils.objectExtend = function(dst, src) {
     }
     return dst;
 };
-
-// Stolen from: https://github.com/douglascrockford/JSON-js/blob/master/json2.js#L195
-var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
-var meta = {    // table of character substitutions
-            '\b': '\\b',
-            '\t': '\\t',
-            '\n': '\\n',
-            '\f': '\\f',
-            '\r': '\\r',
-            '"' : '\\"',
-            '\\': '\\\\'
-        };
-var stringQuote = utils.stringQuote = function(string) {
-        escapable.lastIndex = 0;
-        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
-            var c = meta[a];
-            return typeof c === 'string' ? c :
-                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
-        }) + '"' : '"' + string + '"';
-};
-
-// Qutote an array of strings
-utils.stringsQuote = function(strings){
-    var d = [];
-    for(var i=0; i < strings.length; i++) {
-        d.push(stringQuote(strings[i]));
-    }
-    return '[' + d.join(',') + ']';
-};
diff --git a/tests-src/test-run.coffee b/tests-src/test-run.coffee
index 43f701f..a1eccf6 100644
--- a/tests-src/test-run.coffee
+++ b/tests-src/test-run.coffee
@@ -18,5 +18,5 @@ test_protocol = (protocol) ->
         asyncTest("invalid url port", test_invalid_url_port(protocol))
 
 
-for protocol in ['ws', 'jsonp']
+for protocol in ['ws', 'jsonp', 'iframe-eventsource']
     test_protocol(protocol)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/sockjs-client.git



More information about the Pkg-javascript-commits mailing list