faye 0.5.3 → 0.5.4

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 CHANGED
@@ -1,3 +1,12 @@
1
+ === 0.5.4 / 2010-12-19
2
+
3
+ * Add a #callback method to Subscriptions to detect when they become active
4
+ * Add :extensions option to RackAdapter to make it easier to extend middleware
5
+ * Detect secure WebSocket requests through the HTTP_X_FORWARDED_PROTO header
6
+ * Handle socket errors when sending WebSocket messages from NodeAdapter
7
+ * Use exponential backoff to reconnect client-side WebSockets to reduce CPU load
8
+
9
+
1
10
  === 0.5.3 / 2010-10-21
2
11
 
3
12
  * Improve detection of wss: requirement for secure WebSocket connections
data/README.txt CHANGED
@@ -39,16 +39,36 @@ to install:
39
39
 
40
40
  == To-do
41
41
 
42
+ Refactoring:
43
+
44
+ * Refactor tests, put more unit tests in place for both versions
45
+ * Separate protocol server from pub/sub engine to allow for alternate backends
46
+ * Examine Client vs. Transport responsibilities, e.g. make message batching transport-dependent
47
+
48
+ Fault tolerance:
49
+
42
50
  * Detect failed WebSocket connection and fall back to polling transports
43
- * Add events to Subscriptions to notify the user when they are active
51
+
52
+ Notification API:
53
+
44
54
  * Notify listeners of network drop-out (may be transport dependent)
45
- * Provide better API for adding extensions to Rack middleware
55
+ * Provide reflection API for internal stats on channels, subscriptions, message queues
56
+ * (Maybe) build a monitoring GUI into the server
57
+
58
+ Sugar:
59
+
46
60
  * Add sugar for authentication extensions for protected subscribe + publish
61
+
62
+ Performance:
63
+
47
64
  * Optimise channel unsubscription -- currently O(N) where N = clients
