faye 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
         |