faye 0.1.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

@@ -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;