faye 0.2.2 → 0.3.0

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

Potentially problematic release.


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

data/examples/node/app.js CHANGED
@@ -1,4 +1,4 @@
1
- var posix = require('posix'),
1
+ var fs = require('fs'),
2
2
  path = require('path'),
3
3
  sys = require('sys'),
4
4
  http = require('http')
@@ -17,10 +17,10 @@ http.createServer(function(request, response) {
17
17
 
18
18
  var path = (request.url === '/') ? '/index.html' : request.url;
19
19
 
20
- posix.cat(PUBLIC_DIR + path).addCallback(function(content) {
20
+ fs.readFile(PUBLIC_DIR + path, function(err, content) {
21
21
  response.sendHeader(200, {'Content-Type': 'text/html'});
22
- response.sendBody(content);
23
- response.finish();
22
+ response.write(content);
23
+ response.close();
24
24
  });
25
25
  }).listen(Number(port));
26
26
 
@@ -0,0 +1,23 @@
1
+ // This script demonstrates a logger for the chat app. First, start
2
+ // the chat server in one terminal then run this in another:
3
+ //
4
+ // $ node examples/node/app.js
5
+ // $ node examples/node/client.js
6
+ //
7
+ // The client connects to the chat server and logs all messages
8
+ // sent by all connected users.
9
+
10
+ var sys = require('sys'),
11
+ faye = require('./faye');
12
+
13
+ var client = new faye.Client('http://localhost:8000/comet');
14
+
15
+ client.subscribe('/from/*', function(message) {
16
+ var user = message.user;
17
+ sys.puts('[' + user + ']: ' + message.message);
18
+ client.publish('/mentioning/' + user, {
19
+ user: 'node-logger',
20
+ message: 'Got your message, ' + user + '!'
21
+ });
22
+ });
23
+
@@ -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)&&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');}}}());
1
+ if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.0',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Observable={on:function(a,b,c){this._0=this._0||{};var d=this._0[a]=this._0[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._0||!this._0[a])return;if(!b){delete this._0[a];return}var d=this._0[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._0||!this._0[c])return;Faye.each(this._0[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._1=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._1!==undefined)d.call(f,c,this._1)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._1:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._1=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._1===undefined)?[]:[this._1];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._1!==undefined)g.push(b._1)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._1!==undefined)g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._1);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._m={}},generate:function(){var a=Faye.random();while(this._m.hasOwnProperty(a))a=Faye.random();return this._m[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._f=a;this._6=b},send:function(c,d,f){if(!(c instanceof Array)&&!c.id)c.id=this._f._n.generate();this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){if(a.id===c.id)d.call(f,a);if(a.advice)this._f.handleAdvice(a.advice);if(a.data&&a.channel)this._f.sendToSubscribers(a)},this)},this)}}),{get:function(c,d){var f=c._6;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._g,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._g[a]=b;b.prototype.connectionType=a},_g:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._g,function(a,b){c.push(a)});return c}});Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._2=this.UNCONNECTED;this._n=new Faye.Namespace();this._h=[];this._a=new Faye.Channel.Tree();this._9=[];this._7={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2!==this.UNCONNECTED)return;this._2=this.CONNECTING;var d=this;this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._2=this.UNCONNECTED}this._2=this.CONNECTED;this._8=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2===this.DISCONNECTED)return;if(this._7.reconnect===this.HANDSHAKE||this._2===this.UNCONNECTED)return this.handshake(function(){this.connect(b,c)},this);if(this._2===this.CONNECTING)return this._9.push([b,c]);if(this._2!==this.CONNECTED)return;Faye.each(this._9,function(a){a[0].call(a[1])});this._9=[];if(b)b.call(c);if(this._i)return;this._i=this._n.generate();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._8,connectionType:this._4.connectionType,id:this._i},function(a){delete this._i;setTimeout(function(){d.connect()},this._7.interval)},this)},disconnect:function(){if(this._2!==this.CONNECTED)return;this._2=this.DISCONNECTED;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._8});this._a=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,[d,f])},this)},this)},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,null)},this)},this)},this)},publish:function(b,c){this.connect(function(){this._j([b]);this._r({channel:b,data:c,clientId:this._8});if(this._o)return;var a=this;this._o=setTimeout(function(){delete a._o;a._s()},this.MAX_DELAY*1000)},this)},handleAdvice:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this.HANDSHAKE)this._8=null},sendToSubscribers:function(b){var c=this._a.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},_r:function(a){this._h.push(a)},_s:function(){this._4.send(this._h);this._h=[]},_j:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})}});Faye.Event={_b:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._b.push({_c:a,_k:b,_t:c,_d:d,_p:f})},detach:function(a,b,c,d){var f=this._b.length,g;while(f--){g=this._b[f];if((a&&a!==g._c)||(b&&b!==g._k)||(c&&c!==g._t)||(d&&d!==g._d))continue;if(g._c.removeEventListener)g._c.removeEventListener(g._k,g._p,false);else g._c.detachEvent('on'+g._k,g._p);this._b.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._e=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._9=(typeof d==='function')?{success:d}:d;this._d=f||null;this._3=null},send:function(){if(this._l)return;var a=this._6.pathname,b=this._6.queryString();if(this._e==='GET')a+='?'+b;var c=this._e==='POST'?b:'';this._l=true;this._3=Faye.XHR.getXhrObject();this._3.open(this._e,a,true);if(this._e==='POST')this._3.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._3.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._l=false;d._u();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._3.send(c)},abort:function(){this._3.abort()},_u:function(){var a=this._9;if(!a)return;return this.success()?a.success&&a.success.call(this._d,this):a.failure&&a.failure.call(this._d,this)},waiting:function(){return!!this._l},complete:function(){return this._3&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._3.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._3.responseText},status:function(){if(!this.complete())return null;return this._3.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)};Faye.XHR.request('post',this._6,f,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)},g=document.getElementsByTagName('head')[0],k=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._6,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(k);if(c)c.call(d,a)};h.params.jsonp=i;k.type='text/javascript';k.src=h.toURL();g.appendChild(k)}}),{_q:0,getCallbackName:function(){this._q+=1;return'__jsonp'+this._q+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
@@ -3,23 +3,36 @@ if (!this.Faye) Faye = {};
3
3
  Faye.extend = function(dest, source, overwrite) {
4
4
  if (!source) return dest;
5
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
- }
6
+ if (!source.hasOwnProperty(key)) continue;
7
+ if (dest.hasOwnProperty(key) && overwrite === false) continue;
8
+ if (dest[key] !== source[key])
9
+ dest[key] = source[key];
10
10
  }
