[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