48
- * Expose the Timeouts module to help users expire clients at the app level
65
+ * Provide hubs to connect multiple servers together in a network
66
+ * (maybe) provide a backend based on Redis or AMQP
67
+
68
+ Missing protocol features:
69
+
49
70
  * Provide support for user-defined <tt>/service/*</tt> channels
50
71
  * Let local server-side clients listen to <tt>/meta/*</tt> channels
51
- * Allow server to scale to multiple nodes
52
72
 
53
73
 
54
74
  == License
@@ -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.5.3',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:['long-polling','callback-polling','websocket'],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);return Math.floor(Math.random()*d).toString(36)},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){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}},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(),i=b.getMinutes(),j=b.getSeconds();var h=function(a){return a<10?'0'+a:String(a)};return h(c)+'-'+h(d)+'-'+h(f)+' '+h(g)+':'+h(i)+':'+h(j)}});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._v={}},generate:function(){var a=Faye.random();while(this._v.hasOwnProperty(a))a=Faye.random();return this._v[a]=a}});Faye.Deferrable={callback:function(a,b){if(!a)return;if(this._C==='succeeded')return a.apply(b,this._w);this._a=this._a||[];this._a.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._C=c;this._w=b;if(c!=='succeeded')return;if(!this._a)return;Faye.each(this._a,function(a){a[0].apply(a[1],this._w)},this);this._a=[]}};Faye.Publisher={countSubscribers:function(a){if(!this._2||!this._2[a])return 0;return this._2[a].length},addSubscriber:function(a,b,c){this._2=this._2||{};var d=this._2[a]=this._2[a]||[];d.push([b,c])},removeSubscriber:function(a,b,c){if(!this._2||!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)}},publishEvent: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)})}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._7=this._7||{};if(this._7.hasOwnProperty(a))return;var f=this;this._7[a]=setTimeout(function(){delete f._7[a];c.call(d)},1000*b)},removeTimeout:function(a){this._7=this._7||{};var b=this._7[a];if(!b)return;clearTimeout(b);delete this._7[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=null,g=a.shift().replace(/\?/g,function(){try{return Faye.toJSON(a.shift())}catch(e){return'[Object]'}});for(var i in Faye){if(f)continue;if(typeof Faye[i]!=='function')continue;if(this instanceof Faye[i])f=i}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._8=this._8||[];this._8.push(a);if(a.added)a.added()},removeExtension:function(a){if(!this._8)return;var b=this._8.length;while(b--){if(this._8[b]!==a)continue;this._8.splice(b,1);if(a.removed)a.removed()}},pipeThroughExtensions:function(c,d,f,g){if(!this._8)return f.call(g,d);var i=this._8.slice();var j=function(a){if(!a)return f.call(g,a);var b=i.shift();if(!b)return f.call(g,a);if(b[c])b[c](a,j);else j(a)};j(d)}};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',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,b){this._m=a;this._3=b;this._6={}},eachChild:function(c,d){Faye.each(this._6,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},remove:function(a){if(a){var b=this.traverse(a);if(b)b.remove()}else{if(!this._m)return;this._m.removeChild(this);this._m=this._3=undefined}},removeChild:function(c){this.eachChild(function(a,b){if(b===c)delete this._6[a]},this);if(Faye.size(this._6)===0&&this._3===undefined)this.remove()},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._6[a[0]];if(!c&&!b)return null;if(!c)c=this._6[a[0]]=new Faye.Channel.Tree(this);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._6,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._6,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._6['**'])g.push(this._6['**']._3);return g},subscribe:function(c,d,f){if(!d)return;Faye.each(c,function(a){var b=this.findOrCreate(a);b.addSubscriber('message',d,f)},this)},unsubscribe:function(a,b,c){var d=this.get(a);if(!d)return false;d.removeSubscriber('message',b,c);if(d.isUnused()){this.remove(a);return true}else{return false}},distributeMessage:function(b){var c=this.glob(b.channel);Faye.each(c,function(a){a.publishEvent('message',b.data)})}})});Faye.Subscription=Faye.Class({initialize:function(a,b,c,d){this._c=a;this._b=b;this._n=c;this._d=d;this._x=false},cancel:function(){if(this._x)return;this._c.unsubscribe(this._b,this._n,this._d);this._x=true},unsubscribe:function(){this.cancel()}});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.001,INTERVAL:0.0,initialize:function(a,b){this.info('New client created for ?',a);this._4=a||this.DEFAULT_ENDPOINT;this._y=b||{};this._f=Faye.Transport.get(this,Faye.MANDATORY_CONNECTION_TYPES);this._1=this.UNCONNECTED;this._h=[];this._b=new Faye.Channel.Tree();this._D=new Faye.Namespace();this._o={};this._9={reconnect:this.RETRY,interval:1000*(this._y.interval||this.INTERVAL),timeout:1000*(this._y.timeout||this.CONNECTION_TIMEOUT)};if(Faye.Event)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._e({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:[this._f.connectionType]},function(a){if(a.successful){this._1=this.CONNECTED;this._0=a.clientId;this._f=Faye.Transport.get(this,a.supportedConnectionTypes);this.info('Handshake successful: ?',this._0);this.subscribe(this._b.getKeys());if(b)b.call(c)}else{this.info('Handshake unsuccessful');setTimeout(function(){d.handshake(b,c)},this._9.interval);this._1=this.UNCONNECTED}},this)},connect:function(a,b){if(this._9.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._e({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._e({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for ?',this._0);this._b=new Faye.Channel.Tree()},subscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.subscribe(channel,d,f)},this);this._q(c);this.connect(function(){this.info('Client ? attempting to subscribe to ?',this._0,c);this._e({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return;var b=[].concat(a.subscription);this.info('Subscription acknowledged for ? to ?',this._0,b);this._b.subscribe(b,d,f)},this)},this);return new Faye.Subscription(this,c,d,f)},unsubscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.unsubscribe(channel,d,f)},this);this._q(c);var g=this._b.unsubscribe(c,d,f);if(!g)return;this.connect(function(){this.info('Client ? attempting to unsubscribe from ?',this._0,c);this._e({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){this._q(a);this.connect(function(){this.info('Client ? queueing published message to ?: ?',this._0,a,b);this._e({channel:a,data:b,clientId:this._0})},this)},receiveMessage:function(c){this.pipeThroughExtensions('incoming',c,function(a){if(!a)return;if(a.advice)this._E(a.advice);var b=this._o[a.id];if(b){delete this._o[a.id];b[0].call(b[1],a)}this._F(a)},this)},_E:function(a){Faye.extend(this._9,a);if(this._9.reconnect===this.HANDSHAKE&&this._1!==this.DISCONNECTED){this._1=this.UNCONNECTED;this._0=null;this._z()}},_F:function(a){if(!a.channel||!a.data)return;this.info('Client ? calling listeners for ? with ?',this._0,a.channel,a.data);this._b.distributeMessage(a)},_G:function(){if(!this._p)return;this._p=null;this.info('Closed connection for ?',this._0)},_z:function(){this._G();var a=this;setTimeout(function(){a.connect()},this._9.interval)},_e:function(b,c,d){b.id=this._D.generate();if(c)this._o[b.id]=[c,d];this.pipeThroughExtensions('outgoing',b,function(a){if(!a)return;if(a.channel===Faye.Channel.HANDSHAKE)return this._f.send(a,this._9.timeout/1000);this._h.push(a);if(a.channel===Faye.Channel.CONNECT)this._r=a;this.addTimeout('publish',this.MAX_DELAY,this._H,this)},this)},_H:function(){this.removeTimeout('publish');if(this._h.length>1&&this._r)this._r.advice={timeout:0};this._r=null;this._f.send(this._h,this._9.timeout/1000);this._h=[]},_q: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.extend(Faye.Client.prototype,Faye.Timeouts);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.extend(Faye.Client.prototype,Faye.Extensible);Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this.debug('Created new ? transport for ?',this.connectionType,b);this._c=a;this._4=b},send:function(a,b){a=[].concat(a);this.debug('Client ? sending message to ?: ?',this._c._0,this._4,a);return this.request(a,b)},receive:function(a){this.debug('Client ? received from ?: ?',this._c._0,this._4,a);Faye.each(a,this._c.receiveMessage,this._c)},retry:function(a,b){var c=this;return function(){setTimeout(function(){c.request(a,2*b)},1000*b)}}}),{get:function(d,f){var g=d._4;if(f===undefined)f=this.supportedConnectionTypes();var i=null;Faye.each(this._s,function(a){var b=a[0],c=a[1];if(Faye.indexOf(f,b)<0)return;if(i)return;if(c.isUsable(g))i=c});if(!i)throw'Could not find a usable connection type for '+g;return new i(d,g)},register:function(a,b){this._s.push([a,b]);b.prototype.connectionType=a},_s:[],supportedConnectionTypes:function(){return Faye.map(this._s,function(a){return a[0]})}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.Event={_i:[],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._i.push({_j:a,_t:b,_n:c,_d:d,_A:f})},detach:function(a,b,c,d){var f=this._i.length,g;while(f--){g=this._i[f];if((a&&a!==g._j)||(b&&b!==g._t)||(c&&c!==g._n)||(d&&d!==g._d))continue;if(g._j.removeEventListener)g._j.removeEventListener(g._t,g._A,false);else g._j.detachEvent('on'+g._t,g._A);this._i.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 i=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};i('protocol',/^https?\:\/+/);i('hostname',/^[^\/\:]+/);i('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 j=d.split('?'),h=j.shift(),l=j.join('?'),n=l?l.split('&'):[],o=n.length,k={};while(o--){j=n[o].split('=');k[decodeURIComponent(j[0]||'')]=decodeURIComponent(j[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._k=a.toUpperCase();this._4=Faye.URI.parse(b,c);this._I=(typeof c==='string')?c:null;this._a=(typeof d==='function')?{success:d}:d;this._d=f||null;this._5=null},send:function(){if(this._u)return;var a=this._4.pathname,b=this._4.queryString();if(this._k==='GET')a+='?'+b;var c=(this._k==='POST')?(this._I||b):'';this._u=true;this._5=Faye.XHR.getXhrObject();this._5.open(this._k,a,true);if(this._k==='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._u=false;d._J();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()},_J:function(){var a=this._a;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._u},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,i=k,j,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;j=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){j[c]=q(c,h)||'null'}f=j.length===0?'[]':k?'[\n'+k+j.join(',\n'+k)+'\n'+i+']':'['+j.join(',')+']';k=i;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){j.push(r(d)+(k?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){j.push(r(d)+(k?': ':':')+f)}}}}f=j.length===0?'{}':k?'{\n'+k+j.join(',\n'+k)+'\n'+i+'}':'{'+j.join(',')+'}';k=i;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,i){var j;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 i.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,''))){j=eval('('+g+')');return typeof i==='function'?h({'':j},''):j}throw new SyntaxError('JSON.parse');}}}());Faye.WebSocketTransport=Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,request:function(b,c){this._l=this._l||{};Faye.each(b,function(a){this._l[a.id]=a},this);this.withSocket(function(a){a.send(Faye.toJSON(b))})},withSocket:function(a,b){this.callback(a,b);this.connect()},getSocketUrl:function(){return Faye.URI.parse(this._4).toURL().replace(/^http(s?):/ig,'ws$1:')},connect:function(){this._1=this._1||this.UNCONNECTED;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;this._g=new WebSocket(this.getSocketUrl());var d=this;this._g.onopen=function(){d._1=d.CONNECTED;d.setDeferredStatus('succeeded',d._g)};this._g.onmessage=function(b){var c=[].concat(JSON.parse(b.data));Faye.each(c,function(a){delete d._l[a.id]});d.receive(c)};this._g.onclose=function(){var a=(d._1===d.CONNECTED);d.setDeferredStatus('deferred');d._1=d.UNCONNECTED;d._g=null;if(a)d.resend();else d.connect()}},resend:function(){var c=Faye.map(this._l,function(a,b){return b});this.request(c)}});Faye.extend(Faye.WebSocketTransport.prototype,Faye.Deferrable);Faye.WebSocketTransport.isUsable=function(a){return!!Faye.ENV.WebSocket};Faye.Transport.register('websocket',Faye.WebSocketTransport);Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c){var d=this.retry(b,c);Faye.XHR.request('post',this._4,Faye.toJSON(b),{success:function(a){try{this.receive(JSON.parse(a.text()))}catch(e){d()}},failure:d},this)}});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){var d={message:Faye.toJSON(b)},f=document.getElementsByTagName('head')[0],g=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),j=Faye.URI.parse(this._4,d),h=this;var l=function(){if(!g.parentNode)return false;g.parentNode.removeChild(g);return true};Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}if(!l())return;h.receive(a)};setTimeout(function(){if(!Faye.ENV[i])return;l();h.request(b,2*c)},1000*c);j.params.jsonp=i;g.type='text/javascript';g.src=j.toURL();f.appendChild(g)}}),{_B:0,getCallbackName:function(){this._B+=1;return'__jsonp'+this._B+'__'}});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.5.4',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:['long-polling','callback-polling','websocket'],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);return Math.floor(Math.random()*d).toString(36)},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){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}},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(),i=b.getMinutes(),j=b.getSeconds();var h=function(a){return a<10?'0'+a:String(a)};return h(c)+'-'+h(d)+'-'+h(f)+' '+h(g)+':'+h(i)+':'+h(j)}});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._w={}},generate:function(){var a=Faye.random();while(this._w.hasOwnProperty(a))a=Faye.random();return this._w[a]=a}});Faye.Deferrable={callback:function(a,b){if(!a)return;if(this._D==='succeeded')return a.apply(b,this._x);this._a=this._a||[];this._a.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._D=c;this._x=b;if(c!=='succeeded')return;if(!this._a)return;Faye.each(this._a,function(a){a[0].apply(a[1],this._x)},this);this._a=[]}};Faye.Publisher={countSubscribers:function(a){if(!this._2||!this._2[a])return 0;return this._2[a].length},addSubscriber:function(a,b,c){this._2=this._2||{};var d=this._2[a]=this._2[a]||[];d.push([b,c])},removeSubscriber:function(a,b,c){if(!this._2||!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)}},publishEvent: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)})}};Faye.Timeouts={addTimeout:function(a,b,c,d){this._7=this._7||{};if(this._7.hasOwnProperty(a))return;var f=this;this._7[a]=setTimeout(function(){delete f._7[a];c.call(d)},1000*b)},removeTimeout:function(a){this._7=this._7||{};var b=this._7[a];if(!b)return;clearTimeout(b);delete this._7[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=null,g=a.shift().replace(/\?/g,function(){try{return Faye.toJSON(a.shift())}catch(e){return'[Object]'}});for(var i in Faye){if(f)continue;if(typeof Faye[i]!=='function')continue;if(this instanceof Faye[i])f=i}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._8=this._8||[];this._8.push(a);if(a.added)a.added()},removeExtension:function(a){if(!this._8)return;var b=this._8.length;while(b--){if(this._8[b]!==a)continue;this._8.splice(b,1);if(a.removed)a.removed()}},pipeThroughExtensions:function(c,d,f,g){if(!this._8)return f.call(g,d);var i=this._8.slice();var j=function(a){if(!a)return f.call(g,a);var b=i.shift();if(!b)return f.call(g,a);if(b[c])b[c](a,j);else j(a)};j(d)}};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',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,b){this._n=a;this._3=b;this._6={}},eachChild:function(c,d){Faye.each(this._6,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},remove:function(a){if(a){var b=this.traverse(a);if(b)b.remove()}else{if(!this._n)return;this._n.removeChild(this);this._n=this._3=undefined}},removeChild:function(c){this.eachChild(function(a,b){if(b===c)delete this._6[a]},this);if(Faye.size(this._6)===0&&this._3===undefined)this.remove()},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._6[a[0]];if(!c&&!b)return null;if(!c)c=this._6[a[0]]=new Faye.Channel.Tree(this);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._6,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._6,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._6['**'])g.push(this._6['**']._3);return g},subscribe:function(c,d,f){if(!d)return;Faye.each(c,function(a){var b=this.findOrCreate(a);b.addSubscriber('message',d,f)},this)},unsubscribe:function(a,b,c){var d=this.get(a);if(!d)return false;d.removeSubscriber('message',b,c);if(d.isUnused()){this.remove(a);return true}else{return false}},distributeMessage:function(b){var c=this.glob(b.channel);Faye.each(c,function(a){a.publishEvent('message',b.data)})}})});Faye.Subscription=Faye.Class({initialize:function(a,b,c,d){this._c=a;this._b=b;this._o=c;this._d=d;this._y=false},cancel:function(){if(this._y)return;this._c.unsubscribe(this._b,this._o,this._d);this._y=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',MAX_DELAY:0.001,INTERVAL:0.0,initialize:function(a,b){this.info('New client created for ?',a);this._4=a||this.DEFAULT_ENDPOINT;this._z=b||{};this._f=Faye.Transport.get(this,Faye.MANDATORY_CONNECTION_TYPES);this._1=this.UNCONNECTED;this._i=[];this._b=new Faye.Channel.Tree();this._E=new Faye.Namespace();this._p={};this._9={reconnect:this.RETRY,interval:1000*(this._z.interval||this.INTERVAL),timeout:1000*(this._z.timeout||this.CONNECTION_TIMEOUT)};if(Faye.Event)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._e({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:[this._f.connectionType]},function(a){if(a.successful){this._1=this.CONNECTED;this._0=a.clientId;this._f=Faye.Transport.get(this,a.supportedConnectionTypes);this.info('Handshake successful: ?',this._0);this.subscribe(this._b.getKeys());if(b)b.call(c)}else{this.info('Handshake unsuccessful');setTimeout(function(){d.handshake(b,c)},this._9.interval);this._1=this.UNCONNECTED}},this)},connect:function(a,b){if(this._9.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._q)return;this._q=true;this.info('Initiating connection for ?',this._0);this._e({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._f.connectionType},this._A,this)},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting ?',this._0);this._e({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for ?',this._0);this._b=new Faye.Channel.Tree()},subscribe:function(c,d,f){if(c instanceof Array)return Faye.each(c,function(channel){this.subscribe(channel,d,f)},this);this._r(c);var g=new Faye.Subscription(this,c,d,f);this.connect(function(){this.info('Client ? attempting to subscribe to ?',this._0,c);this._e({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},function(a){if(!a.successful)return;var b=[].concat(a.subscription);this.info('Subscription acknowledged for ? to ?',this._0,b);this._b.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);this._r(c);var g=this._b.unsubscribe(c,d,f);if(!g)return;this.connect(function(){this.info('Client ? attempting to unsubscribe from ?',this._0,c);this._e({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){this._r(a);this.connect(function(){this.info('Client ? queueing published message to ?: ?',this._0,a,b);this._e({channel:a,data:b,clientId:this._0})},this)},receiveMessage:function(c){this.pipeThroughExtensions('incoming',c,function(a){if(!a)return;if(a.advice)this._F(a.advice);var b=this._p[a.id];if(b){delete this._p[a.id];b[0].call(b[1],a)}this._G(a)},this)},_F:function(a){Faye.extend(this._9,a);if(this._9.reconnect===this.HANDSHAKE&&this._1!==this.DISCONNECTED){this._1=this.UNCONNECTED;this._0=null;this._A()}},_G:function(a){if(!a.channel||!a.data)return;this.info('Client ? calling listeners for ? with ?',this._0,a.channel,a.data);this._b.distributeMessage(a)},_H:function(){if(!this._q)return;this._q=null;this.info('Closed connection for ?',this._0)},_A:function(){this._H();var a=this;setTimeout(function(){a.connect()},this._9.interval)},_e:function(b,c,d){b.id=this._E.generate();if(c)this._p[b.id]=[c,d];this.pipeThroughExtensions('outgoing',b,function(a){if(!a)return;if(a.channel===Faye.Channel.HANDSHAKE)return this._f.send(a,this._9.timeout/1000);this._i.push(a);if(a.channel===Faye.Channel.CONNECT)this._s=a;this.addTimeout('publish',this.MAX_DELAY,this._I,this)},this)},_I:function(){this.removeTimeout('publish');if(this._i.length>1&&this._s)this._s.advice={timeout:0};this._s=null;this._f.send(this._i,this._9.timeout/1000);this._i=[]},_r: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.extend(Faye.Client.prototype,Faye.Timeouts);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.extend(Faye.Client.prototype,Faye.Extensible);Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this.debug('Created new ? transport for ?',this.connectionType,b);this._c=a;this._4=b},send:function(a,b){a=[].concat(a);this.debug('Client ? sending message to ?: ?',this._c._0,this._4,a);return this.request(a,b)},receive:function(a){this.debug('Client ? received from ?: ?',this._c._0,this._4,a);Faye.each(a,this._c.receiveMessage,this._c)},retry:function(a,b){var c=this;return function(){setTimeout(function(){c.request(a,2*b)},1000*b)}}}),{get:function(d,f){var g=d._4;if(f===undefined)f=this.supportedConnectionTypes();var i=null;Faye.each(this._t,function(a){var b=a[0],c=a[1];if(Faye.indexOf(f,b)<0)return;if(i)return;if(c.isUsable(g))i=c});if(!i)throw'Could not find a usable connection type for '+g;return new i(d,g)},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.Event={_j:[],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._j.push({_k:a,_u:b,_o:c,_d:d,_B:f})},detach:function(a,b,c,d){var f=this._j.length,g;while(f--){g=this._j[f];if((a&&a!==g._k)||(b&&b!==g._u)||(c&&c!==g._o)||(d&&d!==g._d))continue;if(g._k.removeEventListener)g._k.removeEventListener(g._u,g._B,false);else g._k.detachEvent('on'+g._u,g._B);this._j.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 i=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};i('protocol',/^https?\:\/+/);i('hostname',/^[^\/\:]+/);i('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 j=d.split('?'),h=j.shift(),l=j.join('?'),n=l?l.split('&'):[],o=n.length,k={};while(o--){j=n[o].split('=');k[decodeURIComponent(j[0]||'')]=decodeURIComponent(j[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._l=a.toUpperCase();this._4=Faye.URI.parse(b,c);this._J=(typeof c==='string')?c:null;this._a=(typeof d==='function')?{success:d}:d;this._d=f||null;this._5=null},send:function(){if(this._v)return;var a=this._4.pathname,b=this._4.queryString();if(this._l==='GET')a+='?'+b;var c=(this._l==='POST')?(this._J||b):'';this._v=true;this._5=Faye.XHR.getXhrObject();this._5.open(this._l,a,true);if(this._l==='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._v=false;d._K();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()},_K:function(){var a=this._a;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._v},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,i=k,j,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;j=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){j[c]=q(c,h)||'null'}f=j.length===0?'[]':k?'[\n'+k+j.join(',\n'+k)+'\n'+i+']':'['+j.join(',')+']';k=i;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){j.push(r(d)+(k?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){j.push(r(d)+(k?': ':':')+f)}}}}f=j.length===0?'{}':k?'{\n'+k+j.join(',\n'+k)+'\n'+i+'}':'{'+j.join(',')+'}';k=i;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,i){var j;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 i.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,''))){j=eval('('+g+')');return typeof i==='function'?h({'':j},''):j}throw new SyntaxError('JSON.parse');}}}());Faye.WebSocketTransport=Faye.Class(Faye.Transport,{UNCONNECTED:1,CONNECTING:2,CONNECTED:3,request:function(b,c){this._g=this._g||c;this._m=this._m||{};Faye.each(b,function(a){this._m[a.id]=a},this);this.withSocket(function(a){a.send(Faye.toJSON(b))})},withSocket:function(a,b){this.callback(a,b);this.connect()},getSocketUrl:function(){return Faye.URI.parse(this._4).toURL().replace(/^http(s?):/ig,'ws$1:')},connect:function(){this._1=this._1||this.UNCONNECTED;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;this._h=new WebSocket(this.getSocketUrl());var d=this;this._h.onopen=function(){delete d._g;d._1=d.CONNECTED;d.setDeferredStatus('succeeded',d._h)};this._h.onmessage=function(b){var c=[].concat(JSON.parse(b.data));Faye.each(c,function(a){delete d._m[a.id]});d.receive(c)};this._h.onclose=function(){var a=(d._1===d.CONNECTED);d.setDeferredStatus('deferred');d._1=d.UNCONNECTED;delete d._h;if(a)return d.resend();setTimeout(function(){d.connect()},1000*d._g);d._g=d._g*2}},resend:function(){var c=Faye.map(this._m,function(a,b){return b});this.request(c)}});Faye.extend(Faye.WebSocketTransport.prototype,Faye.Deferrable);Faye.WebSocketTransport.isUsable=function(a){return!!Faye.ENV.WebSocket};Faye.Transport.register('websocket',Faye.WebSocketTransport);Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c){var d=this.retry(b,c);Faye.XHR.request('post',this._4,Faye.toJSON(b),{success:function(a){try{this.receive(JSON.parse(a.text()))}catch(e){d()}},failure:d},this)}});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){var d={message:Faye.toJSON(b)},f=document.getElementsByTagName('head')[0],g=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),j=Faye.URI.parse(this._4,d),h=this;var l=function(){if(!g.parentNode)return false;g.parentNode.removeChild(g);return true};Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}if(!l())return;h.receive(a)};setTimeout(function(){if(!Faye.ENV[i])return;l();h.request(b,2*c)},1000*c);j.params.jsonp=i;g.type='text/javascript';g.src=j.toURL();f.appendChild(g)}}),{_C:0,getCallbackName:function(){this._C+=1;return'__jsonp'+this._C+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
data/lib/faye.rb CHANGED
@@ -5,7 +5,7 @@ require 'eventmachine'
5
5
  require 'json'
6
6
 
7
7
  module Faye
8
- VERSION = '0.5.3'
8
+ VERSION = '0.5.4'
9
9
 
10
10
  ROOT = File.expand_path(File.dirname(__FILE__))
11
11
 
@@ -24,6 +24,9 @@ module Faye
24
24
  @endpoint = @options[:mount] || DEFAULT_ENDPOINT
25
25
  @endpoint_re = Regexp.new('^' + @endpoint + '(/[^/]*)*(\\.js)?$')
26
26
  @server = Server.new(@options)
27
+
28
+ return unless extensions = @options[:extensions]
29
+ [*extensions].each { |extension| add_extension(extension) }
27
30
  end
28
31
 
29
32
  def add_extension(extension)
@@ -169,6 +169,7 @@ module Faye
169
169
  end
170
170
 
171
171
  validate_channel(channels)
172
+ subscription = Subscription.new(self, channels, block)
172
173
 
173
174
  connect {
174
175
  info('Client ? attempting to subscribe to ?', @client_id, channels)
@@ -184,10 +185,12 @@ module Faye
184
185
  channels = [response['subscription']].flatten
185
186
  info('Subscription acknowledged for ? to ?', @client_id, channels)
186
187
  @channels.subscribe(channels, block)
188
+
189
+ subscription.set_deferred_status(:succeeded)
187
190
  end
188
191
  end
189
192
  }
190
- Subscription.new(self, channels, block)
193
+ subscription
191
194
  end
192
195
 
193
196
  # Request Response
@@ -1,5 +1,6 @@
1
1
  module Faye
2
2
  class Subscription
3
+ include EventMachine::Deferrable
3
4
 
4
5
  def initialize(client, channels, callback)
5
6
  @client = client
@@ -57,9 +57,17 @@ class Thin::Request
57
57
  def websocket?
58
58
  @env['HTTP_CONNECTION'] == 'Upgrade' && @env['HTTP_UPGRADE'] == 'WebSocket'
59
59
  end
60
+
61
+ def secure_websocket?
62
+ if @env.has_key?('HTTP_X_FORWARDED_PROTO')
63
+ @env['HTTP_X_FORWARDED_PROTO'] == 'https'
64
+ else
65
+ @env['HTTP_ORIGIN'] =~ /^https:/i
66
+ end
67
+ end
60
68
 
61
69
  def websocket_url
62
- scheme = (@env['HTTP_ORIGIN'] =~ /^https:/i) ? 'wss:' : 'ws:'
70
+ scheme = secure_websocket? ? 'wss:' : 'ws:'
63
71
  @env['websocket.url'] = "#{ scheme }//#{ @env['HTTP_HOST'] }#{ @env['REQUEST_PATH'] }"
64
72
  end
65
73
 
data/test/scenario.rb CHANGED
@@ -135,7 +135,7 @@ module Scenario
135
135
  box[channel] << message
136
136
  end
137
137
 
138
- EM.add_timer(0.5, &block)
138
+ @last_sub.callback(&block)
139
139
  end
140
140
 
141
141
  def cancel_last_subscription(&block)
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faye
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 3
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 5
8
- - 3
9
- version: 0.5.3
9
+ - 4
10
+ version: 0.5.4
10
11
  platform: ruby
11
12
  authors:
12
13
  - James Coglan
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-10-21 00:00:00 +01:00
18
+ date: 2010-12-19 00:00:00 +00:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
@@ -25,6 +26,7 @@ dependencies:
25
26
  requirements:
26
27
  - - ">="
27
28
  - !ruby/object:Gem::Version
29
+ hash: 19
28
30
  segments:
29
31
  - 0
30
32
  - 12
@@ -39,6 +41,7 @@ dependencies:
39
41
  requirements:
40
42
  - - ">="
41
43
  - !ruby/object:Gem::Version
44
+ hash: 15
42
45
  segments:
43
46
  - 0
44
47
  - 2
@@ -53,6 +56,7 @@ dependencies:
53
56
  requirements:
54
57
  - - ">="
55
58
  - !ruby/object:Gem::Version
59
+ hash: 15
56
60
  segments:
57
61
  - 1
58
62
  - 0
@@ -67,6 +71,7 @@ dependencies:
67
71
  requirements:
68
72
  - - ">="
69
73
  - !ruby/object:Gem::Version
74
+ hash: 11
70
75
  segments:
71
76
  - 1
72
77
  - 2
@@ -81,6 +86,7 @@ dependencies:
81
86
  requirements:
82
87
  - - ">="
83
88
  - !ruby/object:Gem::Version
89
+ hash: 15
84
90
  segments:
85
91
  - 1
86
92
  - 0
@@ -88,35 +94,21 @@ dependencies:
88
94
  type: :runtime
89
95
  version_requirements: *id005
90
96
  - !ruby/object:Gem::Dependency
91
- name: rubyforge
97
+ name: hoe
92
98
  prerelease: false
93
99
  requirement: &id006 !ruby/object:Gem::Requirement
94
100
  none: false
95
101
  requirements:
96
102
  - - ">="
97
103
  - !ruby/object:Gem::Version
104
+ hash: 47
98
105
  segments:
99
106
  - 2
107
+ - 8
100
108
  - 0
101
- - 4
102
- version: 2.0.4
109
+ version: 2.8.0
103
110
  type: :development
104
111
  version_requirements: *id006
105
- - !ruby/object:Gem::Dependency
106
- name: hoe
107
- prerelease: false
108
- requirement: &id007 !ruby/object:Gem::Requirement
109
- none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- segments:
114
- - 2
115
- - 6
116
- - 2
117
- version: 2.6.2
118
- type: :development
119
- version_requirements: *id007
120
112
  description: Simple pub/sub messaging for the web
121
113
  email:
122
114
  - jcoglan@googlemail.com
@@ -171,6 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
171
163
  requirements:
172
164
  - - ">="
173
165
  - !ruby/object:Gem::Version
166
+ hash: 3
174
167
  segments:
175
168
  - 0
176
169
  version: "0"
@@ -179,6 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
179
172
  requirements:
180
173
  - - ">="
181
174
  - !ruby/object:Gem::Version
175
+ hash: 3
182
176
  segments:
183
177
  - 0
184
178
  version: "0"