11
11
  return dest;
12
12
  };
13
13
 
14
14
  Faye.extend(Faye, {
15
+ VERSION: '0.3.0',
16
+
15
17
  BAYEUX_VERSION: '1.0',
16
- VERSION: '0.2.2',
17
- JSONP_CALLBACK: 'jsonpcallback',
18
18
  ID_LENGTH: 128,
19
+ JSONP_CALLBACK: 'jsonpcallback',
19
20
  CONNECTION_TYPES: ["long-polling", "callback-polling"],
20
21
 
21
22
  ENV: this,
22
23
 
24
+ random: function(bitlength) {
25
+ bitlength = bitlength || this.ID_LENGTH;
26
+ if (bitlength > 32) {
27
+ var parts = Math.ceil(bitlength / 32),
28
+ string = '';
29
+ while (parts--) string += this.random(32);
30
+ return string;
31
+ }
32
+ var field = Math.pow(2, bitlength);
33
+ return Math.floor(Math.random() * field).toString(16);
34
+ },
35
+
23
36
  Grammar: {
24
37
 
25
38
  LOWALPHA: /^[a-z]$/,
@@ -97,17 +110,21 @@ Faye.extend(Faye, {
97
110
  }
98
111
  },
99
112
 
113
+ filter: function(array, callback, scope) {
114
+ var result = [];
115
+ this.each(array, function() {
116
+ if (callback.apply(scope, arguments))
117
+ result.push(arguments[0]);
118
+ });
119
+ return result;
120
+ },
121
+
100
122
  size: function(object) {
101
123
  var size = 0;
102
124
  this.each(object, function() { size += 1 });
103
125
  return size;
104
126
  },
105
127
 
106
- random: function() {
107
- var field = Math.pow(2, this.ID_LENGTH);
108
- return (Math.random() * field).toString(16).replace(/0*$/, '');
109
- },
110
-
111
128
  enumEqual: function(actual, expected) {
112
129
  if (expected instanceof Array) {
113
130
  if (!(actual instanceof Array)) return false;
@@ -190,7 +207,7 @@ Faye.Observable = {
190
207
 
191
208
  Faye.Channel = Faye.Class({
192
209
  initialize: function(name) {
193
- this.__id = this._name = name;
210
+ this.__id = this.name = name;
194
211
  },
195
212
 
196
213
  push: function(message) {
@@ -311,7 +328,7 @@ Faye.extend(Faye.Channel, {
311
328
 
312
329
  if (Faye.enumEqual(path, ['**'])) {
313
330
  list = this.map(function(key, value) { return value });
314
- list.pop();
331
+ if (this._value !== undefined) list.pop();
315
332
  return list;
316
333
  }
317
334
 
@@ -324,23 +341,341 @@ Faye.extend(Faye.Channel, {
324
341
  if (this._children['**']) list.push(this._children['**']._value);
325
342
  return list;
326
343
  }
344
+ })
345
+ });
346
+
347
+
348
+ Faye.Namespace = Faye.Class({
349
+ initialize: function() {
350
+ this._used = {};
351
+ },
352
+
353
+ generate: function() {
354
+ var name = Faye.random();
355
+ while (this._used.hasOwnProperty(name))
356
+ name = Faye.random();
357
+ return this._used[name] = name;
358
+ }
359
+ });
360
+
361
+
362
+ Faye.Transport = Faye.extend(Faye.Class({
363
+ initialize: function(client, endpoint) {
364
+ this._client = client;
365
+ this._endpoint = endpoint;
366
+ },
367
+
368
+ send: function(message, callback, scope) {
369
+ if (!(message instanceof Array) && !message.id)
370
+ message.id = this._client._namespace.generate();
327
371
 
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(' ');
372
+ this.request(message, function(responses) {
373
+ if (!callback) return;
374
+ Faye.each([].concat(responses), function(response) {
375
+
376
+ if (response.id === message.id)
377
+ callback.call(scope, response);
378
+
379
+ if (response.advice)
380
+ this._client.handleAdvice(response.advice);
381
+
382
+ if (response.data && response.channel)
383
+ this._client.sendToSubscribers(response);
384
+
385
+ }, this);
386
+ }, this);
387
+ }
388
+ }), {
389
+ get: function(client, connectionTypes) {
390
+ var endpoint = client._endpoint;
391
+ if (connectionTypes === undefined) connectionTypes = this.supportedConnectionTypes();
392
+
393
+ var candidateClass = null;
394
+ Faye.each(this._transports, function(connType, klass) {
395
+ if (Faye.indexOf(connectionTypes, connType) < 0) return;
396
+ if (candidateClass) return;
397
+ if (klass.isUsable(endpoint)) candidateClass = klass;
398
+ });
399
+
400
+ if (!candidateClass) throw 'Could not find a usable connection type for ' + endpoint;
401
+
402
+ return new candidateClass(client, endpoint);
403
+ },
404
+
405
+ register: function(type, klass) {
406
+ this._transports[type] = klass;
407
+ klass.prototype.connectionType = type;
408
+ },
409
+
410
+ _transports: {},
411
+
412
+ supportedConnectionTypes: function() {
413
+ var list = [], key;
414
+ Faye.each(this._transports, function(key, type) { list.push(key) });
415
+ return list;
416
+ }
417
+ });
333
418
 
334
- Faye.each(list, function(c, i) {
335
- glob.set(c, i + 1);
336
- });
337
419
 
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
- })
420
+ Faye.Client = Faye.Class({
421
+ UNCONNECTED: 1,
422
+ CONNECTING: 2,
423
+ CONNECTED: 3,
424
+ DISCONNECTED: 4,
425
+
426
+ HANDSHAKE: 'handshake',
427
+ RETRY: 'retry',
428
+ NONE: 'none',
429
+
430
+ DEFAULT_ENDPOINT: '/bayeux',
431
+ MAX_DELAY: 0.1,
432
+ INTERVAL: 1000.0,
433
+
434
+ initialize: function(endpoint) {
435
+ this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
436
+ this._transport = Faye.Transport.get(this);
437
+ this._state = this.UNCONNECTED;
438
+ this._namespace = new Faye.Namespace();
439
+ this._outbox = [];
440
+ this._channels = new Faye.Channel.Tree();
441
+ this._callbacks = [];
442
+
443
+ this._advice = {reconnect: this.RETRY, interval: this.INTERVAL};
444
+
445
+ if (!Faye.Event) return;
446
+ Faye.Event.on(Faye.ENV, 'beforeunload', this.disconnect, this);
447
+ },
448
+
449
+ // Request
450
+ // MUST include: * channel
451
+ // * version
452
+ // * supportedConnectionTypes
453
+ // MAY include: * minimumVersion
454
+ // * ext
455
+ // * id
456
+ //
457
+ // Success Response Failed Response
458
+ // MUST include: * channel MUST include: * channel
459
+ // * version * successful
460
+ // * supportedConnectionTypes * error
461
+ // * clientId MAY include: * supportedConnectionTypes
462
+ // * successful * advice
463
+ // MAY include: * minimumVersion * version
464
+ // * advice * minimumVersion
465
+ // * ext * ext
466
+ // * id * id
467
+ // * authSuccessful
468
+ handshake: function(callback, scope) {
469
+ if (this._advice.reconnect === this.NONE) return;
470
+ if (this._state !== this.UNCONNECTED) return;
471
+
472
+ this._state = this.CONNECTING;
473
+ var self = this;
474
+
475
+ this._transport.send({
476
+ channel: Faye.Channel.HANDSHAKE,
477
+ version: Faye.BAYEUX_VERSION,
478
+ supportedConnectionTypes: Faye.Transport.supportedConnectionTypes()
479
+
480
+ }, function(response) {
481
+
482
+ if (!response.successful) {
483
+ setTimeout(function() { self.handshake(callback, scope) }, this._advice.interval);
484
+ return this._state = this.UNCONNECTED;
485
+ }
486
+
487
+ this._state = this.CONNECTED;
488
+ this._clientId = response.clientId;
489
+ this._transport = Faye.Transport.get(this, response.supportedConnectionTypes);
490
+
491
+ if (callback) callback.call(scope);
492
+ }, this);
493
+ },
494
+
495
+ // Request Response
496
+ // MUST include: * channel MUST include: * channel
497
+ // * clientId * successful
498
+ // * connectionType * clientId
499
+ // MAY include: * ext MAY include: * error
500
+ // * id * advice
501
+ // * ext
502
+ // * id
503
+ // * timestamp
504
+ connect: function(callback, scope) {
505
+ if (this._advice.reconnect === this.NONE) return;
506
+ if (this._state === this.DISCONNECTED) return;
507
+
508
+ if (this._advice.reconnect === this.HANDSHAKE || this._state === this.UNCONNECTED)
509
+ return this.handshake(function() { this.connect(callback, scope) }, this);
510
+
511
+ if (this._state === this.CONNECTING)
512
+ return this._callbacks.push([callback, scope]);
513
+
514
+ if (this._state !== this.CONNECTED) return;
515
+
516
+ Faye.each(this._callbacks, function(listener) { listener[0].call(listener[1]) });
517
+ this._callbacks = [];
518
+ if (callback) callback.call(scope);
519
+
520
+ if (this._connectionId) return;
521
+ this._connectionId = this._namespace.generate();
522
+ var self = this;
523
+
524
+ this._transport.send({
525
+ channel: Faye.Channel.CONNECT,
526
+ clientId: this._clientId,
527
+ connectionType: this._transport.connectionType,
528
+ id: this._connectionId
529
+
530
+ }, function(response) {
531
+ delete this._connectionId;
532
+ setTimeout(function() { self.connect() }, this._advice.interval);
533
+ }, this);
534
+ },
535
+
536
+ // Request Response
537
+ // MUST include: * channel MUST include: * channel
538
+ // * clientId * successful
539
+ // MAY include: * ext * clientId
540
+ // * id MAY include: * error
541
+ // * ext
542
+ // * id
543
+ disconnect: function() {
544
+ if (this._state !== this.CONNECTED) return;
545
+ this._state = this.DISCONNECTED;
546
+
547
+ this._transport.send({
548
+ channel: Faye.Channel.DISCONNECT,
549
+ clientId: this._clientId
550
+ });
551
+
552
+ this._channels = new Faye.Channel.Tree();
553
+ },
554
+
555
+ // Request Response
556
+ // MUST include: * channel MUST include: * channel
557
+ // * clientId * successful
558
+ // * subscription * clientId
559
+ // MAY include: * ext * subscription
560
+ // * id MAY include: * error
561
+ // * advice
562
+ // * ext
563
+ // * id
564
+ // * timestamp
565
+ subscribe: function(channels, callback, scope) {
566
+ this.connect(function() {
567
+
568
+ channels = [].concat(channels);
569
+ this._validateChannels(channels);
570
+
571
+ this._transport.send({
572
+ channel: Faye.Channel.SUBSCRIBE,
573
+ clientId: this._clientId,
574
+ subscription: channels
575
+
576
+ }, function(response) {
577
+ if (!response.successful) return;
578
+
579
+ channels = [].concat(response.subscription);
580
+ Faye.each(channels, function(channel) {
581
+ this._channels.set(channel, [callback, scope]);
582
+ }, this);
583
+ }, this);
584
+
585
+ }, this);
586
+ },
587
+
588
+ // Request Response
589
+ // MUST include: * channel MUST include: * channel
590
+ // * clientId * successful
591
+ // * subscription * clientId
592
+ // MAY include: * ext * subscription
593
+ // * id MAY include: * error
594
+ // * advice
595
+ // * ext
596
+ // * id
597
+ // * timestamp
598
+ unsubscribe: function(channels, callback, scope) {
599
+ this.connect(function() {
600
+
601
+ channels = [].concat(channels);
602
+ this._validateChannels(channels);
603
+
604
+ this._transport.send({
605
+ channel: Faye.Channel.UNSUBSCRIBE,
606
+ clientId: this._clientId,
607
+ subscription: channels
608
+
609
+ }, function(response) {
610
+ if (!response.successful) return;
611
+
612
+ channels = [].concat(response.subscription);
613
+ Faye.each(channels, function(channel) {
614
+ this._channels.set(channel, null);
615
+ }, this);
616
+ }, this);
617
+
618
+ }, this);
619
+ },
620
+
621
+ // Request Response
622
+ // MUST include: * channel MUST include: * channel
623
+ // * data * successful
624
+ // MAY include: * clientId MAY include: * id
625
+ // * id * error
626
+ // * ext * ext
627
+ publish: function(channel, data) {
628
+ this.connect(function() {
629
+
630
+ this._validateChannels([channel]);
631
+
632
+ this._enqueue({
633
+ channel: channel,
634
+ data: data,
635
+ clientId: this._clientId
636
+ });
637
+
638
+ if (this._timeout) return;
639
+ var self = this;
640
+
641
+ this._timeout = setTimeout(function() {
642
+ delete self._timeout;
643
+ self._flush();
644
+ }, this.MAX_DELAY * 1000);
645
+
646
+ }, this);
647
+ },
648
+
649
+ handleAdvice: function(advice) {
650
+ Faye.extend(this._advice, advice);
651
+ if (this._advice.reconnect === this.HANDSHAKE) this._clientId = null;
652
+ },
653
+
654
+ sendToSubscribers: function(message) {
655
+ var channels = this._channels.glob(message.channel);
656
+ Faye.each(channels, function(callback) {
657
+ if (!callback) return;
658
+ callback[0].call(callback[1], message.data);
659
+ });
660
+ },
661
+
662
+ _enqueue: function(message) {
663
+ this._outbox.push(message);
664
+ },
665
+
666
+ _flush: function() {
667
+ this._transport.send(this._outbox);
668
+ this._outbox = [];
669
+ },
670
+
671
+ _validateChannels: function(channels) {
672
+ Faye.each(channels, function(channel) {
673
+ if (!Faye.Channel.isValid(channel))
674
+ throw '"' + channel + '" is not a valid channel name';
675
+ if (!Faye.Channel.isSubscribable(channel))
676
+ throw 'Clients may not subscribe to channel "' + channel + '"';
677
+ });
678
+ }
344
679
  });
345
680
 
346
681
 
@@ -392,9 +727,10 @@ Faye.Set = Faye.Class({
392
727
 
393
728
  Faye.Server = Faye.Class({
394
729
  initialize: function(options) {
395
- this._options = options || {};
396
- this._channels = new Faye.Channel.Tree();
397
- this._clients = {};
730
+ this._options = options || {};
731
+ this._channels = new Faye.Channel.Tree();
732
+ this._clients = {};
733
+ this._namespace = new Faye.Namespace();
398
734
  },
399
735
 
400
736
  clientIds: function() {
@@ -404,7 +740,7 @@ Faye.Server = Faye.Class({
404
740
  },
405
741
 
406
742
  process: function(messages, local, callback) {
407
- messages = (messages instanceof Array) ? messages : [messages];
743
+ messages = [].concat(messages);
408
744
  var processed = 0, responses = [];
409
745
 
410
746
  Faye.each(messages, function(message) {
@@ -417,29 +753,23 @@ Faye.Server = Faye.Class({
417
753
  },
418
754
 
419
755
  flushConnection: function(messages) {
420
- messages = (messages instanceof Array) ? messages : [messages];
756
+ messages = [].concat(messages);
421
757
  Faye.each(messages, function(message) {
422
758
  var client = this._clients[message.clientId];
423
759
  if (client) client.flush();
424
760
  }, this);
425
761
  },
426
762
 
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
763
  _connection: function(id) {
434
764
  if (this._clients.hasOwnProperty(id)) return this._clients[id];
435
765
  var client = new Faye.Connection(id, this._options);
436
- client.on('stale', this._destroyClient, this);
766
+ client.on('staleClient', this._destroyClient, this);
437
767
  return this._clients[id] = client;
438
768
  },
439
769
 
440
770
  _destroyClient: function(client) {
441
771
  client.disconnect();
442
- client.stopObserving('stale', this._destroyClient, this);
772
+ client.stopObserving('staleClient', this._destroyClient, this);
443
773
  delete this._clients[client.id];
444
774
  },
445
775
 
@@ -448,6 +778,9 @@ Faye.Server = Faye.Class({
448
778
  channel = message.channel,
449
779
  response;
450
780
 
781
+ message.__id = Faye.random();
782
+ Faye.each(this._channels.glob(channel), function(c) { c.push(message) });
783
+
451
784
  if (Faye.Channel.isMeta(channel)) {
452
785
  response = this[Faye.Channel.parse(channel)[1]](message, local);
453
786
 
@@ -473,18 +806,19 @@ Faye.Server = Faye.Class({
473
806
  if (!message.clientId || Faye.Channel.isService(channel))
474
807
  return callback([]);
475
808
 
476
- message.__id = Faye.random();
477
- Faye.each(this._channels.glob(channel), function(c) { c.push(message) });
478
-
479
809
  callback( { channel: channel,
480
810
  successful: true,
481
811
  id: message.id } );
482
812
  },
483
813
 
814
+ // MUST contain * version
815
+ // * supportedConnectionTypes
816
+ // MAY contain * minimumVersion
817
+ // * ext
818
+ // * id
484
819
  handshake: function(message, local) {
485
820
  var response = { channel: Faye.Channel.HANDSHAKE,
486
821
  version: Faye.BAYEUX_VERSION,
487
- supportedConnectionTypes: Faye.CONNECTION_TYPES,
488
822
  id: message.id };
489
823
 
490
824
  if (!message.version)
@@ -493,23 +827,32 @@ Faye.Server = Faye.Class({
493
827
  var clientConns = message.supportedConnectionTypes,
494
828
  commonConns;
495
829
 
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');
830
+ if (!local) {
831
+ response.supportedConnectionTypes = Faye.CONNECTION_TYPES;
832
+
833
+ if (clientConns) {
834
+ commonConns = Faye.filter(clientConns, function(conn) {
835
+ return Faye.indexOf(Faye.CONNECTION_TYPES, conn) !== -1;
836
+ });
837
+ if (commonConns.length === 0)
838
+ response.error = Faye.Error.conntypeMismatch(clientConns);
839
+ } else {
840
+ response.error = Faye.Error.parameterMissing('supportedConnectionTypes');
841
+ }
504
842
  }
505
843
 
506
844
  response.successful = !response.error;
507
845
  if (!response.successful) return response;
508
846
 
509
- response.clientId = this._generateId();
847
+ var clientId = this._namespace.generate();
848
+ response.clientId = this._connection(clientId).id;
510
849
  return response;
511
850
  },
512
851
 
852
+ // MUST contain * clientId
853
+ // * connectionType
854
+ // MAY contain * ext
855
+ // * id
513
856
  connect: function(message, local) {
514
857
  var response = { channel: Faye.Channel.CONNECT,
515
858
  id: message.id };
@@ -529,6 +872,9 @@ Faye.Server = Faye.Class({
529
872
  return response;
530
873
  },
531
874
 
875
+ // MUST contain * clientId
876
+ // MAY contain * ext
877
+ // * id
532
878
  disconnect: function(message, local) {
533
879
  var response = { channel: Faye.Channel.DISCONNECT,
534
880
  id: message.id };
@@ -548,6 +894,10 @@ Faye.Server = Faye.Class({
548
894
  return response;
549
895
  },
550
896
 
897
+ // MUST contain * clientId
898
+ // * subscription
899
+ // MAY contain * ext
900
+ // * id
551
901
  subscribe: function(message, local) {
552
902
  var response = { channel: Faye.Channel.SUBSCRIBE,
553
903
  clientId: message.clientId,
@@ -557,7 +907,7 @@ Faye.Server = Faye.Class({
557
907
  client = clientId ? this._clients[clientId] : null,
558
908
  subscription = message.subscription;
559
909
 
560
- subscription = (subscription instanceof Array) ? subscription : [subscription];
910
+ subscription = [].concat(subscription);
561
911
 
562
912
  if (!client) response.error = Faye.Error.clientUnknown(clientId);
563
913
  if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
@@ -567,8 +917,8 @@ Faye.Server = Faye.Class({
567
917
 
568
918
  Faye.each(subscription, function(channel) {
569
919
  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);
920
+ if (!local && !Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
921
+ if (!Faye.Channel.isValid(channel)) response.error = Faye.Error.channelInvalid(channel);
572
922
 
573
923
  if (response.error) return;
574
924
  channel = this._channels.findOrCreate(channel);
@@ -579,6 +929,10 @@ Faye.Server = Faye.Class({
579
929
  return response;
580
930
  },
581
931
 
932
+ // MUST contain * clientId
933
+ // * subscription
934
+ // MAY contain * ext
935
+ // * id
582
936
  unsubscribe: function(message, local) {
583
937
  var response = { channel: Faye.Channel.UNSUBSCRIBE,
584
938
  clientId: message.clientId,
@@ -588,7 +942,7 @@ Faye.Server = Faye.Class({
588
942
  client = clientId ? this._clients[clientId] : null,
589
943
  subscription = message.subscription;
590
944
 
591
- subscription = (subscription instanceof Array) ? subscription : [subscription];
945
+ subscription = [].concat(subscription);
592
946
 
593
947
  if (!client) response.error = Faye.Error.clientUnknown(clientId);
594
948
  if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
@@ -611,16 +965,19 @@ Faye.Server = Faye.Class({
611
965
 
612
966
 
613
967
  Faye.Connection = Faye.Class({
968
+ MAX_DELAY: 0.1,
969
+ INTERVAL: 1.0,
970
+ TIMEOUT: 60.0,
971
+
614
972
  initialize: function(id, options) {
615
973
  this.id = id;
616
974
  this._options = options;
617
- this._observers = {};
618
975
  this._channels = new Faye.Set();
619
976
  this._inbox = new Faye.Set();
620
977
  },
621
978
 
622
- timeout: function() {
623
- return this._options.timeout || Faye.Connection.TIMEOUT;
979
+ getTimeout: function() {
980
+ return this._options.timeout || this.TIMEOUT;
624
981
  },
625
982
 
626
983
  _onMessage: function(event) {
@@ -644,10 +1001,14 @@ Faye.Connection = Faye.Class({
644
1001
  this.on('flush', callback);
645
1002
  if (this._connected) return;
646
1003
 
647
- this._markForDeletion = false;
648
- this._connected = true;
1004
+ this._connected = true;
1005
+
1006
+ if (this._deletionTimeout) {
1007
+ clearTimeout(this._deletionTimeout);
1008
+ delete this._deletionTimeout;
1009
+ }
649
1010
 
650
- if (!this._inbox.isEmpty()) this._beginDeliveryTimeout();
1011
+ this._beginDeliveryTimeout();
651
1012
  this._beginConnectionTimeout();
652
1013
  },
653
1014
 
@@ -673,7 +1034,7 @@ Faye.Connection = Faye.Class({
673
1034
 
674
1035
  var self = this;
675
1036
  this._deliveryTimeout = setTimeout(function () { self.flush() },
676
- Faye.Connection.MAX_DELAY * 1000);
1037
+ this.MAX_DELAY * 1000);
677
1038
  },
678
1039
 
679
1040
  _beginConnectionTimeout: function() {
@@ -682,7 +1043,7 @@ Faye.Connection = Faye.Class({
682
1043
 
683
1044
  var self = this;
684
1045
  this._connectionTimeout = setTimeout(function() { self.flush() },
685
- this.timeout() * 1000);
1046
+ this.getTimeout() * 1000);
686
1047
  },
687
1048
 
688
1049
  _releaseConnection: function() {
@@ -701,25 +1062,17 @@ Faye.Connection = Faye.Class({
701
1062
  },
702
1063
 
703
1064
  _scheduleForDeletion: function() {
704
- if (this._markForDeletion) return;
705
- this._markForDeletion = true;
1065
+ if (this._deletionTimeout) return;
706
1066
  var self = this;
707
1067
 
708
- setTimeout(function() {
709
- if (!self._markForDeletion) return;
710
- self.fire('stale', self);
711
- }, 10000 * Faye.Connection.INTERVAL);
1068
+ this._deletionTimeout = setTimeout(function() {
1069
+ self.fire('staleClient', self);
1070
+ }, 10 * 1000 * this.INTERVAL);
712
1071
  }
713
1072
  });
714
1073
 
715
1074
  Faye.extend(Faye.Connection.prototype, Faye.Observable);
716
1075
 
717
- Faye.extend(Faye.Connection, {
718
- MAX_DELAY: 0.1,
719
- INTERVAL: 1.0,
720
- TIMEOUT: 60.0
721
- });
722
-
723
1076
 
724
1077
  Faye.Error = Faye.Class({
725
1078
  initialize: function(code, args, message) {
@@ -786,33 +1139,100 @@ Faye.Error.serverError = function() {
786
1139
 
787
1140
 
788
1141
 
1142
+ Faye.NodeHttpTransport = Faye.Class(Faye.Transport, {
1143
+ request: function(message, callback, scope) {
1144
+ var params = {message: JSON.stringify(message)},
1145
+ request = this.createRequest();
1146
+
1147
+ request.write(querystring.stringify(params));
1148
+
1149
+ request.addListener('response', function(response) {
1150
+ if (!callback) return;
1151
+ response.addListener('data', function(chunk) {
1152
+ callback.call(scope, JSON.parse(chunk));
1153
+ });
1154
+ });
1155
+ request.close();
1156
+ },
1157
+
1158
+ createRequest: function() {
1159
+ var uri = url.parse(this._endpoint),
1160
+ client = http.createClient(uri.port, uri.hostname);
1161
+
1162
+ return client.request('POST', uri.pathname, {
1163
+ 'Content-Type': 'application/x-www-form-urlencoded'
1164
+ });
1165
+ }
1166
+ });
1167
+
1168
+ Faye.NodeHttpTransport.isUsable = function(endpoint) {
1169
+ return typeof endpoint === 'string';
1170
+ };
1171
+
1172
+ Faye.Transport.register('long-polling', Faye.NodeHttpTransport);
1173
+
1174
+ Faye.NodeLocalTransport = Faye.Class(Faye.Transport, {
1175
+ request: function(message, callback, scope) {
1176
+ this._endpoint.process(message, true, function(response) {
1177
+ callback.call(scope, response);
1178
+ });
1179
+ }
1180
+ });
1181
+
1182
+ Faye.NodeLocalTransport.isUsable = function(endpoint) {
1183
+ return endpoint instanceof Faye.Server;
1184
+ };
1185
+
1186
+ Faye.Transport.register('in-process', Faye.NodeLocalTransport);
1187
+
1188
+
789
1189
  var path = require('path'),
790
- posix = require('posix'),
1190
+ fs = require('fs'),
791
1191
  sys = require('sys'),
792
1192
  url = require('url'),
1193
+ http = require('http'),
793
1194
  querystring = require('querystring');
794
1195
 
795
1196
  Faye.NodeAdapter = Faye.Class({
1197
+ DEFAULT_ENDPOINT: '/bayeux',
1198
+ SCRIPT_PATH: path.dirname(__filename) + '/faye-client-min.js',
1199
+
1200
+ TYPE_JSON: {'Content-Type': 'text/json'},
1201
+ TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
1202
+ TYPE_TEXT: {'Content-Type': 'text/plain'},
1203
+
796
1204
  initialize: function(options) {
797
1205
  this._options = options || {};
798
- this._endpoint = this._options.mount || Faye.NodeAdapter.DEFAULT_ENDPOINT;
1206
+ this._endpoint = this._options.mount || this.DEFAULT_ENDPOINT;
799
1207
  this._script = this._endpoint + '.js';
800
1208
  this._server = new Faye.Server(this._options);
801
1209
  },
802
1210
 
1211
+ getClient: function() {
1212
+ return this._client = this._client || new Faye.Client(this._server);
1213
+ },
1214
+
1215
+ run: function(port) {
1216
+ var self = this;
1217
+ http.createServer(function(request, response) {
1218
+ self.call(request, response);
1219
+ }).listen(Number(port));
1220
+ },
1221
+
803
1222
  call: function(request, response) {
804
- var requestUrl = url.parse(request.url, true);
1223
+ var requestUrl = url.parse(request.url, true),
1224
+ self = this;
1225
+
805
1226
  switch (requestUrl.pathname) {
806
1227
 
807
1228
  case this._endpoint:
808
- var isGet = (request.method === 'GET'),
809
- self = this;
1229
+ var isGet = (request.method === 'GET');
810
1230
 
811
1231
  if (isGet)
812
1232
  this._callWithParams(request, response, requestUrl.query);
813
1233
 
814
1234
  else
815
- request.addListener('body', function(chunk) {
1235
+ request.addListener('data', function(chunk) {
816
1236
  self._callWithParams(request, response, querystring.parse(chunk));
817
1237
  });
818
1238
 
@@ -820,10 +1240,10 @@ Faye.NodeAdapter = Faye.Class({
820
1240
  break;
821
1241
 
822
1242
  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();
1243
+ fs.readFile(this.SCRIPT_PATH, function(err, content) {
1244
+ response.sendHeader(200, self.TYPE_SCRIPT);
1245
+ response.write(content);
1246
+ response.close();
827
1247
  });
828
1248
  return true;
829
1249
  break;
@@ -837,7 +1257,7 @@ Faye.NodeAdapter = Faye.Class({
837
1257
  var message = JSON.parse(params.message),
838
1258
  jsonp = params.jsonp || Faye.JSONP_CALLBACK,
839
1259
  isGet = (request.method === 'GET'),
840
- type = isGet ? Faye.NodeAdapter.TYPE_SCRIPT : Faye.NodeAdapter.TYPE_JSON;
1260
+ type = isGet ? this.TYPE_SCRIPT : this.TYPE_JSON;
841
1261
 
842
1262
  if (isGet) this._server.flushConnection(message);
843
1263
 
@@ -845,24 +1265,16 @@ Faye.NodeAdapter = Faye.Class({
845
1265
  var body = JSON.stringify(replies);
846
1266
  if (isGet) body = jsonp + '(' + body + ');';
847
1267
  response.sendHeader(200, type);
848
- response.sendBody(body);
849
- response.finish();
1268
+ response.write(body);
1269
+ response.close();
850
1270
  });
851
1271
  } catch (e) {
852
- response.sendHeader(400, {'Content-Type': 'text/plain'});
853
- response.sendBody('Bad request');
854
- response.finish();
1272
+ response.sendHeader(400, this.TYPE_TEXT);
1273
+ response.write('Bad request');
1274
+ response.close();
855
1275
  }
856
1276
  }
857
1277
  });
858
1278
 
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;
1279
+ exports.NodeAdapter = Faye.NodeAdapter;
1280
+ exports.Client = Faye.Client;