faye 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye might be problematic. Click here for more details.
- data/History.txt +12 -0
- data/Manifest.txt +5 -0
- data/README.txt +25 -7
- data/Rakefile +1 -0
- data/build/faye-client-min.js +1 -1
- data/build/faye.js +367 -186
- data/examples/node/faye-client-min.js +1 -1
- data/examples/node/faye.js +367 -186
- data/examples/shared/public/index.html +1 -0
- data/examples/shared/public/mootools.js +4329 -0
- data/examples/shared/public/prototype.js +4874 -0
- data/jake.yml +3 -1
- data/lib/faye-client-min.js +1 -1
- data/lib/faye.rb +5 -2
- data/lib/faye/channel.rb +4 -0
- data/lib/faye/client.rb +53 -29
- data/lib/faye/connection.rb +16 -37
- data/lib/faye/rack_adapter.rb +33 -28
- data/lib/faye/server.rb +24 -23
- data/lib/faye/timeouts.rb +21 -0
- data/lib/faye/transport.rb +17 -4
- data/test/scenario.js +73 -37
- data/test/scenario.rb +104 -0
- data/test/test_channel.rb +7 -1
- data/test/test_clients.js +28 -10
- data/test/test_clients.rb +154 -0
- data/test/test_grammar.rb +1 -1
- data/test/test_server.rb +8 -7
- metadata +17 -11
data/jake.yml
CHANGED
@@ -14,6 +14,8 @@ packages:
|
|
14
14
|
- util/class
|
15
15
|
- util/deferrable
|
16
16
|
- util/observable
|
17
|
+
- util/logging
|
18
|
+
- timeouts
|
17
19
|
- channel
|
18
20
|
- namespace
|
19
21
|
- transport
|
@@ -25,8 +27,8 @@ packages:
|
|
25
27
|
- server
|
26
28
|
- connection
|
27
29
|
- error
|
28
|
-
- transports/node
|
29
30
|
- node_adapter
|
31
|
+
- transports/node
|
30
32
|
faye-client:
|
31
33
|
extends: core
|
32
34
|
files:
|
data/lib/faye-client-min.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.1',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Deferrable={callback:function(a,b){if(this._t==='succeeded')return a.apply(b,this._m);this._9=this._9||[];this._9.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._t=c;this._m=b;if(c!=='succeeded')return;if(!this._9)return;Faye.each(this._9,function(a){a[0].apply(a[1],this._m)},this);this._9=[]}};Faye.Observable={on:function(a,b,c){this._0=this._0||{};var d=this._0[a]=this._0[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._0||!this._0[a])return;if(!b){delete this._0[a];return}var d=this._0[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._0||!this._0[c])return;Faye.each(this._0[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._1=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._1!==undefined)d.call(f,c,this._1)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._1:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._1=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._1===undefined)?[]:[this._1];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._1!==undefined)g.push(b._1)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._1!==undefined)g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._1);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._n={}},generate:function(){var a=Faye.random();while(this._n.hasOwnProperty(a))a=Faye.random();return this._n[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._f=a;this._6=b},send:function(c,d,f){if(!(c instanceof Array)&&!c.id)c.id=this._f._o.generate();this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){if(a.id===c.id)d.call(f,a);if(a.advice)this._f.handleAdvice(a.advice);if(a.data&&a.channel)this._f.sendToSubscribers(a)},this)},this)}}),{get:function(c,d){var f=c._6;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._g,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._g[a]=b;b.prototype.connectionType=a},_g:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._g,function(a,b){c.push(a)});return c}});Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._2=this.UNCONNECTED;this._o=new Faye.Namespace();this._h=[];this._a=new Faye.Channel.Tree();this._p=[];this._7={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2!==this.UNCONNECTED)return;this._2=this.CONNECTING;var d=this;this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._2=this.UNCONNECTED}this._2=this.CONNECTED;this._8=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2===this.DISCONNECTED)return;if(this._7.reconnect===this.HANDSHAKE||this._2===this.UNCONNECTED)return this.handshake(function(){this.connect(b,c)},this);if(this._2===this.CONNECTING)return this.callback(b,c);if(this._2!==this.CONNECTED)return;this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(b)b.call(c);if(this._i)return;this._i=this._o.generate();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._8,connectionType:this._4.connectionType,id:this._i},function(a){delete this._i;setTimeout(function(){d.connect()},this._7.interval)},this)},disconnect:function(){if(this._2!==this.CONNECTED)return;this._2=this.DISCONNECTED;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._8});this._a=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,[d,f])},this)},this)},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,null)},this)},this)},this)},publish:function(b,c){this.connect(function(){this._j([b]);this._u({channel:b,data:c,clientId:this._8});if(this._q)return;var a=this;this._q=setTimeout(function(){delete a._q;a._v()},this.MAX_DELAY*1000)},this)},handleAdvice:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this.HANDSHAKE)this._8=null},sendToSubscribers:function(b){var c=this._a.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},_u:function(a){this._h.push(a)},_v:function(){this._4.send(this._h);this._h=[]},_j:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.Event={_b:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._b.push({_c:a,_k:b,_w:c,_d:d,_r:f})},detach:function(a,b,c,d){var f=this._b.length,g;while(f--){g=this._b[f];if((a&&a!==g._c)||(b&&b!==g._k)||(c&&c!==g._w)||(d&&d!==g._d))continue;if(g._c.removeEventListener)g._c.removeEventListener(g._k,g._r,false);else g._c.detachEvent('on'+g._k,g._r);this._b.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._e=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._p=(typeof d==='function')?{success:d}:d;this._d=f||null;this._3=null},send:function(){if(this._l)return;var a=this._6.pathname,b=this._6.queryString();if(this._e==='GET')a+='?'+b;var c=this._e==='POST'?b:'';this._l=true;this._3=Faye.XHR.getXhrObject();this._3.open(this._e,a,true);if(this._e==='POST')this._3.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._3.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._l=false;d._x();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._3.send(c)},abort:function(){this._3.abort()},_x:function(){var a=this._p;if(!a)return;return this.success()?a.success&&a.success.call(this._d,this):a.failure&&a.failure.call(this._d,this)},waiting:function(){return!!this._l},complete:function(){return this._3&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._3.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._3.responseText},status:function(){if(!this.complete())return null;return this._3.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)};Faye.XHR.request('post',this._6,f,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)},g=document.getElementsByTagName('head')[0],k=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._6,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(k);if(c)c.call(d,a)};h.params.jsonp=i;k.type='text/javascript';k.src=h.toURL();g.appendChild(k)}}),{_s:0,getCallbackName:function(){this._s+=1;return'__jsonp'+this._s+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
|
1
|
+
if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.2',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}},toJSON:function(a){if(this.stringify)return this.stringify(a,function(key,value){return(this[key]instanceof Array)?this[key]:value});return JSON.stringify(a)},timestamp:function(){var b=new Date(),c=b.getFullYear(),d=b.getMonth()+1,f=b.getDate(),g=b.getHours(),j=b.getMinutes(),i=b.getSeconds();var h=function(a){return a<10?'0'+a:String(a)};return h(c)+'-'+h(d)+'-'+h(f)+' '+h(g)+':'+h(j)+':'+h(i)}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Deferrable={callback:function(a,b){if(this._w==='succeeded')return a.apply(b,this._o);this._a=this._a||[];this._a.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._w=c;this._o=b;if(c!=='succeeded')return;if(!this._a)return;Faye.each(this._a,function(a){a[0].apply(a[1],this._o)},this);this._a=[]}};Faye.Observable={on:function(a,b,c){this._2=this._2||{};var d=this._2[a]=this._2[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._2||!this._2[a])return;if(!b){delete this._2[a];return}var d=this._2[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._2||!this._2[c])return;Faye.each(this._2[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Logging={LOG_LEVELS:{error:3,warn:2,info:1,debug:0},logLevel:'error',log:function(a,b){if(!Faye.logger)return;var c=Faye.Logging.LOG_LEVELS;if(c[Faye.Logging.logLevel]>c[b])return;var d='['+b.toUpperCase()+'] [Faye',f=null;for(var g in Faye){if(f)continue;if(typeof Faye[g]!=='function')continue;if(this instanceof Faye[g])f=g}if(f)d+='.'+f;d+='] ';Faye.logger(Faye.timestamp()+' '+d+a)},error:function(a){this.log(a,'error')},warn:function(a){this.log(a,'warn')},info:function(a){this.log(a,'info')},debug:function(a){this.log(a,'debug')}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._6=this._6||{};if(this._6.hasOwnProperty(a))return;var f=this;this._6[a]=setTimeout(function(){delete f._6[a];c.call(d)},1000*b)},removeTimeout:function(a){this._6=this._6||{};var b=this._6[a];if(!b)return;clearTimeout(b);delete this._6[a]}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._3=a;this._8={}},eachChild:function(c,d){Faye.each(this._8,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._3!==undefined)d.call(f,c,this._3)},getKeys:function(){return this.map(function(a,b){return'/'+a.join('/')})},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._3:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._3=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._8[a[0]];if(!c&&!b)return null;if(!c)c=this._8[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._3===undefined)?[]:[this._3];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._8,function(a,b){if(b._3!==undefined)g.push(b._3)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._3!==undefined)g.pop();return g}Faye.each(this._8,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._8['**'])g.push(this._8['**']._3);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._p={}},generate:function(){var a=Faye.random();while(this._p.hasOwnProperty(a))a=Faye.random();return this._p[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this.debug('Created new transport for '+b);this._b=a;this._4=b},send:function(f,g,j){if(!(f instanceof Array)&&!f.id)f.id=this._b._q.generate();this.debug('Client '+this._b._0+' sending message to '+this._4+': '+Faye.toJSON(f));this.request(f,function(b){this.debug('Client '+this._b._0+' received from '+this._4+': '+Faye.toJSON(b));if(!g)return;var c=[],d=true;Faye.each([].concat(b),function(a){if(a.id===f.id){if(g.call(j,a)===false)d=false}if(a.advice)this._b.handleAdvice(a.advice);if(a.data&&a.channel)c.push(a)},this);if(d)this._b.deliverMessages(c)},this)}}),{get:function(c,d){var f=c._4;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._i,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._i[a]=b;b.prototype.connectionType=a},_i:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._i,function(a,b){c.push(a)});return c}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',CONNECTION_TIMEOUT:60.0,DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a,b){this.info('New client created for '+a);this._4=a||this.DEFAULT_ENDPOINT;this._x=b||{};this._r=this._x.timeout||this.CONNECTION_TIMEOUT;this._7=Faye.Transport.get(this);this._1=this.UNCONNECTED;this._q=new Faye.Namespace();this._j=[];this._c=new Faye.Channel.Tree();this._s=[];this._9={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var d=this;this.info('Initiating handshake with '+this._4);this._7.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){this.info('Handshake unsuccessful');setTimeout(function(){d.handshake(b,c)},this._9.interval);return this._1=this.UNCONNECTED}this._1=this.CONNECTED;this._0=a.clientId;this._7=Faye.Transport.get(this,a.supportedConnectionTypes);this.info('Handshake successful: '+this._0);if(b)b.call(c)},this)},connect:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1===this.DISCONNECTED)return;if(this._9.reconnect===this.HANDSHAKE||this._1===this.UNCONNECTED){this._t();return this.handshake(function(){this.connect(b,c)},this)}if(this._1===this.CONNECTING)return this.callback(b,c);if(this._1!==this.CONNECTED)return;this.info('Calling deferred actions for '+this._0);this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(b)b.call(c);if(this._d)return;this._d=this._q.generate();var d=this;this.info('Initiating connection for '+this._0);this._7.send({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._7.connectionType,id:this._d},this._k(function(a){delete this._d;this.removeTimeout('reconnect');this.info('Closed connection for '+this._0);setTimeout(function(){d.connect()},this._9.interval)}));this._t()},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting '+this._0);this._7.send({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for '+this._0);this._c=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client '+this._0+' attempting to subscribe to ['+c.join(', ')+']');this._7.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful||!d)return;this.info('Subscription acknowledged for '+this._0+' to ['+c.join(', ')+']');c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,[d,f])},this)}))},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client '+this._0+' attempting to unsubscribe from ['+c.join(', ')+']');this._7.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful)return;this.info('Unsubscription acknowledged for '+this._0+' from ['+c.join(', ')+']');c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,null)},this)}))},this)},publish:function(a,b){this.connect(function(){this._l([a]);this.info('Client '+this._0+' queueing published message to '+a+': '+Faye.toJSON(b));this._y({channel:a,data:b,clientId:this._0});this.addTimeout('publish',this.MAX_DELAY,this._z,this)},this)},handleAdvice:function(a){Faye.extend(this._9,a);if(this._9.reconnect===this.HANDSHAKE)this._0=null},deliverMessages:function(d){Faye.each(d,function(b){this.info('Client '+this._0+' calling listeners for '+b.channel+' with '+Faye.toJSON(b.data));var c=this._c.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},this)},_t:function(){this.addTimeout('reconnect',this._r,function(){delete this._d;delete this._0;this._1=this.UNCONNECTED;this.info('Server took >'+this._r+'s to reply to connection for '+this._0+': attempting to reconnect');this.subscribe(this._c.getKeys())},this)},_y:function(a){this._j.push(a)},_z:function(){this._7.send(this._j);this._j=[]},_l:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})},_k:function(b){var c=this;return function(a){if(a.clientId!==c._0)return false;b.call(c,a);return true}}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.extend(Faye.Client.prototype,Faye.Timeouts);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.Event={_e:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._e.push({_f:a,_m:b,_A:c,_g:d,_u:f})},detach:function(a,b,c,d){var f=this._e.length,g;while(f--){g=this._e[f];if((a&&a!==g._f)||(b&&b!==g._m)||(c&&c!==g._A)||(d&&d!==g._g))continue;if(g._f.removeEventListener)g._f.removeEventListener(g._m,g._u,false);else g._f.detachEvent('on'+g._m,g._u);this._e.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var j=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};j('protocol',/^https?\:\/+/);j('hostname',/^[^\/\:]+/);j('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,k={};while(o--){i=n[o].split('=');k[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}if(typeof f==='object')Faye.extend(k,f);g.pathname=h;g.params=k;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._h=a.toUpperCase();this._4=Faye.URI.parse(b,c);this._B=(typeof c==='string')?c:null;this._s=(typeof d==='function')?{success:d}:d;this._g=f||null;this._5=null},send:function(){if(this._n)return;var a=this._4.pathname,b=this._4.queryString();if(this._h==='GET')a+='?'+b;var c=(this._h==='POST')?(this._B||b):'';this._n=true;this._5=Faye.XHR.getXhrObject();this._5.open(this._h,a,true);if(this._h==='POST')this._5.setRequestHeader('Content-Type','application/json');var d=this,f=function(){if(d._5.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._n=false;d._C();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._5.send(c)},abort:function(){this._5.abort()},_C:function(){var a=this._s;if(!a)return;return this.success()?a.success&&a.success.call(this._g,this):a.failure&&a.failure.call(this._g,this)},waiting:function(){return!!this._n},complete:function(){return this._5&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._5.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._5.responseText},status:function(){if(!this.complete())return null;return this._5.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,k,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,j=k,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}k+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':k?'[\n'+k+i.join(',\n'+k)+'\n'+j+']':'['+i.join(',')+']';k=j;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(k?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(k?': ':':')+f)}}}}f=i.length===0?'{}':k?'{\n'+k+i.join(',\n'+k)+'\n'+j+'}':'{'+i.join(',')+'}';k=j;return f}}Faye.stringify=function(a,b,c){var d;k='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})};if(typeof JSON.stringify!=='function'){JSON.stringify=Faye.stringify}if(typeof JSON.parse!=='function'){JSON.parse=function(g,j){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return j.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof j==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._4,Faye.toJSON(b),function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:Faye.toJSON(b)},g=document.getElementsByTagName('head')[0],j=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._4,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(j);if(c)c.call(d,a)};h.params.jsonp=i;j.type='text/javascript';j.src=h.toURL();g.appendChild(j)}}),{_v:0,getCallbackName:function(){this._v+=1;return'__jsonp'+this._v+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
|
data/lib/faye.rb
CHANGED
@@ -5,7 +5,7 @@ require 'rubygems'
|
|
5
5
|
require 'eventmachine'
|
6
6
|
|
7
7
|
module Faye
|
8
|
-
VERSION = '0.3.
|
8
|
+
VERSION = '0.3.2'
|
9
9
|
|
10
10
|
ROOT = File.expand_path(File.dirname(__FILE__))
|
11
11
|
|
@@ -14,7 +14,10 @@ module Faye
|
|
14
14
|
JSONP_CALLBACK = 'jsonpcallback'
|
15
15
|
CONNECTION_TYPES = %w[long-polling callback-polling]
|
16
16
|
|
17
|
-
%w[grammar namespace
|
17
|
+
%w[ timeouts grammar namespace
|
18
|
+
server channel connection
|
19
|
+
error client transport
|
20
|
+
].each do |lib|
|
18
21
|
require File.join(ROOT, 'faye', lib)
|
19
22
|
end
|
20
23
|
|
data/lib/faye/channel.rb
CHANGED
data/lib/faye/client.rb
CHANGED
@@ -1,23 +1,26 @@
|
|
1
1
|
module Faye
|
2
2
|
class Client
|
3
3
|
include EventMachine::Deferrable
|
4
|
+
include Timeouts
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
UNCONNECTED = 1
|
7
|
+
CONNECTING = 2
|
8
|
+
CONNECTED = 3
|
9
|
+
DISCONNECTED = 4
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
DISCONNECTED = 4
|
11
|
+
HANDSHAKE = 'handshake'
|
12
|
+
RETRY = 'retry'
|
13
|
+
NONE = 'none'
|
12
14
|
|
13
|
-
|
14
|
-
RETRY = 'retry'
|
15
|
-
NONE = 'none'
|
15
|
+
CONNECTION_TIMEOUT = 60.0
|
16
16
|
|
17
17
|
attr_reader :endpoint, :namespace
|
18
18
|
|
19
|
-
def initialize(endpoint = nil)
|
20
|
-
@endpoint
|
19
|
+
def initialize(endpoint = nil, options = {})
|
20
|
+
@endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
|
21
|
+
@options = options
|
22
|
+
@timeout = @options[:timeout] || CONNECTION_TIMEOUT
|
23
|
+
|
21
24
|
@transport = Transport.get(self)
|
22
25
|
@state = UNCONNECTED
|
23
26
|
@namespace = Namespace.new
|
@@ -60,7 +63,7 @@ module Faye
|
|
60
63
|
}) do |response|
|
61
64
|
|
62
65
|
unless response['successful']
|
63
|
-
add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
|
66
|
+
EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
|
64
67
|
return @state = UNCONNECTED
|
65
68
|
end
|
66
69
|
|
@@ -86,6 +89,7 @@ module Faye
|
|
86
89
|
@state == DISCONNECTED
|
87
90
|
|
88
91
|
if @advice['reconnect'] == HANDSHAKE or @state == UNCONNECTED
|
92
|
+
begin_reconnect_timeout
|
89
93
|
return handshake { connect(&block) }
|
90
94
|
end
|
91
95
|
|
@@ -105,10 +109,13 @@ module Faye
|
|
105
109
|
'connectionType' => @transport.connection_type,
|
106
110
|
'id' => @connection_id
|
107
111
|
|
108
|
-
}
|
112
|
+
}, &verify_client_id { |response|
|
109
113
|
@connection_id = nil
|
110
|
-
|
111
|
-
|
114
|
+
remove_timeout(:reconnect)
|
115
|
+
EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
|
116
|
+
})
|
117
|
+
|
118
|
+
begin_reconnect_timeout
|
112
119
|
end
|
113
120
|
|
114
121
|
# Request Response
|
@@ -150,12 +157,12 @@ module Faye
|
|
150
157
|
'clientId' => @client_id,
|
151
158
|
'subscription' => channels
|
152
159
|
|
153
|
-
}
|
154
|
-
if response['successful']
|
160
|
+
}, &verify_client_id { |response|
|
161
|
+
if response['successful'] and block
|
155
162
|
channels = [response['subscription']].flatten
|
156
163
|
channels.each { |channel| @channels[channel] = block }
|
157
164
|
end
|
158
|
-
|
165
|
+
})
|
159
166
|
}
|
160
167
|
end
|
161
168
|
|
@@ -179,12 +186,12 @@ module Faye
|
|
179
186
|
'clientId' => @client_id,
|
180
187
|
'subscription' => channels
|
181
188
|
|
182
|
-
}
|
189
|
+
}, &verify_client_id { |response|
|
183
190
|
if response['successful']
|
184
191
|
channels = [response['subscription']].flatten
|
185
192
|
channels.each { |channel| @channels[channel] = nil }
|
186
193
|
end
|
187
|
-
|
194
|
+
})
|
188
195
|
}
|
189
196
|
end
|
190
197
|
|
@@ -204,12 +211,7 @@ module Faye
|
|
204
211
|
'clientId' => @client_id
|
205
212
|
})
|
206
213
|
|
207
|
-
|
208
|
-
|
209
|
-
@timeout = add_timer(Connection::MAX_DELAY) do
|
210
|
-
@timeout = nil
|
211
|
-
flush!
|
212
|
-
end
|
214
|
+
add_timeout(:publish, Connection::MAX_DELAY) { flush! }
|
213
215
|
}
|
214
216
|
end
|
215
217
|
|
@@ -218,13 +220,24 @@ module Faye
|
|
218
220
|
@client_id = nil if @advice['reconnect'] == HANDSHAKE
|
219
221
|
end
|
220
222
|
|
221
|
-
def
|
222
|
-
|
223
|
-
|
223
|
+
def deliver_messages(messages)
|
224
|
+
messages.each do |message|
|
225
|
+
channels = @channels.glob(message['channel'])
|
226
|
+
channels.each { |callback| callback.call(message['data']) }
|
227
|
+
end
|
224
228
|
end
|
225
229
|
|
226
230
|
private
|
227
231
|
|
232
|
+
def begin_reconnect_timeout
|
233
|
+
add_timeout(:reconnect, @timeout) do
|
234
|
+
@connection_id = nil
|
235
|
+
@client_id = nil
|
236
|
+
@state = UNCONNECTED
|
237
|
+
subscribe(@channels.keys)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
228
241
|
def enqueue(message)
|
229
242
|
@outbox << message
|
230
243
|
end
|
@@ -241,6 +254,17 @@ module Faye
|
|
241
254
|
end
|
242
255
|
end
|
243
256
|
|
257
|
+
def verify_client_id(&block)
|
258
|
+
lambda do |response|
|
259
|
+
if response['clientId'] != @client_id
|
260
|
+
false
|
261
|
+
else
|
262
|
+
block.call(response)
|
263
|
+
true
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
244
268
|
end
|
245
269
|
end
|
246
270
|
|
data/lib/faye/connection.rb
CHANGED
@@ -2,9 +2,7 @@ module Faye
|
|
2
2
|
class Connection
|
3
3
|
include EventMachine::Deferrable
|
4
4
|
include Observable
|
5
|
-
|
6
|
-
extend Forwardable
|
7
|
-
def_delegators :EventMachine, :add_timer, :cancel_timer
|
5
|
+
include Timeouts
|
8
6
|
|
9
7
|
MAX_DELAY = 0.1
|
10
8
|
INTERVAL = 1.0
|
@@ -13,20 +11,18 @@ module Faye
|
|
13
11
|
attr_reader :id
|
14
12
|
|
15
13
|
def initialize(id, options = {})
|
16
|
-
@id
|
17
|
-
@options
|
18
|
-
@
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
def timeout
|
23
|
-
@options[:timeout] || TIMEOUT
|
14
|
+
@id = id
|
15
|
+
@options = options
|
16
|
+
@timeout = @options[:timeout] || TIMEOUT
|
17
|
+
@channels = Set.new
|
18
|
+
@inbox = Set.new
|
19
|
+
@connected = false
|
24
20
|
end
|
25
21
|
|
26
22
|
def update(message, event)
|
27
23
|
return unless message == :message
|
28
24
|
@inbox.add(event)
|
29
|
-
begin_delivery_timeout!
|
25
|
+
begin_delivery_timeout!
|
30
26
|
end
|
31
27
|
|
32
28
|
def subscribe(channel)
|
@@ -45,11 +41,7 @@ module Faye
|
|
45
41
|
return if @connected
|
46
42
|
|
47
43
|
@connected = true
|
48
|
-
|
49
|
-
if @deletion_timeout
|
50
|
-
cancel_timer(@deletion_timeout)
|
51
|
-
@deletion_timeout = nil
|
52
|
-
end
|
44
|
+
remove_timeout(:deletion)
|
53
45
|
|
54
46
|
begin_delivery_timeout!
|
55
47
|
begin_connection_timeout!
|
@@ -74,34 +66,21 @@ module Faye
|
|
74
66
|
private
|
75
67
|
|
76
68
|
def begin_delivery_timeout!
|
77
|
-
return unless @
|
78
|
-
|
69
|
+
return unless @connected and not @inbox.empty?
|
70
|
+
add_timeout(:delivery, MAX_DELAY) { flush! }
|
79
71
|
end
|
80
72
|
|
81
73
|
def begin_connection_timeout!
|
82
|
-
return unless @
|
83
|
-
@
|
74
|
+
return unless @connected
|
75
|
+
add_timeout(:connection, @timeout) { flush! }
|
84
76
|
end
|
85
77
|
|
86
78
|
def release_connection!
|
87
|
-
|
88
|
-
|
89
|
-
@connection_timeout = nil
|
90
|
-
end
|
91
|
-
|
92
|
-
if @delivery_timeout
|
93
|
-
cancel_timer(@delivery_timeout)
|
94
|
-
@delivery_timeout = nil
|
95
|
-
end
|
96
|
-
|
79
|
+
remove_timeout(:connection)
|
80
|
+
remove_timeout(:delivery)
|
97
81
|
@connected = false
|
98
|
-
schedule_for_deletion!
|
99
|
-
end
|
100
|
-
|
101
|
-
def schedule_for_deletion!
|
102
|
-
return if @deletion_timeout
|
103
82
|
|
104
|
-
|
83
|
+
add_timeout(:deletion, 10 * INTERVAL) do
|
105
84
|
changed(true)
|
106
85
|
notify_observers(:stale_client, self)
|
107
86
|
end
|
data/lib/faye/rack_adapter.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rack'
|
3
|
+
require 'thin'
|
3
4
|
require 'json'
|
4
5
|
|
5
6
|
module Faye
|
@@ -11,7 +12,7 @@ module Faye
|
|
11
12
|
DEFAULT_ENDPOINT = '/bayeux'
|
12
13
|
SCRIPT_PATH = File.join(ROOT, 'faye-client-min.js')
|
13
14
|
|
14
|
-
TYPE_JSON = {'Content-Type' => '
|
15
|
+
TYPE_JSON = {'Content-Type' => 'application/json'}
|
15
16
|
TYPE_SCRIPT = {'Content-Type' => 'text/javascript'}
|
16
17
|
TYPE_TEXT = {'Content-Type' => 'text/plain'}
|
17
18
|
|
@@ -19,9 +20,9 @@ module Faye
|
|
19
20
|
@app = app if app.respond_to?(:call)
|
20
21
|
@options = [app, options].grep(Hash).first || {}
|
21
22
|
|
22
|
-
@endpoint
|
23
|
-
@
|
24
|
-
@server
|
23
|
+
@endpoint = @options[:mount] || DEFAULT_ENDPOINT
|
24
|
+
@endpoint_re = Regexp.new('^' + @endpoint + '(/[^/]+)*(\\.js)?$')
|
25
|
+
@server = Server.new(@options)
|
25
26
|
end
|
26
27
|
|
27
28
|
def get_client
|
@@ -34,32 +35,33 @@ module Faye
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def call(env)
|
38
|
+
ensure_reactor_running!
|
37
39
|
request = Rack::Request.new(env)
|
38
|
-
case request.path_info
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@server.flush_connection(message) if request.get?
|
46
|
-
|
47
|
-
on_response(env, message) do |replies|
|
48
|
-
response = JSON.unparse(replies)
|
49
|
-
response = "#{ jsonp }(#{ response });" if request.get?
|
50
|
-
response
|
51
|
-
end
|
52
|
-
rescue
|
53
|
-
[400, TYPE_TEXT, 'Bad request']
|
54
|
-
end
|
41
|
+
unless request.path_info =~ @endpoint_re
|
42
|
+
env['faye.client'] = get_client
|
43
|
+
return @app ? @app.call(env) :
|
44
|
+
[404, TYPE_TEXT, ["Sure you're not looking for #{@endpoint} ?"]]
|
45
|
+
end
|
55
46
|
|
56
|
-
|
57
|
-
[200, TYPE_SCRIPT, File.new(SCRIPT_PATH)]
|
47
|
+
if request.path_info =~ /\.js$/
|
48
|
+
return [200, TYPE_SCRIPT, File.new(SCRIPT_PATH)]
|
49
|
+
end
|
58
50
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
51
|
+
begin
|
52
|
+
json_msg = request.post? ? request.body.read : request.params['message']
|
53
|
+
message = JSON.parse(json_msg)
|
54
|
+
jsonp = request.params['jsonp'] || JSONP_CALLBACK
|
55
|
+
|
56
|
+
@server.flush_connection(message) if request.get?
|
57
|
+
|
58
|
+
on_response(env, message) do |replies|
|
59
|
+
response = JSON.unparse(replies)
|
60
|
+
response = "#{ jsonp }(#{ response });" if request.get?
|
61
|
+
response
|
62
|
+
end
|
63
|
+
rescue
|
64
|
+
[400, TYPE_TEXT, 'Bad request']
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
@@ -70,8 +72,6 @@ module Faye
|
|
70
72
|
type = request.get? ? TYPE_SCRIPT : TYPE_JSON
|
71
73
|
callback = env['async.callback']
|
72
74
|
|
73
|
-
EM.run unless EM.reactor_running?
|
74
|
-
|
75
75
|
if callback
|
76
76
|
body = DeferredBody.new
|
77
77
|
callback.call [200, type, body]
|
@@ -85,6 +85,11 @@ module Faye
|
|
85
85
|
[200, type, [response]]
|
86
86
|
end
|
87
87
|
|
88
|
+
def ensure_reactor_running!
|
89
|
+
Thread.new { EM.run } unless EM.reactor_running?
|
90
|
+
while not EM.reactor_running?; end
|
91
|
+
end
|
92
|
+
|
88
93
|
class DeferredBody
|
89
94
|
include EventMachine::Deferrable
|
90
95
|
alias :each :callback
|
data/lib/faye/server.rb
CHANGED
@@ -54,20 +54,16 @@ module Faye
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def handle(message, local = false, &callback)
|
57
|
-
|
58
|
-
channel = message['channel']
|
59
|
-
|
57
|
+
channel = message['channel']
|
60
58
|
@channels.glob(channel).each { |c| c << message }
|
61
59
|
|
62
60
|
if Channel.meta?(channel)
|
63
61
|
response = __send__(Channel.parse(channel)[1], message, local)
|
64
62
|
|
65
|
-
client_id
|
63
|
+
client_id = response['clientId']
|
66
64
|
response['advice'] ||= {}
|
67
65
|
response['advice']['reconnect'] ||= @clients.has_key?(client_id) ? 'retry' : 'handshake'
|
68
|
-
response['advice']['interval'] ||= Connection::INTERVAL * 1000
|
69
|
-
|
70
|
-
response['id'] = message['id']
|
66
|
+
response['advice']['interval'] ||= (Connection::INTERVAL * 1000).floor
|
71
67
|
|
72
68
|
return callback[response] unless response['channel'] == Channel::CONNECT and
|
73
69
|
response['successful'] == true
|
@@ -79,9 +75,19 @@ module Faye
|
|
79
75
|
|
80
76
|
return callback[[]] if message['clientId'].nil? or Channel.service?(channel)
|
81
77
|
|
82
|
-
|
83
|
-
|
84
|
-
|
78
|
+
response = make_response(message)
|
79
|
+
response['successful'] = true
|
80
|
+
callback[response]
|
81
|
+
end
|
82
|
+
|
83
|
+
def make_response(message)
|
84
|
+
response = {}
|
85
|
+
%w[id clientId channel].each do |field|
|
86
|
+
if message[field]
|
87
|
+
response[field] = message[field]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
response
|
85
91
|
end
|
86
92
|
|
87
93
|
# MUST contain * version
|
@@ -90,9 +96,8 @@ module Faye
|
|
90
96
|
# * ext
|
91
97
|
# * id
|
92
98
|
def handshake(message, local = false)
|
93
|
-
response =
|
94
|
-
|
95
|
-
'id' => message['id'] }
|
99
|
+
response = make_response(message)
|
100
|
+
response['version'] = BAYEUX_VERSION
|
96
101
|
|
97
102
|
response['error'] = Error.parameter_missing('version') if message['version'].nil?
|
98
103
|
|
@@ -121,8 +126,7 @@ module Faye
|
|
121
126
|
# MAY contain * ext
|
122
127
|
# * id
|
123
128
|
def connect(message, local = false)
|
124
|
-
response =
|
125
|
-
'id' => message['id'] }
|
129
|
+
response = make_response(message)
|
126
130
|
|
127
131
|
client_id = message['clientId']
|
128
132
|
client = client_id ? @clients[client_id] : nil
|
@@ -132,6 +136,7 @@ module Faye
|
|
132
136
|
response['error'] = Error.parameter_missing('connectionType') if message['connectionType'].nil?
|
133
137
|
|
134
138
|
response['successful'] = response['error'].nil?
|
139
|
+
response.delete('clientId') unless response['successful']
|
135
140
|
return response unless response['successful']
|
136
141
|
|
137
142
|
response['clientId'] = client.id
|
@@ -142,8 +147,7 @@ module Faye
|
|
142
147
|
# MAY contain * ext
|
143
148
|
# * id
|
144
149
|
def disconnect(message, local = false)
|
145
|
-
response =
|
146
|
-
'id' => message['id'] }
|
150
|
+
response = make_response(message)
|
147
151
|
|
148
152
|
client_id = message['clientId']
|
149
153
|
client = client_id ? @clients[client_id] : nil
|
@@ -152,6 +156,7 @@ module Faye
|
|
152
156
|
response['error'] = Error.parameter_missing('clientId') if client_id.nil?
|
153
157
|
|
154
158
|
response['successful'] = response['error'].nil?
|
159
|
+
response.delete('clientId') unless response['successful']
|
155
160
|
return response unless response['successful']
|
156
161
|
|
157
162
|
destroy_client(client)
|
@@ -165,9 +170,7 @@ module Faye
|
|
165
170
|
# MAY contain * ext
|
166
171
|
# * id
|
167
172
|
def subscribe(message, local = false)
|
168
|
-
response =
|
169
|
-
'clientId' => message['clientId'],
|
170
|
-
'id' => message['id'] }
|
173
|
+
response = make_response(message)
|
171
174
|
|
172
175
|
client_id = message['clientId']
|
173
176
|
client = client_id ? @clients[client_id] : nil
|
@@ -200,9 +203,7 @@ module Faye
|
|
200
203
|
# MAY contain * ext
|
201
204
|
# * id
|
202
205
|
def unsubscribe(message, local = false)
|
203
|
-
response =
|
204
|
-
'clientId' => message['clientId'],
|
205
|
-
'id' => message['id'] }
|
206
|
+
response = make_response(message)
|
206
207
|
|
207
208
|
client_id = message['clientId']
|
208
209
|
client = client_id ? @clients[client_id] : nil
|