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/History.txt +11 -0
- data/Manifest.txt +7 -0
- data/README.txt +116 -34
- data/Rakefile +6 -1
- data/build/faye-client-min.js +1 -1
- data/build/faye.js +515 -103
- data/examples/node/app.js +4 -4
- data/examples/node/client.js +23 -0
- data/examples/node/faye-client-min.js +1 -1
- data/examples/node/faye.js +515 -103
- data/examples/rack/client.rb +25 -0
- data/examples/shared/public/index.html +0 -2
- data/jake.yml +5 -2
- data/lib/faye-client-min.js +1 -1
- data/lib/faye.rb +2 -3
- data/lib/faye/channel.rb +14 -13
- data/lib/faye/client.rb +246 -0
- data/lib/faye/connection.rb +18 -17
- data/lib/faye/namespace.rb +16 -0
- data/lib/faye/rack_adapter.rb +12 -2
- data/lib/faye/server.rb +19 -20
- data/lib/faye/transport.rb +103 -0
- data/test/scenario.js +99 -0
- data/test/test_channel.rb +19 -13
- data/test/test_clients.js +177 -0
- data/test/test_server.rb +42 -0
- metadata +23 -6
data/examples/node/app.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
var
|
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
|
-
|
20
|
+
fs.readFile(PUBLIC_DIR + path, function(err, content) {
|
21
21
|
response.sendHeader(200, {'Content-Type': 'text/html'});
|
22
|
-
response.
|
23
|
-
response.
|
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);
|
data/examples/node/faye.js
CHANGED
@@ -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)
|
7
|
-
|
8
|
-
|
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.
|
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
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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
|
396
|
-
this._channels
|
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
|
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
|
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('
|
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('
|
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 (
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
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
|
-
|
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
|
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))
|
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
|
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
|
-
|
623
|
-
return this._options.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.
|
648
|
-
|
1004
|
+
this._connected = true;
|
1005
|
+
|
1006
|
+
if (this._deletionTimeout) {
|
1007
|
+
clearTimeout(this._deletionTimeout);
|
1008
|
+
delete this._deletionTimeout;
|
1009
|
+
}
|
649
1010
|
|
650
|
-
|
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
|
-
|
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.
|
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.
|
705
|
-
this._markForDeletion = true;
|
1065
|
+
if (this._deletionTimeout) return;
|
706
1066
|
var self = this;
|
707
1067
|
|
708
|
-
setTimeout(function() {
|
709
|
-
|
710
|
-
|
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
|
-
|
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 ||
|
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('
|
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
|
-
|
824
|
-
response.sendHeader(200,
|
825
|
-
response.
|
826
|
-
response.
|
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 ?
|
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.
|
849
|
-
response.
|
1268
|
+
response.write(body);
|
1269
|
+
response.close();
|
850
1270
|
});
|
851
1271
|
} catch (e) {
|
852
|
-
response.sendHeader(400,
|
853
|
-
response.
|
854
|
-
response.
|
1272
|
+
response.sendHeader(400, this.TYPE_TEXT);
|
1273
|
+
response.write('Bad request');
|
1274
|
+
response.close();
|
855
1275
|
}
|
856
1276
|
}
|
857
1277
|
});
|
858
1278
|
|
859
|
-
|
860
|
-
|
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;
|