faye 0.1.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of faye might be problematic. Click here for more details.

@@ -0,0 +1,41 @@
1
+ = Soapbox -- a Twitter-style chat app
2
+
3
+ Soapbox is a chat app written using Faye and jQuery, with functionality
4
+ modelled on that of Twitter. You can pick a username, type in some users
5
+ to follow, and enter messages. You receive messages from anyone you're
6
+ following, and any messages that mention you using the <tt>@username</tt>
7
+ syntax.
8
+
9
+
10
+ == Running the demo
11
+
12
+ There are two backends that handle message routing; one for Node.js
13
+ and one for Rack. To run the Node.js version:
14
+
15
+ node examples/node/app.js
16
+
17
+ To run the Rack version you need a few gems first:
18
+
19
+ sudo gem install eventmachine rack json sinatra
20
+ rackup -s mongrel examples/rack/config.ru
21
+
22
+ You can also use Thin to run the app as long as <tt>Rack::Lint</tt>
23
+ is not being used (it complains about the status codes Thin uses
24
+ for async responses).
25
+
26
+ rackup -s thin -E production examples/rack/config.ru
27
+
28
+ Note that Faye does not depend on Sinatra; the demo just uses it to
29
+ provide a concrete app behind the Faye middleware.
30
+
31
+
32
+ == Source code
33
+
34
+ There is no server-side logic for this app; the Faye server simply
35
+ handles message routing between clients and all subscriptions are set
36
+ up on the client side. Since this is a simple demo of client-side
37
+ messaging, your username and followees are not persisted across page
38
+ reloads. The source code for the client is at:
39
+
40
+ shared/public/soapbox.js
41
+
@@ -0,0 +1,26 @@
1
+ var posix = require('posix'),
2
+ path = require('path'),
3
+ sys = require('sys'),
4
+ http = require('http')
5
+ faye = require('./faye');
6
+
7
+ var PUBLIC_DIR = path.dirname(__filename) + '/../shared/public',
8
+ comet = new faye.NodeAdapter({mount: '/comet', timeout: 45}),
9
+
10
+ port = process.ARGV[2] || '8000';
11
+
12
+ sys.puts('Listening on ' + port);
13
+
14
+ http.createServer(function(request, response) {
15
+ sys.puts(request.method + ' ' + request.url);
16
+ if (comet.call(request, response)) return;
17
+
18
+ var path = (request.url === '/') ? '/index.html' : request.url;
19
+
20
+ posix.cat(PUBLIC_DIR + path).addCallback(function(content) {
21
+ response.sendHeader(200, {'Content-Type': 'text/html'});
22
+ response.sendBody(content);
23
+ response.finish();
24
+ });
25
+ }).listen(Number(port));
26
+
@@ -0,0 +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)&&a[d]!==b[d]){if(!a.hasOwnProperty(d)||c!==false)a[d]=b[d]}}return a};Faye.extend(Faye,{BAYEUX_VERSION:'1.0',VERSION:'0.2.2',JSONP_CALLBACK:'jsonpcallback',ID_LENGTH:128,CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},size:function(a){var b=0;this.each(a,function(){b+=1});return b},random:function(){var a=Math.pow(2,this.ID_LENGTH);return(Math.random()*a).toString(16).replace(/0*$/,'')},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Observable={on:function(a,b,c){this._1=this._1||{};var d=this._1[a]=this._1[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._1||!this._1[a])return;if(!b){delete this._1[a];return}var d=this._1[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._1||!this._1[c])return;Faye.each(this._1[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this._A=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._3=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._3!==undefined)d.call(f,c,this._3)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._3:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._3=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._3===undefined)?[]:[this._3];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,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});g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._3);return g}})});Faye.Event={_a:[],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._a.push({_b:a,_h:b,_s:c,_c:d,_m:f})},detach:function(a,b,c,d){var f=this._a.length,g;while(f--){g=this._a[f];if((a&&a!==g._b)||(b&&b!==g._h)||(c&&c!==g._s)||(d&&d!==g._c))continue;if(g._b.removeEventListener)g._b.removeEventListener(g._h,g._m,false);else g._b.detachEvent('on'+g._h,g._m);this._a.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._d=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._t=(typeof d==='function')?{success:d}:d;this._c=f||null;this._2=null},send:function(){if(this._i)return;var a=this._6.pathname,b=this._6.queryString();if(this._d==='GET')a+='?'+b;var c=this._d==='POST'?b:'';this._i=true;this._2=Faye.XHR.getXhrObject();this._2.open(this._d,a,true);if(this._d==='POST')this._2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._2.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._i=false;d._u();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._2.send(c)},abort:function(){this._2.abort()},_u:function(){var a=this._t;if(!a)return;return this.success()?a.success&&a.success.call(this._c,this):a.failure&&a.failure.call(this._c,this)},waiting:function(){return!!this._i},complete:function(){return this._2&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._2.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._2.responseText},status:function(){if(!this.complete())return null;return this._2.status}})};Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._n=a;this._6=b},send:function(c,d,f){c={message:JSON.stringify(c)};return this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){d.call(f,a);if(a.advice)this._n._v(a.advice);if(a.data&&a.channel)this._n._w(a)},this)},this)}}),{get:function(a,b){var c=a._6;if(b===undefined)b=this.supportedConnectionTypes();var d=Faye.URI.parse(c).isLocal()?['long-polling','callback-polling']:['callback-polling'];var f=Faye.commonElement(d,b);if(!f)throw'Could not find a usable connection type for '+c;var g=this._j[f];return new g(a,c)},register:function(a,b){this._j[a]=b;b.prototype.connectionType=a},_j:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._j,function(a,b){c.push(a)});return c}});Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._6,b,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f=document.getElementsByTagName('head')[0],g=document.createElement('script'),k=Faye.JSONPTransport.getCallbackName(),i=Faye.URI.parse(this._6,b);Faye.ENV[k]=function(a){Faye.ENV[k]=undefined;try{delete Faye.ENV[k]}catch(e){}f.removeChild(g);if(c)c.call(d,a)};i.params.jsonp=k;g.type='text/javascript';g.src=i.toURL();f.appendChild(g)}}),{_o:0,getCallbackName:function(){this._o+=1;return'__jsonp'+this._o+'__'}});Faye.Transport.register('callback-polling',Faye.JSONPTransport);Faye.Client=Faye.Class({_e:{},_x:{},_8:{},_y:{},_p:'handshake',_z:'retry',_q:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._0=this._e;this._k=[];this._f=new Faye.Channel.Tree();this._7={reconnect:this._z,interval:this.INTERVAL};Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this._q)return;if(this._0!==this._e)return;this._0=this._x;var d=this,f=this.generateId();this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes(),id:f},function(a){if(a.id!==f)return;if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._0=this._e}this._0=this._8;this._9=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this._q)return;if(this._7.reconnect===this._p||this._0===this._e)return this.handshake(function(){this.connect(b,c)},this);if(this._0!==this._8)return;if(this._g)return;this._g=this.generateId();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._9,connectionType:this._4.connectionType,id:this._g},function(a){if(a.id!==this._g)return;delete this._g;if(a.successful)this.connect();else setTimeout(function(){d.connect()},this._7.interval)},this);if(b)b.call(c)},disconnect:function(){if(this._0!==this._8)return;this._0=this._y;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._9});this._f=new Faye.Channel.Tree()},subscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,[d,f])},this)},this)},unsubscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,null)},this)},this)},publish:function(a,b){if(this._0!==this._8)return;this._l([a]);this.enqueue({channel:a,data:b,clientId:this._9});if(this._r)return;var c=this;this._r=setTimeout(function(){delete c._r;c.flush()},this.MAX_DELAY*1000)},generateId:function(a){a=a||32;return Math.floor(Math.pow(2,a)*Math.random()).toString(16)},enqueue:function(a){this._k.push(a)},flush:function(){this._4.send(this._k);this._k=[]},_l:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})},_v:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this._p)this._9=null},_w:function(b){var c=this._f.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})}});if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());
@@ -0,0 +1,868 @@
1
+ if (!this.Faye) Faye = {};
2
+
3
+ Faye.extend = function(dest, source, overwrite) {
4
+ if (!source) return dest;
5
+ for (var key in source) {
6
+ if (source.hasOwnProperty(key) && dest[key] !== source[key]) {
7
+ if (!dest.hasOwnProperty(key) || overwrite !== false)
8
+ dest[key] = source[key];
9
+ }
10
+ }
11
+ return dest;
12
+ };
13
+
14
+ Faye.extend(Faye, {
15
+ BAYEUX_VERSION: '1.0',
16
+ VERSION: '0.2.2',
17
+ JSONP_CALLBACK: 'jsonpcallback',
18
+ ID_LENGTH: 128,
19
+ CONNECTION_TYPES: ["long-polling", "callback-polling"],
20
+
21
+ ENV: this,
22
+
23
+ Grammar: {
24
+
25
+ LOWALPHA: /^[a-z]$/,
26
+
27
+ UPALPHA: /^[A-Z]$/,
28
+
29
+ ALPHA: /^([a-z]|[A-Z])$/,
30
+
31
+ DIGIT: /^[0-9]$/,
32
+
33
+ ALPHANUM: /^(([a-z]|[A-Z])|[0-9])$/,
34
+
35
+ MARK: /^(\-|\_|\!|\~|\(|\)|\$|\@)$/,
36
+
37
+ STRING: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
38
+
39
+ TOKEN: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
40
+
41
+ INTEGER: /^([0-9])+$/,
42
+
43
+ CHANNEL_SEGMENT: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
44
+
45
+ CHANNEL_SEGMENTS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
46
+
47
+ CHANNEL_NAME: /^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
48
+
49
+ WILD_CARD: /^\*{1,2}$/,
50
+
51
+ CHANNEL_PATTERN: /^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,
52
+
53
+ VERSION_ELEMENT: /^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,
54
+
55
+ VERSION: /^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,
56
+
57
+ CLIENT_ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
58
+
59
+ ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
60
+
61
+ ERROR_MESSAGE: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
62
+
63
+ ERROR_ARGS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,
64
+
65
+ ERROR_CODE: /^[0-9][0-9][0-9]$/,
66
+
67
+ 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])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/
68
+
69
+ },
70
+
71
+ commonElement: function(lista, listb) {
72
+ for (var i = 0, n = lista.length; i < n; i++) {
73
+ if (this.indexOf(listb, lista[i]) !== -1)
74
+ return lista[i];
75
+ }
76
+ return null;
77
+ },
78
+
79
+ indexOf: function(list, needle) {
80
+ for (var i = 0, n = list.length; i < n; i++) {
81
+ if (list[i] === needle) return i;
82
+ }
83
+ return -1;
84
+ },
85
+
86
+ each: function(object, callback, scope) {
87
+ if (object instanceof Array) {
88
+ for (var i = 0, n = object.length; i < n; i++) {
89
+ if (object[i] !== undefined)
90
+ callback.call(scope || null, object[i], i);
91
+ }
92
+ } else {
93
+ for (var key in object) {
94
+ if (object.hasOwnProperty(key))
95
+ callback.call(scope || null, key, object[key]);
96
+ }
97
+ }
98
+ },
99
+
100
+ size: function(object) {
101
+ var size = 0;
102
+ this.each(object, function() { size += 1 });
103
+ return size;
104
+ },
105
+
106
+ random: function() {
107
+ var field = Math.pow(2, this.ID_LENGTH);
108
+ return (Math.random() * field).toString(16).replace(/0*$/, '');
109
+ },
110
+
111
+ enumEqual: function(actual, expected) {
112
+ if (expected instanceof Array) {
113
+ if (!(actual instanceof Array)) return false;
114
+ var i = actual.length;
115
+ if (i !== expected.length) return false;
116
+ while (i--) {
117
+ if (actual[i] !== expected[i]) return false;
118
+ }
119
+ return true;
120
+ } else {
121
+ if (!(actual instanceof Object)) return false;
122
+ if (this.size(expected) !== this.size(actual)) return false;
123
+ var result = true;
124
+ this.each(actual, function(key, value) {
125
+ result = result && (expected[key] === value);
126
+ });
127
+ return result;
128
+ }
129
+ }
130
+ });
131
+
132
+
133
+ Faye.Class = function(parent, methods) {
134
+ if (typeof parent !== 'function') {
135
+ methods = parent;
136
+ parent = Object;
137
+ }
138
+
139
+ var klass = function() {
140
+ if (!this.initialize) return this;
141
+ return this.initialize.apply(this, arguments) || this;
142
+ };
143
+
144
+ var bridge = function() {};
145
+ bridge.prototype = parent.prototype;
146
+
147
+ klass.prototype = new bridge();
148
+ Faye.extend(klass.prototype, methods);
149
+
150
+ return klass;
151
+ };
152
+
153
+
154
+ Faye.Observable = {
155
+ on: function(eventType, block, scope) {
156
+ this._observers = this._observers || {};
157
+ var list = this._observers[eventType] = this._observers[eventType] || [];
158
+ list.push([block, scope]);
159
+ },
160
+
161
+ stopObserving: function(eventType, block, scope) {
162
+ if (!this._observers || !this._observers[eventType]) return;
163
+
164
+ if (!block) {
165
+ delete this._observers[eventType];
166
+ return;
167
+ }
168
+ var list = this._observers[eventType],
169
+ i = list.length;
170
+
171
+ while (i--) {
172
+ if (block && list[i][0] !== block) continue;
173
+ if (scope && list[i][1] !== scope) continue;
174
+ list.splice(i,1);
175
+ }
176
+ },
177
+
178
+ fire: function() {
179
+ var args = Array.prototype.slice.call(arguments),
180
+ eventType = args.shift();
181
+
182
+ if (!this._observers || !this._observers[eventType]) return;
183
+
184
+ Faye.each(this._observers[eventType], function(listener) {
185
+ listener[0].apply(listener[1], args.slice());
186
+ });
187
+ }
188
+ };
189
+
190
+
191
+ Faye.Channel = Faye.Class({
192
+ initialize: function(name) {
193
+ this.__id = this._name = name;
194
+ },
195
+
196
+ push: function(message) {
197
+ this.fire('message', message);
198
+ }
199
+ });
200
+
201
+ Faye.extend(Faye.Channel.prototype, Faye.Observable);
202
+
203
+ Faye.extend(Faye.Channel, {
204
+ HANDSHAKE: '/meta/handshake',
205
+ CONNECT: '/meta/connect',
206
+ SUBSCRIBE: '/meta/subscribe',
207
+ UNSUBSCRIBE: '/meta/unsubscribe',
208
+ DISCONNECT: '/meta/disconnect',
209
+
210
+ META: 'meta',
211
+ SERVICE: 'service',
212
+
213
+ isValid: function(name) {
214
+ return Faye.Grammar.CHANNEL_NAME.test(name) ||
215
+ Faye.Grammar.CHANNEL_PATTERN.test(name);
216
+ },
217
+
218
+ parse: function(name) {
219
+ if (!this.isValid(name)) return null;
220
+ return name.split('/').slice(1);
221
+ },
222
+
223
+ isMeta: function(name) {
224
+ var segments = this.parse(name);
225
+ return segments ? (segments[0] === this.META) : null;
226
+ },
227
+
228
+ isService: function(name) {
229
+ var segments = this.parse(name);
230
+ return segments ? (segments[0] === this.SERVICE) : null;
231
+ },
232
+
233
+ isSubscribable: function(name) {
234
+ if (!this.isValid(name)) return null;
235
+ return !this.isMeta(name) && !this.isService(name);
236
+ },
237
+
238
+ Tree: Faye.Class({
239
+ initialize: function(value) {
240
+ this._value = value;
241
+ this._children = {};
242
+ },
243
+
244
+ eachChild: function(block, context) {
245
+ Faye.each(this._children, function(key, subtree) {
246
+ block.call(context, key, subtree);
247
+ });
248
+ },
249
+
250
+ each: function(prefix, block, context) {
251
+ this.eachChild(function(path, subtree) {
252
+ path = prefix.concat(path);
253
+ subtree.each(path, block, context);
254
+ });
255
+ if (this._value !== undefined) block.call(context, prefix, this._value);
256
+ },
257
+
258
+ map: function(block, context) {
259
+ var result = [];
260
+ this.each([], function(path, value) {
261
+ result.push(block.call(context, path, value));
262
+ });
263
+ return result;
264
+ },
265
+
266
+ get: function(name) {
267
+ var tree = this.traverse(name);
268
+ return tree ? tree._value : null;
269
+ },
270
+
271
+ set: function(name, value) {
272
+ var subtree = this.traverse(name, true);
273
+ if (subtree) subtree._value = value;
274
+ },
275
+
276
+ traverse: function(path, createIfAbsent) {
277
+ if (typeof path === 'string') path = Faye.Channel.parse(path);
278
+
279
+ if (path === null) return null;
280
+ if (path.length === 0) return this;
281
+
282
+ var subtree = this._children[path[0]];
283
+ if (!subtree && !createIfAbsent) return null;
284
+ if (!subtree) subtree = this._children[path[0]] = new Faye.Channel.Tree();
285
+
286
+ return subtree.traverse(path.slice(1), createIfAbsent);
287
+ },
288
+
289
+ findOrCreate: function(channel) {
290
+ var existing = this.get(channel);
291
+ if (existing) return existing;
292
+ existing = new Faye.Channel(channel);
293
+ this.set(channel, existing);
294
+ return existing;
295
+ },
296
+
297
+ glob: function(path) {
298
+ if (typeof path === 'string') path = Faye.Channel.parse(path);
299
+
300
+ if (path === null) return [];
301
+ if (path.length === 0) return (this._value === undefined) ? [] : [this._value];
302
+
303
+ var list = [];
304
+
305
+ if (Faye.enumEqual(path, ['*'])) {
306
+ Faye.each(this._children, function(key, subtree) {
307
+ if (subtree._value !== undefined) list.push(subtree._value);
308
+ });
309
+ return list;
310
+ }
311
+
312
+ if (Faye.enumEqual(path, ['**'])) {
313
+ list = this.map(function(key, value) { return value });
314
+ list.pop();
315
+ return list;
316
+ }
317
+
318
+ Faye.each(this._children, function(key, subtree) {
319
+ if (key !== path[0] && key !== '*') return;
320
+ var sublist = subtree.glob(path.slice(1));
321
+ Faye.each(sublist, function(channel) { list.push(channel) });
322
+ });
323
+
324
+ if (this._children['**']) list.push(this._children['**']._value);
325
+ return list;
326
+ }
327
+
328
+ /**
329
+ Tests
330
+
331
+ glob = new Faye.Channel.Tree();
332
+ list = '/foo/bar /foo/boo /foo /foobar /foo/bar/boo /foobar/boo /foo/* /foo/**'.split(' ');
333
+
334
+ Faye.each(list, function(c, i) {
335
+ glob.set(c, i + 1);
336
+ });
337
+
338
+ console.log(glob.glob('/foo/*').sort()); // 1,2,7,8
339
+ console.log(glob.glob('/foo/bar').sort()); // 1,7,8
340
+ console.log(glob.glob('/foo/**').sort()); // 1,2,5,7,8
341
+ console.log(glob.glob('/foo/bar/boo').sort()); // 5,8
342
+ **/
343
+ })
344
+ });
345
+
346
+
347
+ Faye.Set = Faye.Class({
348
+ initialize: function() {
349
+ this._index = {};
350
+ },
351
+
352
+ add: function(item) {
353
+ var key = (item.__id !== undefined) ? item.__id : item;
354
+ if (this._index.hasOwnProperty(key)) return false;
355
+ this._index[key] = item;
356
+ return true;
357
+ },
358
+
359
+ forEach: function(block, scope) {
360
+ for (var key in this._index) {
361
+ if (this._index.hasOwnProperty(key))
362
+ block.call(scope, this._index[key]);
363
+ }
364
+ },
365
+
366
+ isEmpty: function() {
367
+ for (var key in this._index) {
368
+ if (this._index.hasOwnProperty(key)) return false;
369
+ }
370
+ return true;
371
+ },
372
+
373
+ member: function(item) {
374
+ for (var key in this._index) {
375
+ if (this._index[key] === item) return true;
376
+ }
377
+ return false;
378
+ },
379
+
380
+ remove: function(item) {
381
+ var key = (item.__id !== undefined) ? item.__id : item;
382
+ delete this._index[key];
383
+ },
384
+
385
+ toArray: function() {
386
+ var array = [];
387
+ this.forEach(function(item) { array.push(item) });
388
+ return array;
389
+ }
390
+ });
391
+
392
+
393
+ Faye.Server = Faye.Class({
394
+ initialize: function(options) {
395
+ this._options = options || {};
396
+ this._channels = new Faye.Channel.Tree();
397
+ this._clients = {};
398
+ },
399
+
400
+ clientIds: function() {
401
+ var ids = [];
402
+ Faye.each(this._clients, function(key, value) { ids.push(key) });
403
+ return ids;
404
+ },
405
+
406
+ process: function(messages, local, callback) {
407
+ messages = (messages instanceof Array) ? messages : [messages];
408
+ var processed = 0, responses = [];
409
+
410
+ Faye.each(messages, function(message) {
411
+ this._handle(message, local, function(reply) {
412
+ responses = responses.concat(reply);
413
+ processed += 1;
414
+ if (processed === messages.length) callback(responses);
415
+ });
416
+ }, this);
417
+ },
418
+
419
+ flushConnection: function(messages) {
420
+ messages = (messages instanceof Array) ? messages : [messages];
421
+ Faye.each(messages, function(message) {
422
+ var client = this._clients[message.clientId];
423
+ if (client) client.flush();
424
+ }, this);
425
+ },
426
+
427
+ _generateId: function() {
428
+ var id = Faye.random();
429
+ while (this._clients.hasOwnProperty(id)) id = Faye.random();
430
+ return this._connection(id).id;
431
+ },
432
+
433
+ _connection: function(id) {
434
+ if (this._clients.hasOwnProperty(id)) return this._clients[id];
435
+ var client = new Faye.Connection(id, this._options);
436
+ client.on('stale', this._destroyClient, this);
437
+ return this._clients[id] = client;
438
+ },
439
+
440
+ _destroyClient: function(client) {
441
+ client.disconnect();
442
+ client.stopObserving('stale', this._destroyClient, this);
443
+ delete this._clients[client.id];
444
+ },
445
+
446
+ _handle: function(message, local, callback) {
447
+ var clientId = message.clientId,
448
+ channel = message.channel,
449
+ response;
450
+
451
+ if (Faye.Channel.isMeta(channel)) {
452
+ response = this[Faye.Channel.parse(channel)[1]](message, local);
453
+
454
+ clientId = clientId || response.clientId;
455
+ response.advice = response.advice || {};
456
+ Faye.extend(response.advice, {
457
+ reconnect: this._clients.hasOwnProperty(clientId) ? 'retry' : 'handshake',
458
+ interval: Faye.Connection.INTERVAL * 1000
459
+ }, false);
460
+
461
+ response.id = message.id;
462
+
463
+ if (response.channel !== Faye.Channel.CONNECT ||
464
+ response.successful !== true)
465
+ return callback(response);
466
+
467
+ return this._connection(response.clientId).connect(function(events) {
468
+ Faye.each(events, function(e) { delete e.__id });
469
+ callback([response].concat(events));
470
+ });
471
+ }
472
+
473
+ if (!message.clientId || Faye.Channel.isService(channel))
474
+ return callback([]);
475
+
476
+ message.__id = Faye.random();
477
+ Faye.each(this._channels.glob(channel), function(c) { c.push(message) });
478
+
479
+ callback( { channel: channel,
480
+ successful: true,
481
+ id: message.id } );
482
+ },
483
+
484
+ handshake: function(message, local) {
485
+ var response = { channel: Faye.Channel.HANDSHAKE,
486
+ version: Faye.BAYEUX_VERSION,
487
+ supportedConnectionTypes: Faye.CONNECTION_TYPES,
488
+ id: message.id };
489
+
490
+ if (!message.version)
491
+ response.error = Faye.Error.parameterMissing('version');
492
+
493
+ var clientConns = message.supportedConnectionTypes,
494
+ commonConns;
495
+
496
+ if (clientConns) {
497
+ commonConns = clientConns.filter(function(conn) {
498
+ return Faye.CONNECTION_TYPES.indexOf(conn) !== -1;
499
+ });
500
+ if (commonConns.length === 0)
501
+ response.error = Faye.Error.conntypeMismatch(clientConns);
502
+ } else {
503
+ response.error = Faye.Error.parameterMissing('supportedConnectionTypes');
504
+ }
505
+
506
+ response.successful = !response.error;
507
+ if (!response.successful) return response;
508
+
509
+ response.clientId = this._generateId();
510
+ return response;
511
+ },
512
+
513
+ connect: function(message, local) {
514
+ var response = { channel: Faye.Channel.CONNECT,
515
+ id: message.id };
516
+
517
+ var clientId = message.clientId,
518
+ client = clientId ? this._clients[clientId] : null,
519
+ connectionType = message.connectionType;
520
+
521
+ if (!client) response.error = Faye.Error.clientUnknown(clientId);
522
+ if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
523
+ if (!connectionType) response.error = Faye.Error.parameterMissing('connectionType');
524
+
525
+ response.successful = !response.error;
526
+ if (!response.successful) return response;
527
+
528
+ response.clientId = client.id;
529
+ return response;
530
+ },
531
+
532
+ disconnect: function(message, local) {
533
+ var response = { channel: Faye.Channel.DISCONNECT,
534
+ id: message.id };
535
+
536
+ var clientId = message.clientId,
537
+ client = clientId ? this._clients[clientId] : null;
538
+
539
+ if (!client) response.error = Faye.Error.clientUnknown(clientId);
540
+ if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
541
+
542
+ response.successful = !response.error;
543
+ if (!response.successful) return response;
544
+
545
+ this._destroyClient(client);
546
+
547
+ response.clientId = clientId;
548
+ return response;
549
+ },
550
+
551
+ subscribe: function(message, local) {
552
+ var response = { channel: Faye.Channel.SUBSCRIBE,
553
+ clientId: message.clientId,
554
+ id: message.id };
555
+
556
+ var clientId = message.clientId,
557
+ client = clientId ? this._clients[clientId] : null,
558
+ subscription = message.subscription;
559
+
560
+ subscription = (subscription instanceof Array) ? subscription : [subscription];
561
+
562
+ if (!client) response.error = Faye.Error.clientUnknown(clientId);
563
+ if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
564
+ if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
565
+
566
+ response.subscription = subscription;
567
+
568
+ Faye.each(subscription, function(channel) {
569
+ if (response.error) return;
570
+ if (!Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
571
+ if (!Faye.Channel.isValid(channel)) response.error = Faye.Error.channelInvalid(channel);
572
+
573
+ if (response.error) return;
574
+ channel = this._channels.findOrCreate(channel);
575
+ client.subscribe(channel);
576
+ }, this);
577
+
578
+ response.successful = !response.error;
579
+ return response;
580
+ },
581
+
582
+ unsubscribe: function(message, local) {
583
+ var response = { channel: Faye.Channel.UNSUBSCRIBE,
584
+ clientId: message.clientId,
585
+ id: message.id };
586
+
587
+ var clientId = message.clientId,
588
+ client = clientId ? this._clients[clientId] : null,
589
+ subscription = message.subscription;
590
+
591
+ subscription = (subscription instanceof Array) ? subscription : [subscription];
592
+
593
+ if (!client) response.error = Faye.Error.clientUnknown(clientId);
594
+ if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
595
+ if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
596
+
597
+ Faye.each(subscription, function(channel) {
598
+ if (response.error) return;
599
+
600
+ if (!Faye.Channel.isValid(channel))
601
+ return response.error = Faye.Error.channelInvalid(channel);
602
+
603
+ channel = this._channels.get(channel);
604
+ if (channel) client.unsubscribe(channel);
605
+ }, this);
606
+
607
+ response.successful = !response.error;
608
+ return response;
609
+ }
610
+ });
611
+
612
+
613
+ Faye.Connection = Faye.Class({
614
+ initialize: function(id, options) {
615
+ this.id = id;
616
+ this._options = options;
617
+ this._observers = {};
618
+ this._channels = new Faye.Set();
619
+ this._inbox = new Faye.Set();
620
+ },
621
+
622
+ timeout: function() {
623
+ return this._options.timeout || Faye.Connection.TIMEOUT;
624
+ },
625
+
626
+ _onMessage: function(event) {
627
+ this._inbox.add(event);
628
+ this._beginDeliveryTimeout();
629
+ },
630
+
631
+ subscribe: function(channel) {
632
+ if (!this._channels.add(channel)) return;
633
+ channel.on('message', this._onMessage, this);
634
+ },
635
+
636
+ unsubscribe: function(channel) {
637
+ if (channel === 'all') return this._channels.forEach(this.unsubscribe, this);
638
+ if (!this._channels.member(channel)) return;
639
+ this._channels.remove(channel);
640
+ channel.stopObserving('message', this._onMessage, this);
641
+ },
642
+
643
+ connect: function(callback) {
644
+ this.on('flush', callback);
645
+ if (this._connected) return;
646
+
647
+ this._markForDeletion = false;
648
+ this._connected = true;
649
+
650
+ if (!this._inbox.isEmpty()) this._beginDeliveryTimeout();
651
+ this._beginConnectionTimeout();
652
+ },
653
+
654
+ flush: function() {
655
+ if (!this._connected) return;
656
+ this._releaseConnection();
657
+
658
+ var events = this._inbox.toArray();
659
+ this._inbox = new Faye.Set();
660
+
661
+ this.fire('flush', events);
662
+ this.stopObserving('flush');
663
+ },
664
+
665
+ disconnect: function() {
666
+ this.unsubscribe('all');
667
+ this.flush();
668
+ },
669
+
670
+ _beginDeliveryTimeout: function() {
671
+ if (this._deliveryTimeout || !this._connected || this._inbox.isEmpty())
672
+ return;
673
+
674
+ var self = this;
675
+ this._deliveryTimeout = setTimeout(function () { self.flush() },
676
+ Faye.Connection.MAX_DELAY * 1000);
677
+ },
678
+
679
+ _beginConnectionTimeout: function() {
680
+ if (this._connectionTimeout || !this._connected)
681
+ return;
682
+
683
+ var self = this;
684
+ this._connectionTimeout = setTimeout(function() { self.flush() },
685
+ this.timeout() * 1000);
686
+ },
687
+
688
+ _releaseConnection: function() {
689
+ if (this._connectionTimeout) {
690
+ clearTimeout(this._connectionTimeout);
691
+ delete this._connectionTimeout;
692
+ }
693
+
694
+ if (this._deliveryTimeout) {
695
+ clearTimeout(this._deliveryTimeout);
696
+ delete this._deliveryTimeout;
697
+ }
698
+
699
+ this._connected = false;
700
+ this._scheduleForDeletion();
701
+ },
702
+
703
+ _scheduleForDeletion: function() {
704
+ if (this._markForDeletion) return;
705
+ this._markForDeletion = true;
706
+ var self = this;
707
+
708
+ setTimeout(function() {
709
+ if (!self._markForDeletion) return;
710
+ self.fire('stale', self);
711
+ }, 10000 * Faye.Connection.INTERVAL);
712
+ }
713
+ });
714
+
715
+ Faye.extend(Faye.Connection.prototype, Faye.Observable);
716
+
717
+ Faye.extend(Faye.Connection, {
718
+ MAX_DELAY: 0.1,
719
+ INTERVAL: 1.0,
720
+ TIMEOUT: 60.0
721
+ });
722
+
723
+
724
+ Faye.Error = Faye.Class({
725
+ initialize: function(code, args, message) {
726
+ this.code = code;
727
+ this.args = Array.prototype.slice.call(args);
728
+ this.message = message;
729
+ },
730
+
731
+ toString: function() {
732
+ return this.code + ':' +
733
+ this.args.join(',') + ':' +
734
+ this.message;
735
+ }
736
+ });
737
+
738
+
739
+ Faye.Error.versionMismatch = function() {
740
+ return new this(300, arguments, "Version mismatch").toString();
741
+ };
742
+
743
+ Faye.Error.conntypeMismatch = function() {
744
+ return new this(301, arguments, "Connection types not supported").toString();
745
+ };
746
+
747
+ Faye.Error.extMismatch = function() {
748
+ return new this(302, arguments, "Extension mismatch").toString();
749
+ };
750
+
751
+ Faye.Error.badRequest = function() {
752
+ return new this(400, arguments, "Bad request").toString();
753
+ };
754
+
755
+ Faye.Error.clientUnknown = function() {
756
+ return new this(401, arguments, "Unknown client").toString();
757
+ };
758
+
759
+ Faye.Error.parameterMissing = function() {
760
+ return new this(402, arguments, "Missing required parameter").toString();
761
+ };
762
+
763
+ Faye.Error.channelForbidden = function() {
764
+ return new this(403, arguments, "Forbidden channel").toString();
765
+ };
766
+
767
+ Faye.Error.channelUnknown = function() {
768
+ return new this(404, arguments, "Unknown channel").toString();
769
+ };
770
+
771
+ Faye.Error.channelInvalid = function() {
772
+ return new this(405, arguments, "Invalid channel").toString();
773
+ };
774
+
775
+ Faye.Error.extUnknown = function() {
776
+ return new this(406, arguments, "Unknown extension").toString();
777
+ };
778
+
779
+ Faye.Error.publishFailed = function() {
780
+ return new this(407, arguments, "Failed to publish").toString();
781
+ };
782
+
783
+ Faye.Error.serverError = function() {
784
+ return new this(500, arguments, "Internal server error").toString();
785
+ };
786
+
787
+
788
+
789
+ var path = require('path'),
790
+ posix = require('posix'),
791
+ sys = require('sys'),
792
+ url = require('url'),
793
+ querystring = require('querystring');
794
+
795
+ Faye.NodeAdapter = Faye.Class({
796
+ initialize: function(options) {
797
+ this._options = options || {};
798
+ this._endpoint = this._options.mount || Faye.NodeAdapter.DEFAULT_ENDPOINT;
799
+ this._script = this._endpoint + '.js';
800
+ this._server = new Faye.Server(this._options);
801
+ },
802
+
803
+ call: function(request, response) {
804
+ var requestUrl = url.parse(request.url, true);
805
+ switch (requestUrl.pathname) {
806
+
807
+ case this._endpoint:
808
+ var isGet = (request.method === 'GET'),
809
+ self = this;
810
+
811
+ if (isGet)
812
+ this._callWithParams(request, response, requestUrl.query);
813
+
814
+ else
815
+ request.addListener('body', function(chunk) {
816
+ self._callWithParams(request, response, querystring.parse(chunk));
817
+ });
818
+
819
+ return true;
820
+ break;
821
+
822
+ case this._script:
823
+ posix.cat(Faye.NodeAdapter.SCRIPT_PATH).addCallback(function(content) {
824
+ response.sendHeader(200, Faye.NodeAdapter.TYPE_SCRIPT);
825
+ response.sendBody(content);
826
+ response.finish();
827
+ });
828
+ return true;
829
+ break;
830
+
831
+ default: return false;
832
+ }
833
+ },
834
+
835
+ _callWithParams: function(request, response, params) {
836
+ try {
837
+ var message = JSON.parse(params.message),
838
+ jsonp = params.jsonp || Faye.JSONP_CALLBACK,
839
+ isGet = (request.method === 'GET'),
840
+ type = isGet ? Faye.NodeAdapter.TYPE_SCRIPT : Faye.NodeAdapter.TYPE_JSON;
841
+
842
+ if (isGet) this._server.flushConnection(message);
843
+
844
+ this._server.process(message, false, function(replies) {
845
+ var body = JSON.stringify(replies);
846
+ if (isGet) body = jsonp + '(' + body + ');';
847
+ response.sendHeader(200, type);
848
+ response.sendBody(body);
849
+ response.finish();
850
+ });
851
+ } catch (e) {
852
+ response.sendHeader(400, {'Content-Type': 'text/plain'});
853
+ response.sendBody('Bad request');
854
+ response.finish();
855
+ }
856
+ }
857
+ });
858
+
859
+ Faye.extend(Faye.NodeAdapter, {
860
+ DEFAULT_ENDPOINT: '/bayeux',
861
+ SCRIPT_PATH: path.dirname(__filename) + '/faye-client-min.js',
862
+
863
+ TYPE_JSON: {'Content-Type': 'text/json'},
864
+ TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
865
+ TYPE_TEXT: {'Content-Type': 'text/plain'}
866
+ });
867
+
868
+ exports.NodeAdapter = Faye.NodeAdapter;