faye 0.6.8 → 0.7.0
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 +10 -3
- data/README.rdoc +1 -2
- data/lib/faye-browser-min.js +1 -1
- data/lib/faye.rb +89 -32
- data/lib/faye/adapters/rack_adapter.rb +20 -26
- data/lib/faye/engines/base.rb +5 -0
- data/lib/faye/engines/memory.rb +9 -3
- data/lib/faye/engines/redis.rb +26 -11
- data/lib/faye/mixins/publisher.rb +4 -8
- data/lib/faye/protocol/channel.rb +8 -8
- data/lib/faye/protocol/client.rb +45 -4
- data/lib/faye/protocol/publication.rb +5 -0
- data/lib/faye/protocol/server.rb +10 -19
- data/lib/faye/thin_extensions.rb +1 -1
- data/lib/faye/transport/http.rb +17 -8
- data/lib/faye/transport/local.rb +6 -3
- data/lib/faye/transport/transport.rb +23 -9
- data/lib/faye/transport/web_socket.rb +102 -0
- data/lib/faye/util/web_socket.rb +34 -80
- data/lib/faye/util/web_socket/api.rb +103 -0
- data/lib/faye/util/web_socket/client.rb +82 -0
- data/lib/faye/util/web_socket/draft75_parser.rb +3 -5
- data/lib/faye/util/web_socket/draft76_parser.rb +5 -7
- data/lib/faye/util/web_socket/protocol8_parser.rb +111 -46
- data/spec/javascript/client_spec.js +99 -7
- data/spec/javascript/engine_spec.js +116 -3
- data/spec/javascript/node_adapter_spec.js +2 -4
- data/spec/javascript/server/handshake_spec.js +0 -12
- data/spec/javascript/server/integration_spec.js +74 -29
- data/spec/javascript/server_spec.js +0 -11
- data/spec/javascript/web_socket/client_spec.js +121 -0
- data/spec/javascript/web_socket/protocol8parser_spec.js +26 -3
- data/spec/node.js +2 -0
- data/spec/redis.conf +10 -280
- data/spec/ruby/client_spec.rb +101 -8
- data/spec/ruby/engine_spec.rb +106 -0
- data/spec/ruby/server/handshake_spec.rb +0 -12
- data/spec/ruby/server/integration_spec.rb +56 -18
- data/spec/ruby/server_spec.rb +1 -12
- data/spec/ruby/transport_spec.rb +14 -8
- data/spec/ruby/web_socket/client_spec.rb +126 -0
- data/spec/ruby/web_socket/protocol8_parser_spec.rb +28 -3
- metadata +96 -150
data/History.txt
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
-
=== 0.
|
2
|
-
|
3
|
-
|
1
|
+
=== 0.7.0 / 2011-11-22
|
2
|
+
TestSwarm build: http://swarm.jcoglan.com/job/107/
|
3
|
+
|
4
|
+
* Provide an event API for monitoring engine events on the server side
|
5
|
+
* Implement server-side WebSocket connections for improved latency
|
6
|
+
* Fix WebSocket protocol bugs and expose APIs for developers to use
|
7
|
+
* Make server-side HTTP transports support SSL and cookies
|
8
|
+
* Allow clients to disable selected transports and autodisconnection
|
9
|
+
* Add callback/errback API to Client#publish() interface
|
10
|
+
* Add 'socket' setting for the Redis engine for connecting through a Unix socket
|
4
11
|
|
5
12
|
|
6
13
|
=== 0.6.7 / 2011-10-20
|
data/README.rdoc
CHANGED
data/lib/faye-browser-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.6.8',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:['long-polling','cross-origin-long-polling','callback-polling','websocket','in-process'],MANDATORY_CONNECTION_TYPES:['long-polling','callback-polling','in-process'],ENV:(function(){return 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)-1,f=d.toString(36).length,c=Math.floor(Math.random()*d).toString(36);while(c.length<f)c='0'+c;return c},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])}}},map:function(a,b,c){if(a.map)return a.map(b,c);var d=[];this.each(a,function(){d.push(b.apply(c||null,arguments))});return d},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}},asyncEach:function(a,b,c,d){var f=a.length,g=-1,h=0,i=false;var j=function(){h-=1;g+=1;if(g===f)return c&&c.call(d);b(a[g],m)};var l=function(){if(i)return;i=true;while(h>0)j();i=false};var m=function(){h+=1;l()};m()},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(),h=b.getMinutes(),i=b.getSeconds();var j=function(a){return a<10?'0'+a:String(a)};return j(c)+'-'+j(d)+'-'+j(f)+' '+j(g)+':'+j(h)+':'+j(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.Namespace=Faye.Class({initialize:function(){this._c={}},exists:function(a){return this._c.hasOwnProperty(a)},generate:function(){var a=Faye.random();while(this._c.hasOwnProperty(a))a=Faye.random();return this._c[a]=a},release:function(a){delete this._c[a]}});Faye.Error=Faye.Class({initialize:function(a,b,c){this.code=a;this.params=Array.prototype.slice.call(b);this.message=c},toString:function(){return this.code+':'+this.params.join(',')+':'+this.message}});Faye.Error.parse=function(a){a=a||'';if(!Faye.Grammar.ERROR.test(a))return new this(null,[],a);var b=a.split(':'),c=parseInt(b[0]),d=b[1].split(','),a=b[2];return new this(c,d,a)};Faye.Error.versionMismatch=function(){return new this(300,arguments,"Version mismatch").toString()};Faye.Error.conntypeMismatch=function(){return new this(301,arguments,"Connection types not supported").toString()};Faye.Error.extMismatch=function(){return new this(302,arguments,"Extension mismatch").toString()};Faye.Error.badRequest=function(){return new this(400,arguments,"Bad request").toString()};Faye.Error.clientUnknown=function(){return new this(401,arguments,"Unknown client").toString()};Faye.Error.parameterMissing=function(){return new this(402,arguments,"Missing required parameter").toString()};Faye.Error.channelForbidden=function(){return new this(403,arguments,"Forbidden channel").toString()};Faye.Error.channelUnknown=function(){return new this(404,arguments,"Unknown channel").toString()};Faye.Error.channelInvalid=function(){return new this(405,arguments,"Invalid channel").toString()};Faye.Error.extUnknown=function(){return new this(406,arguments,"Unknown extension").toString()};Faye.Error.publishFailed=function(){return new this(407,arguments,"Failed to publish").toString()};Faye.Error.serverError=function(){return new this(500,arguments,"Internal server error").toString()};Faye.Deferrable={callback:function(a,b){if(!a)return;if(this._t==='succeeded')return a.apply(b,this._j);this._k=this._k||[];this._k.push([a,b])},errback:function(a,b){if(!a)return;if(this._t==='failed')return a.apply(b,this._j);this._l=this._l||[];this._l.push([a,b])},setDeferredStatus:function(){var a=Array.prototype.slice.call(arguments),b=a.shift(),c;this._t=b;this._j=a;if(b==='succeeded')c=this._k;else if(b==='failed')c=this._l;if(!c)return;var d;while(d=c.shift())d[0].apply(d[1],this._j)}};Faye.Publisher={countSubscribers:function(a){if(!this._3||!this._3[a])return 0;return this._3[a].length},addSubscriber:function(a,b,c){this._3=this._3||{};var d=this._3[a]=this._3[a]||[];d.push([b,c])},removeSubscriber:function(a,b,c){if(!this._3||!this._3[a])return;if(!b){delete this._3[a];return}var d=this._3[a],f=d.length;while(f--){if(b!==d[f][0])continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},removeSubscribers:function(){this._3={}},publishEvent:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._3||!this._3[c])return;Faye.each(this._3[c],function(a){a[0].apply(a[1],b)})}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._4=this._4||{};if(this._4.hasOwnProperty(a))return;var f=this;this._4[a]=Faye.ENV.setTimeout(function(){delete f._4[a];c.call(d)},1000*b)},removeTimeout:function(a){this._4=this._4||{};var b=this._4[a];if(!b)return;clearTimeout(b);delete this._4[a]}};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 a=Array.prototype.slice.apply(a),d=' ['+b.toUpperCase()+'] [Faye',f=this.className,g=a.shift().replace(/\?/g,function(){try{return Faye.toJSON(a.shift())}catch(e){return'[Object]'}});for(var h in Faye){if(f)continue;if(typeof Faye[h]!=='function')continue;if(this instanceof Faye[h])f=h}if(f)d+='.'+f;d+='] ';Faye.logger(Faye.timestamp()+d+g)}};Faye.each(Faye.Logging.LOG_LEVELS,function(a,b){Faye.Logging[a]=function(){this.log(arguments,a)}});Faye.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])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/};Faye.Extensible={addExtension:function(a){this._5=this._5||[];this._5.push(a);if(a.added)a.added()},removeExtension:function(a){if(!this._5)return;var b=this._5.length;while(b--){if(this._5[b]!==a)continue;this._5.splice(b,1);if(a.removed)a.removed()}},pipeThroughExtensions:function(c,d,f,g){this.debug('Passing through ? extensions: ?',c,d);if(!this._5)return f.call(g,d);var h=this._5.slice();var i=function(a){if(!a)return f.call(g,a);var b=h.shift();if(!b)return f.call(g,a);if(b[c])b[c](a,i);else i(a)};i(d)}};Faye.extend(Faye.Extensible,Faye.Logging);Faye.Channel=Faye.Class({initialize:function(a){this.id=this.name=a},push:function(a){this.publishEvent('message',a)},isUnused:function(){return this.countSubscribers('message')===0}});Faye.extend(Faye.Channel.prototype,Faye.Publisher);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',expand:function(a){var b=this.parse(a),c=['/**',a];var d=b.slice();d[d.length-1]='*';c.push(this.unparse(d));for(var f=1,g=b.length;f<g;f++){d=b.slice(0,f);d.push('**');c.push(this.unparse(d))}return c},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)},unparse:function(a){return'/'+a.join('/')},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)},Set:Faye.Class({initialize:function(){this._2={}},getKeys:function(){var c=[];Faye.each(this._2,function(a,b){c.push(a)});return c},remove:function(a){delete this._2[a]},hasSubscription:function(a){return this._2.hasOwnProperty(a)},subscribe:function(c,d,f){if(!d)return;Faye.each(c,function(a){var b=this._2[a]=this._2[a]||new Faye.Channel(a);b.addSubscriber('message',d,f)},this)},unsubscribe:function(a,b,c){var d=this._2[a];if(!d)return false;d.removeSubscriber('message',b,c);if(d.isUnused()){this.remove(a);return true}else{return false}},distributeMessage:function(c){var d=Faye.Channel.expand(c.channel);Faye.each(d,function(a){var b=this._2[a];if(b)b.publishEvent('message',c.data)},this)}})});Faye.Subscription=Faye.Class({initialize:function(a,b,c,d){this._8=a;this._2=b;this._m=c;this._n=d;this._u=false},cancel:function(){if(this._u)return;this._8.unsubscribe(this._2,this._m,this._n);this._u=true},unsubscribe:function(){this.cancel()}});Faye.extend(Faye.Subscription.prototype,Faye.Deferrable);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',INTERVAL:0.0,initialize:function(b,c){this.info('New client created for ?',b);this.endpoint=b||this.DEFAULT_ENDPOINT;this._v=c||{};Faye.Transport.get(this,Faye.MANDATORY_CONNECTION_TYPES,function(a){this._d=a},this);this._1=this.UNCONNECTED;this._2=new Faye.Channel.Set();this._e=0;this._o={};this._6={reconnect:this.RETRY,interval:1000*(this._v.interval||this.INTERVAL),timeout:1000*(this._v.timeout||this.CONNECTION_TIMEOUT)};if(Faye.Event)Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},getClientId:function(){return this._0},getState:function(){switch(this._1){case this.UNCONNECTED:return'UNCONNECTED';case this.CONNECTING:return'CONNECTING';case this.CONNECTED:return'CONNECTED';case this.DISCONNECTED:return'DISCONNECTED'}},handshake:function(c,d){if(this._6.reconnect===this.NONE)return;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var f=this;this.info('Initiating handshake with ?',this.endpoint);this._9({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:[this._d.connectionType]},function(b){if(b.successful){this._1=this.CONNECTED;this._0=b.clientId;Faye.Transport.get(this,b.supportedConnectionTypes,function(a){this._d=a},this);this.info('Handshake successful: ?',this._0);this.subscribe(this._2.getKeys(),true);if(c)c.call(d)}else{this.info('Handshake unsuccessful');Faye.ENV.setTimeout(function(){f.handshake(c,d)},this._6.interval);this._1=this.UNCONNECTED}},this)},connect:function(a,b){if(this._6.reconnect===this.NONE)return;if(this._1===this.DISCONNECTED)return;if(this._1===this.UNCONNECTED)return this.handshake(function(){this.connect(a,b)},this);this.callback(a,b);if(this._1!==this.CONNECTED)return;this.info('Calling deferred actions for ?',this._0);this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(this._p)return;this._p=true;this.info('Initiating connection for ?',this._0);this._9({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._d.connectionType},this._w,this)},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting ?',this._0);this._9({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for ?',this._0);this._2=new Faye.Channel.Set()},subscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.subscribe(channel,d,f)},this);var g=new Faye.Subscription(this,c,d,f);var h=(d===true);if(!h&&this._2.hasSubscription(c)){this._2.subscribe([c],d,f);g.setDeferredStatus('succeeded');return g}this.connect(function(){this.info('Client ? attempting to subscribe to ?',this._0,c);this._9({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return g.setDeferredStatus('failed',Faye.Error.parse(a.error));var b=[].concat(a.subscription);this.info('Subscription acknowledged for ? to ?',this._0,b);if(!h)this._2.subscribe(b,d,f);g.setDeferredStatus('succeeded')},this)},this);return g},unsubscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.unsubscribe(channel,d,f)},this);var g=this._2.unsubscribe(c,d,f);if(!g)return;this.connect(function(){this.info('Client ? attempting to unsubscribe from ?',this._0,c);this._9({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return;var b=[].concat(a.subscription);this.info('Unsubscription acknowledged for ? from ?',this._0,b)},this)},this)},publish:function(a,b){if(!Faye.Grammar.CHANNEL_NAME.test(a))throw new Error("Cannot publish: '"+a+"' is not a valid channel name");this.connect(function(){this.info('Client ? queueing published message to ?: ?',this._0,a,b);this._9({channel:a,data:b,clientId:this._0})},this)},receiveMessage:function(c){this.pipeThroughExtensions('incoming',c,function(a){if(!a)return;if(a.advice)this._z(a.advice);var b=this._o[a.id];if(b){delete this._o[a.id];b[0].call(b[1],a)}this._A(a)},this)},_9:function(b,c,d){b.id=this._B();if(c)this._o[b.id]=[c,d];this.pipeThroughExtensions('outgoing',b,function(a){if(!a)return;this._d.send(a,this._6.timeout/1000)},this)},_B:function(){this._e+=1;if(this._e>=Math.pow(2,32))this._e=0;return this._e.toString(36)},_z:function(a){Faye.extend(this._6,a);if(this._6.reconnect===this.HANDSHAKE&&this._1!==this.DISCONNECTED){this._1=this.UNCONNECTED;this._0=null;this._w()}},_A:function(a){if(!a.channel||!a.data)return;this.info('Client ? calling listeners for ? with ?',this._0,a.channel,a.data);this._2.distributeMessage(a)},_C:function(){if(!this._p)return;this._p=null;this.info('Closed connection for ?',this._0)},_w:function(){this._C();var a=this;Faye.ENV.setTimeout(function(){a.connect()},this._6.interval)}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.extend(Faye.Client.prototype,Faye.Extensible);Faye.Transport=Faye.extend(Faye.Class({MAX_DELAY:0.0,batching:true,initialize:function(a,b){this.debug('Created new ? transport for ?',this.connectionType,b);this._8=a;this._a=b;this._f=[]},send:function(a,b){this.debug('Client ? sending message to ?: ?',this._8._0,this._a,a);if(!this.batching)return this.request([a],b);this._f.push(a);this._7=b;if(a.channel===Faye.Channel.HANDSHAKE)return this.flush();if(a.channel===Faye.Channel.CONNECT)this._q=a;this.addTimeout('publish',this.MAX_DELAY,this.flush,this)},flush:function(){this.removeTimeout('publish');if(this._f.length>1&&this._q)this._q.advice={timeout:0};this.request(this._f,this._7);this._q=null;this._f=[]},receive:function(a){this.debug('Client ? received from ?: ?',this._8._0,this._a,a);Faye.each(a,this._8.receiveMessage,this._8)},retry:function(a,b){var c=this,d=false;return function(){if(d)return;d=true;Faye.ENV.setTimeout(function(){c.request(a,2*b)},1000*b)}}}),{get:function(g,h,i,j){var l=g.endpoint;if(h===undefined)h=this.supportedConnectionTypes();Faye.asyncEach(this._r,function(b,c){var d=b[0],f=b[1];if(Faye.indexOf(h,d)<0)return c();f.isUsable(l,function(a){if(a)i.call(j,new f(g,l));else c()})},function(){throw new Error('Could not find a usable connection type for '+l);})},register:function(a,b){this._r.push([a,b]);b.prototype.connectionType=a},_r:[],supportedConnectionTypes:function(){return Faye.map(this._r,function(a){return a[0]})}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.extend(Faye.Transport.prototype,Faye.Timeouts);Faye.Event={_g:[],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._g.push({_h:a,_s:b,_m:c,_n:d,_x:f})},detach:function(a,b,c,d){var f=this._g.length,g;while(f--){g=this._g[f];if((a&&a!==g._h)||(b&&b!==g._s)||(c&&c!==g._m)||(d&&d!==g._n))continue;if(g._h.removeEventListener)g._h.removeEventListener(g._s,g._x,false);else g._h.detachEvent('on'+g._s,g._x);this._g.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(){var a=this.queryString();return this.protocol+this.hostname+':'+this.port+this.pathname+(a?'?'+a:'')}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var h=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};h('protocol',/^https?\:\/+/);h('hostname',/^[^\/\:]+/);h('port',/^:[0-9]+/);Faye.extend(g,{protocol:Faye.ENV.location.protocol+'//',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('?'),j=i.shift(),l=i.join('?'),m=l?l.split('&'):[],n=m.length,k={};while(n--){i=m[n].split('=');k[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}if(typeof f==='object')Faye.extend(k,f);g.pathname=j;g.params=k;return g}});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 m=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,n=/[\\\"\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','"':'\\"','\\':'\\\\'},o;function r(c){n.lastIndex=0;return n.test(c)?'"'+c.replace(n,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,h=k,i,j=b[a];if(j&&typeof j==='object'&&typeof j.toJSON==='function'){j=j.toJSON(a)}if(typeof o==='function'){j=o.call(b,a,j)}switch(typeof j){case'string':return r(j);case'number':return isFinite(j)?String(j):'null';case'boolean':case'null':return String(j);case'object':if(!j){return'null'}k+=p;i=[];if(Object.prototype.toString.apply(j)==='[object Array]'){g=j.length;for(c=0;c<g;c+=1){i[c]=q(c,j)||'null'}f=i.length===0?'[]':k?'[\n'+k+i.join(',\n'+k)+'\n'+h+']':'['+i.join(',')+']';k=h;return f}if(o&&typeof o==='object'){g=o.length;for(c=0;c<g;c+=1){d=o[c];if(typeof d==='string'){f=q(d,j);if(f){i.push(r(d)+(k?': ':':')+f)}}}}else{for(d in j){if(Object.hasOwnProperty.call(j,d)){f=q(d,j);if(f){i.push(r(d)+(k?': ':':')+f)}}}}f=i.length===0?'{}':k?'{\n'+k+i.join(',\n'+k)+'\n'+h+'}':'{'+i.join(',')+'}';k=h;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}o=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,h){var i;function j(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=j(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return h.call(a,b,f)}m.lastIndex=0;if(m.test(g)){g=g.replace(m,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 h==='function'?j({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.Transport.WebSocket=Faye.extend(Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,batching:false,request:function(b,c){this._7=this._7||c;this._i=this._i||{};Faye.each(b,function(a){this._i[a.id]=a},this);this.withSocket(function(a){a.send(Faye.toJSON(b))})},withSocket:function(a,b){this.callback(a,b);this.connect()},connect:function(){this._1=this._1||this.UNCONNECTED;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var d=Faye.ENV.WebSocket||Faye.ENV.MozWebSocket;this._b=new d(Faye.Transport.WebSocket.getSocketUrl(this._a));var f=this;this._b.onopen=function(){delete f._7;f._1=f.CONNECTED;f.setDeferredStatus('succeeded',f._b)};this._b.onmessage=function(b){var c=[].concat(JSON.parse(b.data));Faye.each(c,function(a){delete f._i[a.id]});f.receive(c)};this._b.onclose=function(){var a=(f._1===f.CONNECTED);f.setDeferredStatus('deferred');f._1=f.UNCONNECTED;delete f._b;if(a)return f.resend();Faye.ENV.setTimeout(function(){f.connect()},1000*f._7);f._7=f._7*2}},resend:function(){var c=Faye.map(this._i,function(a,b){return b});this.request(c)}}),{WEBSOCKET_TIMEOUT:1000,getSocketUrl:function(a){return Faye.URI.parse(a).toURL().replace(/^http(s?):/ig,'ws$1:')},isUsable:function(a,b,c){var d=Faye.ENV.WebSocket||Faye.ENV.MozWebSocket;if(!d)return b.call(c,false);var f=false,g=false,h=this.getSocketUrl(a),i=new d(h);i.onopen=function(){f=true;i.close();b.call(c,true);g=true;i=null};var j=function(){if(!g&&!f)b.call(c,false);g=true};i.onclose=i.onerror=j;Faye.ENV.setTimeout(j,this.WEBSOCKET_TIMEOUT)}});Faye.extend(Faye.Transport.WebSocket.prototype,Faye.Deferrable);Faye.Transport.register('websocket',Faye.Transport.WebSocket);Faye.Transport.XHR=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c){var d=this.retry(b,c),f=Faye.URI.parse(this._a).pathname,g=this,h=Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();h.open('POST',f,true);h.setRequestHeader('Content-Type','application/json');h.setRequestHeader('X-Requested-With','XMLHttpRequest');h.onreadystatechange=function(){if(h.readyState!==4)return;var a=h.status;try{if((a>=200&&a<300)||a===304||a===1223)g.receive(JSON.parse(h.responseText));else d()}catch(e){d()}finally{Faye.Event.detach(Faye.ENV,'beforeunload',i);h.onreadystatechange=function(){};h=null}};var i=function(){h.abort()};Faye.Event.on(Faye.ENV,'beforeunload',i);h.send(Faye.toJSON(b))}}),{isUsable:function(a,b,c){b.call(c,Faye.URI.parse(a).isLocal())}});Faye.Transport.register('long-polling',Faye.Transport.XHR);Faye.Transport.CORS=Faye.extend(Faye.Class(Faye.Transport,{request:function(a,b){var c=Faye.ENV.XDomainRequest?XDomainRequest:XMLHttpRequest,d=new c(),f=this.retry(a,b),g=this;d.open('POST',this._a,true);var h=function(){if(!d)return false;d.onload=d.onerror=d.ontimeout=d.onprogress=null;d=null;Faye.ENV.clearTimeout(j);return true};d.onload=function(){try{g.receive(JSON.parse(d.responseText))}catch(e){f()}finally{h()}};var i=function(){h();f()};var j=Faye.ENV.setTimeout(i,1.5*1000*b);d.onerror=i;d.ontimeout=i;d.onprogress=function(){};d.send('message='+encodeURIComponent(Faye.toJSON(a)))}}),{isUsable:function(a,b,c){if(Faye.URI.parse(a).isLocal())return b.call(c,false);if(Faye.ENV.XDomainRequest)return b.call(c,true);if(Faye.ENV.XMLHttpRequest){var d=new Faye.ENV.XMLHttpRequest();return b.call(c,d.withCredentials!==undefined)}return b.call(c,false)}});Faye.Transport.register('cross-origin-long-polling',Faye.Transport.CORS);Faye.Transport.JSONP=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c){var d={message:Faye.toJSON(b)},f=document.getElementsByTagName('head')[0],g=document.createElement('script'),h=Faye.Transport.JSONP.getCallbackName(),i=Faye.URI.parse(this._a,d),j=this.retry(b,c),l=this;Faye.ENV[h]=function(a){n();l.receive(a)};var m=Faye.ENV.setTimeout(function(){n();j()},1.5*1000*c);var n=function(){if(!Faye.ENV[h])return false;Faye.ENV[h]=undefined;try{delete Faye.ENV[h]}catch(e){}Faye.ENV.clearTimeout(m);g.parentNode.removeChild(g);return true};i.params.jsonp=h;g.type='text/javascript';g.src=i.toURL();f.appendChild(g)}}),{_y:0,getCallbackName:function(){this._y+=1;return'__jsonp'+this._y+'__'},isUsable:function(a,b,c){b.call(c,true)}});Faye.Transport.register('callback-polling',Faye.Transport.JSONP);
|
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.7.0',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:['long-polling','cross-origin-long-polling','callback-polling','websocket','in-process'],MANDATORY_CONNECTION_TYPES:['long-polling','callback-polling','in-process'],ENV:(function(){return 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)-1,f=d.toString(36).length,c=Math.floor(Math.random()*d).toString(36);while(c.length<f)c='0'+c;return c},copyObject:function(a){return JSON.parse(Faye.toJSON(a))},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])}}},map:function(a,b,c){if(a.map)return a.map(b,c);var d=[];this.each(a,function(){d.push(b.apply(c||null,arguments))});return d},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}},asyncEach:function(a,b,c,d){var f=a.length,g=-1,h=0,i=false;var j=function(){h-=1;g+=1;if(g===f)return c&&c.call(d);b(a[g],m)};var k=function(){if(i)return;i=true;while(h>0)j();i=false};var m=function(){h+=1;k()};m()},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(),h=b.getMinutes(),i=b.getSeconds();var j=function(a){return a<10?'0'+a:String(a)};return j(c)+'-'+j(d)+'-'+j(f)+' '+j(g)+':'+j(h)+':'+j(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.Namespace=Faye.Class({initialize:function(){this._d={}},exists:function(a){return this._d.hasOwnProperty(a)},generate:function(){var a=Faye.random();while(this._d.hasOwnProperty(a))a=Faye.random();return this._d[a]=a},release:function(a){delete this._d[a]}});Faye.Error=Faye.Class({initialize:function(a,b,c){this.code=a;this.params=Array.prototype.slice.call(b);this.message=c},toString:function(){return this.code+':'+this.params.join(',')+':'+this.message}});Faye.Error.parse=function(a){a=a||'';if(!Faye.Grammar.ERROR.test(a))return new this(null,[],a);var b=a.split(':'),c=parseInt(b[0]),d=b[1].split(','),a=b[2];return new this(c,d,a)};Faye.Error.versionMismatch=function(){return new this(300,arguments,"Version mismatch").toString()};Faye.Error.conntypeMismatch=function(){return new this(301,arguments,"Connection types not supported").toString()};Faye.Error.extMismatch=function(){return new this(302,arguments,"Extension mismatch").toString()};Faye.Error.badRequest=function(){return new this(400,arguments,"Bad request").toString()};Faye.Error.clientUnknown=function(){return new this(401,arguments,"Unknown client").toString()};Faye.Error.parameterMissing=function(){return new this(402,arguments,"Missing required parameter").toString()};Faye.Error.channelForbidden=function(){return new this(403,arguments,"Forbidden channel").toString()};Faye.Error.channelUnknown=function(){return new this(404,arguments,"Unknown channel").toString()};Faye.Error.channelInvalid=function(){return new this(405,arguments,"Invalid channel").toString()};Faye.Error.extUnknown=function(){return new this(406,arguments,"Unknown extension").toString()};Faye.Error.publishFailed=function(){return new this(407,arguments,"Failed to publish").toString()};Faye.Error.serverError=function(){return new this(500,arguments,"Internal server error").toString()};Faye.Deferrable={callback:function(a,b){if(!a)return;if(this._v==='succeeded')return a.apply(b,this._k);this._l=this._l||[];this._l.push([a,b])},errback:function(a,b){if(!a)return;if(this._v==='failed')return a.apply(b,this._k);this._m=this._m||[];this._m.push([a,b])},setDeferredStatus:function(){var a=Array.prototype.slice.call(arguments),b=a.shift(),c;this._v=b;this._k=a;if(b==='succeeded')c=this._l;else if(b==='failed')c=this._m;if(!c)return;var d;while(d=c.shift())d[0].apply(d[1],this._k)}};Faye.Publisher={countListeners:function(a){if(!this._3||!this._3[a])return 0;return this._3[a].length},bind:function(a,b,c){this._3=this._3||{};var d=this._3[a]=this._3[a]||[];d.push([b,c])},unbind:function(a,b,c){if(!this._3||!this._3[a])return;if(!b){delete this._3[a];return}var d=this._3[a],f=d.length;while(f--){if(b!==d[f][0])continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},trigger:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._3||!this._3[c])return;Faye.each(this._3[c],function(a){a[0].apply(a[1],b)})}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._4=this._4||{};if(this._4.hasOwnProperty(a))return;var f=this;this._4[a]=Faye.ENV.setTimeout(function(){delete f._4[a];c.call(d)},1000*b)},removeTimeout:function(a){this._4=this._4||{};var b=this._4[a];if(!b)return;clearTimeout(b);delete this._4[a]}};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 a=Array.prototype.slice.apply(a),d=' ['+b.toUpperCase()+'] [Faye',f=this.className,g=a.shift().replace(/\?/g,function(){try{return Faye.toJSON(a.shift())}catch(e){return'[Object]'}});for(var h in Faye){if(f)continue;if(typeof Faye[h]!=='function')continue;if(this instanceof Faye[h])f=h}if(f)d+='.'+f;d+='] ';Faye.logger(Faye.timestamp()+d+g)}};Faye.each(Faye.Logging.LOG_LEVELS,function(a,b){Faye.Logging[a]=function(){this.log(arguments,a)}});Faye.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])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/};Faye.Extensible={addExtension:function(a){this._5=this._5||[];this._5.push(a);if(a.added)a.added()},removeExtension:function(a){if(!this._5)return;var b=this._5.length;while(b--){if(this._5[b]!==a)continue;this._5.splice(b,1);if(a.removed)a.removed()}},pipeThroughExtensions:function(c,d,f,g){this.debug('Passing through ? extensions: ?',c,d);if(!this._5)return f.call(g,d);var h=this._5.slice();var i=function(a){if(!a)return f.call(g,a);var b=h.shift();if(!b)return f.call(g,a);if(b[c])b[c](a,i);else i(a)};i(d)}};Faye.extend(Faye.Extensible,Faye.Logging);Faye.Channel=Faye.Class({initialize:function(a){this.id=this.name=a},push:function(a){this.trigger('message',a)},isUnused:function(){return this.countListeners('message')===0}});Faye.extend(Faye.Channel.prototype,Faye.Publisher);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',expand:function(a){var b=this.parse(a),c=['/**',a];var d=b.slice();d[d.length-1]='*';c.push(this.unparse(d));for(var f=1,g=b.length;f<g;f++){d=b.slice(0,f);d.push('**');c.push(this.unparse(d))}return c},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)},unparse:function(a){return'/'+a.join('/')},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)},Set:Faye.Class({initialize:function(){this._2={}},getKeys:function(){var c=[];Faye.each(this._2,function(a,b){c.push(a)});return c},remove:function(a){delete this._2[a]},hasSubscription:function(a){return this._2.hasOwnProperty(a)},subscribe:function(c,d,f){if(!d)return;Faye.each(c,function(a){var b=this._2[a]=this._2[a]||new Faye.Channel(a);b.bind('message',d,f)},this)},unsubscribe:function(a,b,c){var d=this._2[a];if(!d)return false;d.unbind('message',b,c);if(d.isUnused()){this.remove(a);return true}else{return false}},distributeMessage:function(c){var d=Faye.Channel.expand(c.channel);Faye.each(d,function(a){var b=this._2[a];if(b)b.trigger('message',c.data)},this)}})});Faye.Publication=Faye.Class(Faye.Deferrable);Faye.Subscription=Faye.Class({initialize:function(a,b,c,d){this._8=a;this._2=b;this._n=c;this._o=d;this._w=false},cancel:function(){if(this._w)return;this._8.unsubscribe(this._2,this._n,this._o);this._w=true},unsubscribe:function(){this.cancel()}});Faye.extend(Faye.Subscription.prototype,Faye.Deferrable);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',INTERVAL:0.0,initialize:function(a,b){this.info('New client created for ?',a);this.endpoint=a||this.DEFAULT_ENDPOINT;this._x=b||{};this._p=[];this._y(Faye.MANDATORY_CONNECTION_TYPES);this._1=this.UNCONNECTED;this._2=new Faye.Channel.Set();this._e=0;this._q={};this._6={reconnect:this.RETRY,interval:1000*(this._x.interval||this.INTERVAL),timeout:1000*(this._x.timeout||this.CONNECTION_TIMEOUT)};if(Faye.Event)Faye.Event.on(Faye.ENV,'beforeunload',function(){if(Faye.indexOf(this._p,'autodisconnect')<0)this.disconnect()},this)},disable:function(a){this._p.push(a)},getClientId:function(){return this._0},getState:function(){switch(this._1){case this.UNCONNECTED:return'UNCONNECTED';case this.CONNECTING:return'CONNECTING';case this.CONNECTED:return'CONNECTED';case this.DISCONNECTED:return'DISCONNECTED'}},handshake:function(f,g){if(this._6.reconnect===this.NONE)return;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var h=this;this.info('Initiating handshake with ?',this.endpoint);this._9({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:[this._f.connectionType]},function(c){if(c.successful){this._1=this.CONNECTED;this._0=c.clientId;var d=c.supportedConnectionTypes;Faye.each(this._p,function(a){var b=Faye.indexOf(d,a);if(b>=0)d.splice(b,1)},this);this._y(d);this.info('Handshake successful: ?',this._0);this.subscribe(this._2.getKeys(),true);if(f)f.call(g)}else{this.info('Handshake unsuccessful');Faye.ENV.setTimeout(function(){h.handshake(f,g)},this._6.interval);this._1=this.UNCONNECTED}},this)},connect:function(a,b){if(this._6.reconnect===this.NONE)return;if(this._1===this.DISCONNECTED)return;if(this._1===this.UNCONNECTED)return this.handshake(function(){this.connect(a,b)},this);this.callback(a,b);if(this._1!==this.CONNECTED)return;this.info('Calling deferred actions for ?',this._0);this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(this._r)return;this._r=true;this.info('Initiating connection for ?',this._0);this._9({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._f.connectionType},this._z,this)},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting ?',this._0);this._9({channel:Faye.Channel.DISCONNECT,clientId:this._0},function(a){if(a.successful)this._f.close()},this);this.info('Clearing channel listeners for ?',this._0);this._2=new Faye.Channel.Set()},subscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.subscribe(channel,d,f)},this);var g=new Faye.Subscription(this,c,d,f);var h=(d===true);if(!h&&this._2.hasSubscription(c)){this._2.subscribe([c],d,f);g.setDeferredStatus('succeeded');return g}this.connect(function(){this.info('Client ? attempting to subscribe to ?',this._0,c);this._9({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return g.setDeferredStatus('failed',Faye.Error.parse(a.error));var b=[].concat(a.subscription);this.info('Subscription acknowledged for ? to ?',this._0,b);if(!h)this._2.subscribe(b,d,f);g.setDeferredStatus('succeeded')},this)},this);return g},unsubscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.unsubscribe(channel,d,f)},this);var g=this._2.unsubscribe(c,d,f);if(!g)return;this.connect(function(){this.info('Client ? attempting to unsubscribe from ?',this._0,c);this._9({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return;var b=[].concat(a.subscription);this.info('Unsubscription acknowledged for ? from ?',this._0,b)},this)},this)},publish:function(b,c){if(!Faye.Grammar.CHANNEL_NAME.test(b))throw new Error("Cannot publish: '"+b+"' is not a valid channel name");var d=new Faye.Publication();this.connect(function(){this.info('Client ? queueing published message to ?: ?',this._0,b,c);this._9({channel:b,data:c,clientId:this._0},function(a){if(a.successful)d.setDeferredStatus('succeeded');else d.setDeferredStatus('failed',Faye.Error.parse(a.error))},this)},this);return d},receiveMessage:function(c){this.pipeThroughExtensions('incoming',c,function(a){if(!a)return;if(a.advice)this._D(a.advice);var b=this._q[a.id];if(b){delete this._q[a.id];b[0].call(b[1],a)}this._E(a)},this)},_y:function(b){Faye.Transport.get(this,b,function(a){this._f=a;a.bind('down',function(){if(this._c!==undefined&&!this._c)return;this._c=false;this.trigger('transport:down')},this);a.bind('up',function(){if(this._c!==undefined&&this._c)return;this._c=true;this.trigger('transport:up')},this)},this)},_9:function(b,c,d){b.id=this._F();if(c)this._q[b.id]=[c,d];this.pipeThroughExtensions('outgoing',b,function(a){if(!a)return;this._f.send(a,this._6.timeout/1000)},this)},_F:function(){this._e+=1;if(this._e>=Math.pow(2,32))this._e=0;return this._e.toString(36)},_D:function(a){Faye.extend(this._6,a);if(this._6.reconnect===this.HANDSHAKE&&this._1!==this.DISCONNECTED){this._1=this.UNCONNECTED;this._0=null;this._z()}},_E:function(a){if(!a.channel||!a.data)return;this.info('Client ? calling listeners for ? with ?',this._0,a.channel,a.data);this._2.distributeMessage(a)},_G:function(){if(!this._r)return;this._r=null;this.info('Closed connection for ?',this._0)},_z:function(){this._G();var a=this;Faye.ENV.setTimeout(function(){a.connect()},this._6.interval)}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.extend(Faye.Client.prototype,Faye.Publisher);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.extend(Faye.Client.prototype,Faye.Extensible);Faye.Transport=Faye.extend(Faye.Class({MAX_DELAY:0.0,batching:true,initialize:function(a,b){this.debug('Created new ? transport for ?',this.connectionType,b);this._8=a;this._a=b;this._g=[]},close:function(){},send:function(a,b){this.debug('Client ? sending message to ?: ?',this._8._0,this._a,a);if(!this.batching)return this.request([a],b);this._g.push(a);this._b=b;if(a.channel===Faye.Channel.HANDSHAKE)return this.flush();if(a.channel===Faye.Channel.CONNECT)this._s=a;this.addTimeout('publish',this.MAX_DELAY,this.flush,this)},flush:function(){this.removeTimeout('publish');if(this._g.length>1&&this._s)this._s.advice={timeout:0};this.request(this._g,this._b);this._s=null;this._g=[]},receive:function(a){this.debug('Client ? received from ?: ?',this._8._0,this._a,a);Faye.each(a,this._8.receiveMessage,this._8)},retry:function(a,b){var c=this,d=false;return function(){if(d)return;d=true;Faye.ENV.setTimeout(function(){c.request(a,2*b)},1000*b)}}}),{get:function(g,h,i,j){var k=g.endpoint;if(h===undefined)h=this.supportedConnectionTypes();Faye.asyncEach(this._t,function(b,c){var d=b[0],f=b[1];if(Faye.indexOf(h,d)<0)return c();f.isUsable(k,function(a){if(a)i.call(j,new f(g,k));else c()})},function(){throw new Error('Could not find a usable connection type for '+k);})},register:function(a,b){this._t.push([a,b]);b.prototype.connectionType=a},_t:[],supportedConnectionTypes:function(){return Faye.map(this._t,function(a){return a[0]})}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.extend(Faye.Transport.prototype,Faye.Publisher);Faye.extend(Faye.Transport.prototype,Faye.Timeouts);Faye.Event={_h:[],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._h.push({_i:a,_u:b,_n:c,_o:d,_A:f})},detach:function(a,b,c,d){var f=this._h.length,g;while(f--){g=this._h[f];if((a&&a!==g._i)||(b&&b!==g._u)||(c&&c!==g._n)||(d&&d!==g._o))continue;if(g._i.removeEventListener)g._i.removeEventListener(g._u,g._A,false);else g._i.detachEvent('on'+g._u,g._A);this._h.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(){var a=this.queryString();return this.protocol+this.hostname+':'+this.port+this.pathname+(a?'?'+a:'')}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var h=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};h('protocol',/^https?\:\/+/);h('hostname',/^[^\/\:]+/);h('port',/^:[0-9]+/);Faye.extend(g,{protocol:Faye.ENV.location.protocol+'//',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('?'),j=i.shift(),k=i.join('?'),m=k?k.split('&'):[],n=m.length,l={};while(n--){i=m[n].split('=');l[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}if(typeof f==='object')Faye.extend(l,f);g.pathname=j;g.params=l;return g}});if(!this.JSON){JSON={}}(function(){function k(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+k(this.getUTCMonth()+1)+'-'+k(this.getUTCDate())+'T'+k(this.getUTCHours())+':'+k(this.getUTCMinutes())+':'+k(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var m=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,n=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,l,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},o;function r(c){n.lastIndex=0;return n.test(c)?'"'+c.replace(n,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,h=l,i,j=b[a];if(j&&typeof j==='object'&&typeof j.toJSON==='function'){j=j.toJSON(a)}if(typeof o==='function'){j=o.call(b,a,j)}switch(typeof j){case'string':return r(j);case'number':return isFinite(j)?String(j):'null';case'boolean':case'null':return String(j);case'object':if(!j){return'null'}l+=p;i=[];if(Object.prototype.toString.apply(j)==='[object Array]'){g=j.length;for(c=0;c<g;c+=1){i[c]=q(c,j)||'null'}f=i.length===0?'[]':l?'[\n'+l+i.join(',\n'+l)+'\n'+h+']':'['+i.join(',')+']';l=h;return f}if(o&&typeof o==='object'){g=o.length;for(c=0;c<g;c+=1){d=o[c];if(typeof d==='string'){f=q(d,j);if(f){i.push(r(d)+(l?': ':':')+f)}}}}else{for(d in j){if(Object.hasOwnProperty.call(j,d)){f=q(d,j);if(f){i.push(r(d)+(l?': ':':')+f)}}}}f=i.length===0?'{}':l?'{\n'+l+i.join(',\n'+l)+'\n'+h+'}':'{'+i.join(',')+'}';l=h;return f}}Faye.stringify=function(a,b,c){var d;l='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}o=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,h){var i;function j(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=j(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return h.call(a,b,f)}m.lastIndex=0;if(m.test(g)){g=g.replace(m,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 h==='function'?j({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.Transport.WebSocket=Faye.extend(Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,batching:false,request:function(b,c){this._b=c||this._b;this._j=this._j||{};Faye.each(b,function(a){this._j[a.id]=a},this);this.withSocket(function(a){a.send(Faye.toJSON(b))})},withSocket:function(a,b){this.callback(a,b);this.connect()},close:function(){if(this._B)return;this._B=true;if(this._7)this._7.close()},connect:function(){if(this._B)return;this._1=this._1||this.UNCONNECTED;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var d=Faye.Transport.WebSocket.getClass();this._7=new d(Faye.Transport.WebSocket.getSocketUrl(this._a));var f=this;this._7.onopen=function(){f._1=f.CONNECTED;f.setDeferredStatus('succeeded',f._7);f.trigger('up')};this._7.onmessage=function(b){var c=[].concat(JSON.parse(b.data));Faye.each(c,function(a){delete f._j[a.id]});f.receive(c)};this._7.onclose=function(){var a=(f._1===f.CONNECTED);f.setDeferredStatus('deferred');f._1=f.UNCONNECTED;delete f._7;if(a)return f.resend();Faye.ENV.setTimeout(function(){f.connect()},1000*f._b);f._b=f._b*2;f.trigger('down')}},resend:function(){var c=Faye.map(this._j,function(a,b){return b});this.request(c)}}),{WEBSOCKET_TIMEOUT:1000,getSocketUrl:function(a){if(Faye.URI)a=Faye.URI.parse(a).toURL();return a.replace(/^http(s?):/ig,'ws$1:')},getClass:function(){if(Faye.WebSocket)return Faye.WebSocket.Client;return Faye.ENV.WebSocket||Faye.ENV.MozWebSocket},isUsable:function(a,b,c){var d=this.getClass();if(!d)return b.call(c,false);var f=false,g=false,h=this.getSocketUrl(a),i=new d(h);i.onopen=function(){f=true;i.close();b.call(c,true);g=true;i=null};var j=function(){if(!g&&!f)b.call(c,false);g=true};i.onclose=i.onerror=j;Faye.ENV.setTimeout(j,this.WEBSOCKET_TIMEOUT)}});Faye.extend(Faye.Transport.WebSocket.prototype,Faye.Deferrable);Faye.Transport.register('websocket',Faye.Transport.WebSocket);Faye.Transport.XHR=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c){var d=this.retry(b,c),f=Faye.URI.parse(this._a).pathname,g=this,h=Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();h.open('POST',f,true);h.setRequestHeader('Content-Type','application/json');h.setRequestHeader('X-Requested-With','XMLHttpRequest');h.onreadystatechange=function(){if(h.readyState!==4)return;var a=h.status;try{if((a>=200&&a<300)||a===304||a===1223){g.receive(JSON.parse(h.responseText));g.trigger('up')}else{d();g.trigger('down')}}catch(e){d()}finally{Faye.Event.detach(Faye.ENV,'beforeunload',i);h.onreadystatechange=function(){};h=null}};var i=function(){h.abort()};Faye.Event.on(Faye.ENV,'beforeunload',i);h.send(Faye.toJSON(b))}}),{isUsable:function(a,b,c){b.call(c,Faye.URI.parse(a).isLocal())}});Faye.Transport.register('long-polling',Faye.Transport.XHR);Faye.Transport.CORS=Faye.extend(Faye.Class(Faye.Transport,{request:function(a,b){var c=Faye.ENV.XDomainRequest?XDomainRequest:XMLHttpRequest,d=new c(),f=this.retry(a,b),g=this;d.open('POST',this._a,true);var h=function(){if(!d)return false;d.onload=d.onerror=d.ontimeout=d.onprogress=null;d=null;Faye.ENV.clearTimeout(j);return true};d.onload=function(){try{g.receive(JSON.parse(d.responseText));g.trigger('up')}catch(e){f()}finally{h()}};var i=function(){h();f();g.trigger('down')};var j=Faye.ENV.setTimeout(i,1.5*1000*b);d.onerror=i;d.ontimeout=i;d.onprogress=function(){};d.send('message='+encodeURIComponent(Faye.toJSON(a)))}}),{isUsable:function(a,b,c){if(Faye.URI.parse(a).isLocal())return b.call(c,false);if(Faye.ENV.XDomainRequest)return b.call(c,true);if(Faye.ENV.XMLHttpRequest){var d=new Faye.ENV.XMLHttpRequest();return b.call(c,d.withCredentials!==undefined)}return b.call(c,false)}});Faye.Transport.register('cross-origin-long-polling',Faye.Transport.CORS);Faye.Transport.JSONP=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c){var d={message:Faye.toJSON(b)},f=document.getElementsByTagName('head')[0],g=document.createElement('script'),h=Faye.Transport.JSONP.getCallbackName(),i=Faye.URI.parse(this._a,d),j=this.retry(b,c),k=this;Faye.ENV[h]=function(a){n();k.receive(a);k.trigger('up')};var m=Faye.ENV.setTimeout(function(){n();j();k.trigger('down')},1.5*1000*c);var n=function(){if(!Faye.ENV[h])return false;Faye.ENV[h]=undefined;try{delete Faye.ENV[h]}catch(e){}Faye.ENV.clearTimeout(m);g.parentNode.removeChild(g);return true};i.params.jsonp=h;g.type='text/javascript';g.src=i.toURL();f.appendChild(g)}}),{_C:0,getCallbackName:function(){this._C+=1;return'__jsonp'+this._C+'__'},isUsable:function(a,b,c){b.call(c,true)}});Faye.Transport.register('callback-polling',Faye.Transport.JSONP);
|
data/lib/faye.rb
CHANGED
@@ -1,12 +1,47 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'base64'
|
2
|
+
require 'cgi'
|
3
|
+
require 'cookiejar'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'digest/sha1'
|
6
|
+
require 'em-http'
|
7
|
+
require 'em-http/version'
|
3
8
|
require 'eventmachine'
|
9
|
+
require 'forwardable'
|
4
10
|
require 'json'
|
11
|
+
require 'net/http'
|
12
|
+
require 'rack'
|
13
|
+
require 'set'
|
14
|
+
require 'thin'
|
15
|
+
require 'time'
|
16
|
+
require 'uri'
|
5
17
|
|
6
18
|
module Faye
|
7
|
-
VERSION = '0.
|
19
|
+
VERSION = '0.7.0'
|
8
20
|
|
9
21
|
ROOT = File.expand_path(File.dirname(__FILE__))
|
22
|
+
require File.join(ROOT, 'faye', 'thin_extensions')
|
23
|
+
|
24
|
+
autoload :Publisher, File.join(ROOT, 'faye', 'mixins', 'publisher')
|
25
|
+
autoload :Timeouts, File.join(ROOT, 'faye', 'mixins', 'timeouts')
|
26
|
+
autoload :Logging, File.join(ROOT, 'faye', 'mixins', 'logging')
|
27
|
+
|
28
|
+
autoload :Namespace, File.join(ROOT, 'faye', 'util', 'namespace')
|
29
|
+
|
30
|
+
autoload :Engine, File.join(ROOT, 'faye', 'engines', 'base')
|
31
|
+
|
32
|
+
autoload :Grammar, File.join(ROOT, 'faye', 'protocol', 'grammar')
|
33
|
+
autoload :Extensible, File.join(ROOT, 'faye', 'protocol', 'extensible')
|
34
|
+
autoload :Channel, File.join(ROOT, 'faye', 'protocol', 'channel')
|
35
|
+
autoload :Subscription, File.join(ROOT, 'faye', 'protocol', 'subscription')
|
36
|
+
autoload :Publication, File.join(ROOT, 'faye', 'protocol', 'publication')
|
37
|
+
autoload :Client, File.join(ROOT, 'faye', 'protocol', 'client')
|
38
|
+
autoload :Server, File.join(ROOT, 'faye', 'protocol', 'server')
|
39
|
+
|
40
|
+
autoload :Transport, File.join(ROOT, 'faye', 'transport', 'transport')
|
41
|
+
autoload :Error, File.join(ROOT, 'faye', 'error')
|
42
|
+
|
43
|
+
autoload :RackAdapter, File.join(ROOT, 'faye', 'adapters', 'rack_adapter')
|
44
|
+
autoload :WebSocket, File.join(ROOT, 'faye', 'util', 'web_socket')
|
10
45
|
|
11
46
|
BAYEUX_VERSION = '1.0'
|
12
47
|
ID_LENGTH = 128
|
@@ -15,31 +50,13 @@ module Faye
|
|
15
50
|
|
16
51
|
MANDATORY_CONNECTION_TYPES = %w[long-polling callback-polling in-process]
|
17
52
|
|
18
|
-
|
19
|
-
|
20
|
-
mixins/logging
|
21
|
-
util/namespace
|
22
|
-
engines/base
|
23
|
-
engines/connection
|
24
|
-
engines/memory
|
25
|
-
engines/redis
|
26
|
-
protocol/grammar
|
27
|
-
protocol/extensible
|
28
|
-
protocol/channel
|
29
|
-
protocol/subscription
|
30
|
-
protocol/client
|
31
|
-
protocol/server
|
32
|
-
transport/transport
|
33
|
-
transport/local
|
34
|
-
transport/http
|
35
|
-
error
|
36
|
-
|
37
|
-
].each do |lib|
|
38
|
-
require File.join(ROOT, 'faye', lib)
|
39
|
-
end
|
53
|
+
# http://www.w3.org/International/questions/qa-forms-utf-8.en.php
|
54
|
+
UTF8_MATCH = /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/
|
40
55
|
|
41
|
-
|
42
|
-
|
56
|
+
def self.ensure_reactor_running!
|
57
|
+
Thread.new { EM.run } unless EM.reactor_running?
|
58
|
+
while not EM.reactor_running?; end
|
59
|
+
end
|
43
60
|
|
44
61
|
def self.random(bitlength = ID_LENGTH)
|
45
62
|
limit = 2 ** bitlength - 1
|
@@ -49,6 +66,10 @@ module Faye
|
|
49
66
|
string
|
50
67
|
end
|
51
68
|
|
69
|
+
def self.copy_object(object)
|
70
|
+
Marshal.load(Marshal.dump(object))
|
71
|
+
end
|
72
|
+
|
52
73
|
def self.to_json(value)
|
53
74
|
case value
|
54
75
|
when Hash, Array then JSON.unparse(value)
|
@@ -57,14 +78,50 @@ module Faye
|
|
57
78
|
end
|
58
79
|
end
|
59
80
|
|
60
|
-
def self.
|
81
|
+
def self.async_each(list, iterator, callback)
|
82
|
+
n = list.size
|
83
|
+
i = -1
|
84
|
+
calls = 0
|
85
|
+
looping = false
|
86
|
+
|
87
|
+
loop, resume = nil, nil
|
88
|
+
|
89
|
+
iterate = lambda do
|
90
|
+
calls -= 1
|
91
|
+
i += 1
|
92
|
+
if i == n
|
93
|
+
callback.call if callback
|
94
|
+
else
|
95
|
+
iterator.call(list[i], resume)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
loop = lambda do
|
100
|
+
unless looping
|
101
|
+
looping = true
|
102
|
+
iterate.call while calls > 0
|
103
|
+
looping = false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
resume = lambda do
|
108
|
+
calls += 1
|
109
|
+
loop.call
|
110
|
+
end
|
111
|
+
resume.call
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.encode(string, validate_encoding = false)
|
115
|
+
if Array === string
|
116
|
+
return nil if validate_encoding and !valid_utf8?(string)
|
117
|
+
string = string.pack('C*')
|
118
|
+
end
|
61
119
|
return string unless string.respond_to?(:force_encoding)
|
62
|
-
string.force_encoding(
|
120
|
+
string.force_encoding('UTF-8')
|
63
121
|
end
|
64
122
|
|
65
|
-
def self.
|
66
|
-
|
67
|
-
while not EM.reactor_running?; end
|
123
|
+
def self.valid_utf8?(byte_array)
|
124
|
+
UTF8_MATCH =~ byte_array.pack('C*') ? true : false
|
68
125
|
end
|
69
126
|
end
|
70
127
|
|
@@ -1,16 +1,11 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
require 'digest/sha1'
|
3
|
-
require 'json'
|
4
|
-
require 'rack'
|
5
|
-
require 'thin'
|
6
|
-
require 'time'
|
7
|
-
require Faye::ROOT + '/faye/thin_extensions'
|
8
|
-
|
9
1
|
module Faye
|
10
2
|
class RackAdapter
|
11
3
|
|
12
4
|
include Logging
|
13
5
|
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators "@server.engine", :bind, :unbind
|
8
|
+
|
14
9
|
# Only supported under Thin
|
15
10
|
ASYNC_RESPONSE = [-1, {}, []].freeze
|
16
11
|
|
@@ -128,11 +123,27 @@ module Faye
|
|
128
123
|
end
|
129
124
|
|
130
125
|
ASYNC_RESPONSE
|
131
|
-
|
132
126
|
rescue
|
133
127
|
[400, TYPE_TEXT, ['Bad request']]
|
134
128
|
end
|
135
129
|
|
130
|
+
def handle_upgrade(request)
|
131
|
+
socket = Faye::WebSocket.new(request.env)
|
132
|
+
|
133
|
+
socket.onmessage = lambda do |message|
|
134
|
+
begin
|
135
|
+
message = JSON.parse(message.data)
|
136
|
+
debug "Received via WebSocket[#{socket.version}]: ?", message
|
137
|
+
@server.process(message, false) do |replies|
|
138
|
+
debug "Sending via WebSocket[#{socket.version}]: ?", replies
|
139
|
+
socket.send(JSON.unparse(replies))
|
140
|
+
end
|
141
|
+
rescue
|
142
|
+
end
|
143
|
+
end
|
144
|
+
ASYNC_RESPONSE
|
145
|
+
end
|
146
|
+
|
136
147
|
def message_from_request(request)
|
137
148
|
message = request.params['message']
|
138
149
|
return message if message
|
@@ -160,23 +171,6 @@ module Faye
|
|
160
171
|
[200, headers, ['']]
|
161
172
|
end
|
162
173
|
|
163
|
-
def handle_upgrade(request)
|
164
|
-
socket = Faye::WebSocket.new(request)
|
165
|
-
|
166
|
-
socket.onmessage = lambda do |message|
|
167
|
-
begin
|
168
|
-
message = JSON.parse(message.data)
|
169
|
-
debug "Received via WebSocket[#{socket.version}]: ?", message
|
170
|
-
@server.process(message, false) do |replies|
|
171
|
-
debug "Sending via WebSocket[#{socket.version}]: ?", replies
|
172
|
-
socket.send(JSON.unparse(replies))
|
173
|
-
end
|
174
|
-
rescue
|
175
|
-
end
|
176
|
-
end
|
177
|
-
ASYNC_RESPONSE
|
178
|
-
end
|
179
|
-
|
180
174
|
class DeferredBody
|
181
175
|
include EventMachine::Deferrable
|
182
176
|
alias :each :callback
|
data/lib/faye/engines/base.rb
CHANGED
@@ -17,6 +17,7 @@ module Faye
|
|
17
17
|
end
|
18
18
|
|
19
19
|
class Base
|
20
|
+
include Publisher
|
20
21
|
include Logging
|
21
22
|
|
22
23
|
attr_reader :interval, :timeout
|
@@ -56,6 +57,10 @@ module Faye
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
60
|
+
%w[connection memory redis].each do |type|
|
61
|
+
require File.join(ROOT, 'faye', 'engines', type)
|
62
|
+
end
|
63
|
+
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
data/lib/faye/engines/memory.rb
CHANGED
@@ -17,6 +17,7 @@ module Faye
|
|
17
17
|
debug 'Created new client ?', client_id
|
18
18
|
ping(client_id)
|
19
19
|
callback.call(client_id)
|
20
|
+
trigger(:handshake, client_id)
|
20
21
|
end
|
21
22
|
|
22
23
|
def destroy_client(client_id, &callback)
|
@@ -31,6 +32,7 @@ module Faye
|
|
31
32
|
@messages.delete(client_id)
|
32
33
|
debug 'Destroyed client ?', client_id
|
33
34
|
callback.call if callback
|
35
|
+
trigger(:disconnect, client_id)
|
34
36
|
end
|
35
37
|
|
36
38
|
def client_exists(client_id, &callback)
|
@@ -46,18 +48,19 @@ module Faye
|
|
46
48
|
|
47
49
|
def subscribe(client_id, channel, &callback)
|
48
50
|
@clients[client_id] ||= Set.new
|
49
|
-
@clients[client_id].add(channel)
|
51
|
+
should_trigger = @clients[client_id].add?(channel)
|
50
52
|
|
51
53
|
@channels[channel] ||= Set.new
|
52
54
|
@channels[channel].add(client_id)
|
53
55
|
|
54
56
|
debug 'Subscribed client ? to channel ?', client_id, channel
|
57
|
+
trigger(:subscribe, client_id, channel) if should_trigger
|
55
58
|
callback.call(true) if callback
|
56
59
|
end
|
57
60
|
|
58
61
|
def unsubscribe(client_id, channel, &callback)
|
59
62
|
if @clients.has_key?(client_id)
|
60
|
-
@clients[client_id].delete(channel)
|
63
|
+
should_trigger = @clients[client_id].delete?(channel)
|
61
64
|
@clients.delete(client_id) if @clients[client_id].empty?
|
62
65
|
end
|
63
66
|
|
@@ -67,6 +70,7 @@ module Faye
|
|
67
70
|
end
|
68
71
|
|
69
72
|
debug 'Unsubscribed client ? from channel ?', client_id, channel
|
73
|
+
trigger(:unsubscribe, client_id, channel) if should_trigger
|
70
74
|
callback.call(true) if callback
|
71
75
|
end
|
72
76
|
|
@@ -84,9 +88,11 @@ module Faye
|
|
84
88
|
clients.each do |client_id|
|
85
89
|
debug 'Queueing for client ?: ?', client_id, message
|
86
90
|
@messages[client_id] ||= []
|
87
|
-
@messages[client_id] << message
|
91
|
+
@messages[client_id] << Faye.copy_object(message)
|
88
92
|
empty_queue(client_id)
|
89
93
|
end
|
94
|
+
|
95
|
+
trigger(:publish, message['clientId'], message['channel'], message['data'])
|
90
96
|
end
|
91
97
|
|
92
98
|
private
|
data/lib/faye/engines/redis.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Faye
|
2
2
|
module Engine
|
3
|
-
|
3
|
+
|
4
4
|
class Redis < Base
|
5
5
|
DEFAULT_HOST = 'localhost'
|
6
6
|
DEFAULT_PORT = 6379
|
@@ -12,15 +12,21 @@ module Faye
|
|
12
12
|
return if @redis
|
13
13
|
require 'em-hiredis'
|
14
14
|
|
15
|
-
host
|
16
|
-
port
|
17
|
-
db
|
18
|
-
auth
|
19
|
-
gc
|
20
|
-
@ns
|
15
|
+
host = @options[:host] || DEFAULT_HOST
|
16
|
+
port = @options[:port] || DEFAULT_PORT
|
17
|
+
db = @options[:database] || 0
|
18
|
+
auth = @options[:password]
|
19
|
+
gc = @options[:gc] || DEFAULT_GC
|
20
|
+
@ns = @options[:namespace] || ''
|
21
|
+
socket = @options[:socket]
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
if socket
|
24
|
+
@redis = EventMachine::Hiredis::Client.connect(socket, nil)
|
25
|
+
@subscriber = EventMachine::Hiredis::Client.connect(socket, nil)
|
26
|
+
else
|
27
|
+
@redis = EventMachine::Hiredis::Client.connect(host, port)
|
28
|
+
@subscriber = EventMachine::Hiredis::Client.connect(host, port)
|
29
|
+
end
|
24
30
|
|
25
31
|
if auth
|
26
32
|
@redis.auth(auth)
|
@@ -52,6 +58,7 @@ module Faye
|
|
52
58
|
debug 'Created new client ?', client_id
|
53
59
|
ping(client_id)
|
54
60
|
callback.call(client_id)
|
61
|
+
trigger(:handshake, client_id)
|
55
62
|
end
|
56
63
|
end
|
57
64
|
end
|
@@ -66,6 +73,7 @@ module Faye
|
|
66
73
|
if n == 0
|
67
74
|
debug 'Destroyed client ?', client_id
|
68
75
|
callback.call if callback
|
76
|
+
trigger(:disconnect, client_id)
|
69
77
|
else
|
70
78
|
channels.each do |channel|
|
71
79
|
unsubscribe(client_id, channel) do
|
@@ -73,6 +81,7 @@ module Faye
|
|
73
81
|
if i == n
|
74
82
|
debug 'Destroyed client ?', client_id
|
75
83
|
callback.call if callback
|
84
|
+
trigger(:disconnect, client_id)
|
76
85
|
end
|
77
86
|
end
|
78
87
|
end
|
@@ -98,7 +107,9 @@ module Faye
|
|
98
107
|
|
99
108
|
def subscribe(client_id, channel, &callback)
|
100
109
|
init
|
101
|
-
@redis.sadd(@ns + "/clients/#{client_id}/channels", channel)
|
110
|
+
@redis.sadd(@ns + "/clients/#{client_id}/channels", channel) do |added|
|
111
|
+
trigger(:subscribe, client_id, channel) if added == 1
|
112
|
+
end
|
102
113
|
@redis.sadd(@ns + "/channels#{channel}", client_id) do
|
103
114
|
debug 'Subscribed client ? to channel ?', client_id, channel
|
104
115
|
callback.call if callback
|
@@ -107,7 +118,9 @@ module Faye
|
|
107
118
|
|
108
119
|
def unsubscribe(client_id, channel, &callback)
|
109
120
|
init
|
110
|
-
@redis.srem(@ns + "/clients/#{client_id}/channels", channel)
|
121
|
+
@redis.srem(@ns + "/clients/#{client_id}/channels", channel) do |removed|
|
122
|
+
trigger(:unsubscribe, client_id, channel) if removed == 1
|
123
|
+
end
|
111
124
|
@redis.srem(@ns + "/channels#{channel}", client_id) do
|
112
125
|
debug 'Unsubscribed client ? from channel ?', client_id, channel
|
113
126
|
callback.call if callback
|
@@ -129,6 +142,8 @@ module Faye
|
|
129
142
|
@redis.publish(@ns + '/notifications', client_id)
|
130
143
|
end
|
131
144
|
end
|
145
|
+
|
146
|
+
trigger(:publish, message['clientId'], message['channel'], message['data'])
|
132
147
|
end
|
133
148
|
|
134
149
|
private
|
@@ -1,29 +1,25 @@
|
|
1
1
|
module Faye
|
2
2
|
module Publisher
|
3
3
|
|
4
|
-
def
|
4
|
+
def count_listeners(event_type)
|
5
5
|
return 0 unless @subscribers and @subscribers[event_type]
|
6
6
|
@subscribers[event_type].size
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def bind(event_type, &listener)
|
10
10
|
@subscribers ||= {}
|
11
11
|
list = @subscribers[event_type] ||= []
|
12
12
|
list << listener
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
15
|
+
def unbind(event_type, &listener)
|
16
16
|
return unless @subscribers and @subscribers[event_type]
|
17
17
|
return @subscribers.delete(event_type) unless listener
|
18
18
|
|
19
19
|
@subscribers[event_type].delete_if(&listener.method(:==))
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
@subscribers = {}
|
24
|
-
end
|
25
|
-
|
26
|
-
def publish_event(event_type, *args)
|
22
|
+
def trigger(event_type, *args)
|
27
23
|
return unless @subscribers and @subscribers[event_type]
|
28
24
|
@subscribers[event_type].each do |listener|
|
29
25
|
listener.call(*args)
|