faye 0.1.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye might be problematic. Click here for more details.
- data/History.txt +28 -0
- data/Jakefile +11 -0
- data/Manifest.txt +15 -17
- data/README.txt +149 -47
- data/build/faye-client-min.js +1 -0
- data/build/faye.js +868 -0
- data/examples/README.rdoc +41 -0
- data/examples/node/app.js +26 -0
- data/examples/node/faye-client-min.js +1 -0
- data/examples/node/faye.js +868 -0
- data/examples/rack/app.rb +6 -0
- data/examples/{soapbox → rack}/config.ru +1 -1
- data/examples/shared/public/favicon.ico +0 -0
- data/examples/{soapbox/views/index.erb → shared/public/index.html} +0 -0
- data/examples/{soapbox → shared}/public/jquery.js +0 -0
- data/examples/shared/public/robots.txt +0 -0
- data/examples/{soapbox → shared}/public/soapbox.js +0 -0
- data/examples/{soapbox → shared}/public/style.css +0 -0
- data/jake.yml +24 -9
- data/lib/faye-client-min.js +1 -0
- data/lib/faye.rb +2 -2
- data/lib/faye/rack_adapter.rb +44 -12
- data/lib/faye/server.rb +38 -31
- metadata +44 -23
- data/client/channel.js +0 -135
- data/client/client.js +0 -265
- data/client/faye.js +0 -95
- data/client/transport.js +0 -91
- data/client/util/class.js +0 -20
- data/client/util/event.js +0 -44
- data/client/util/json.js +0 -479
- data/client/util/uri.js +0 -69
- data/client/util/xhr.js +0 -99
- data/examples/soapbox/README +0 -22
- data/examples/soapbox/app.rb +0 -8
- data/lib/faye-min.js +0 -1
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/jake.yml
CHANGED
@@ -1,19 +1,34 @@
|
|
1
1
|
---
|
2
|
-
source_directory:
|
3
|
-
build_directory:
|
2
|
+
source_directory: javascript
|
3
|
+
build_directory: build
|
4
4
|
builds:
|
5
|
+
src:
|
6
|
+
packer: false
|
7
|
+
suffix: false
|
5
8
|
min:
|
6
9
|
shrink_vars: true
|
7
10
|
private: true
|
8
11
|
packages:
|
9
|
-
|
12
|
+
core:
|
10
13
|
- faye
|
11
14
|
- util/class
|
12
|
-
- util/
|
13
|
-
- util/uri
|
14
|
-
- util/xhr
|
15
|
+
- util/observable
|
15
16
|
- channel
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
faye:
|
18
|
+
extends: core
|
19
|
+
files:
|
20
|
+
- util/set
|
21
|
+
- server
|
22
|
+
- connection
|
23
|
+
- error
|
24
|
+
- node_adapter
|
25
|
+
faye-client:
|
26
|
+
extends: core
|
27
|
+
files:
|
28
|
+
- util/event
|
29
|
+
- util/uri
|
30
|
+
- util/xhr
|
31
|
+
- transport
|
32
|
+
- client
|
33
|
+
- util/json
|
19
34
|
|
@@ -0,0 +1 @@
|
|
1
|
+
if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(b.hasOwnProperty(d)&&a[d]!==b[d]){if(!a.hasOwnProperty(d)||c!==false)a[d]=b[d]}}return a};Faye.extend(Faye,{BAYEUX_VERSION:'1.0',VERSION:'0.2.2',JSONP_CALLBACK:'jsonpcallback',ID_LENGTH:128,CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},size:function(a){var b=0;this.each(a,function(){b+=1});return b},random:function(){var a=Math.pow(2,this.ID_LENGTH);return(Math.random()*a).toString(16).replace(/0*$/,'')},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Observable={on:function(a,b,c){this._1=this._1||{};var d=this._1[a]=this._1[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._1||!this._1[a])return;if(!b){delete this._1[a];return}var d=this._1[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._1||!this._1[c])return;Faye.each(this._1[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this._A=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._3=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._3!==undefined)d.call(f,c,this._3)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._3:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._3=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._3===undefined)?[]:[this._3];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._3!==undefined)g.push(b._3)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._3);return g}})});Faye.Event={_a:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._a.push({_b:a,_h:b,_s:c,_c:d,_m:f})},detach:function(a,b,c,d){var f=this._a.length,g;while(f--){g=this._a[f];if((a&&a!==g._b)||(b&&b!==g._h)||(c&&c!==g._s)||(d&&d!==g._c))continue;if(g._b.removeEventListener)g._b.removeEventListener(g._h,g._m,false);else g._b.detachEvent('on'+g._h,g._m);this._a.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._d=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._t=(typeof d==='function')?{success:d}:d;this._c=f||null;this._2=null},send:function(){if(this._i)return;var a=this._6.pathname,b=this._6.queryString();if(this._d==='GET')a+='?'+b;var c=this._d==='POST'?b:'';this._i=true;this._2=Faye.XHR.getXhrObject();this._2.open(this._d,a,true);if(this._d==='POST')this._2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._2.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._i=false;d._u();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._2.send(c)},abort:function(){this._2.abort()},_u:function(){var a=this._t;if(!a)return;return this.success()?a.success&&a.success.call(this._c,this):a.failure&&a.failure.call(this._c,this)},waiting:function(){return!!this._i},complete:function(){return this._2&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._2.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._2.responseText},status:function(){if(!this.complete())return null;return this._2.status}})};Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._n=a;this._6=b},send:function(c,d,f){c={message:JSON.stringify(c)};return this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){d.call(f,a);if(a.advice)this._n._v(a.advice);if(a.data&&a.channel)this._n._w(a)},this)},this)}}),{get:function(a,b){var c=a._6;if(b===undefined)b=this.supportedConnectionTypes();var d=Faye.URI.parse(c).isLocal()?['long-polling','callback-polling']:['callback-polling'];var f=Faye.commonElement(d,b);if(!f)throw'Could not find a usable connection type for '+c;var g=this._j[f];return new g(a,c)},register:function(a,b){this._j[a]=b;b.prototype.connectionType=a},_j:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._j,function(a,b){c.push(a)});return c}});Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._6,b,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f=document.getElementsByTagName('head')[0],g=document.createElement('script'),k=Faye.JSONPTransport.getCallbackName(),i=Faye.URI.parse(this._6,b);Faye.ENV[k]=function(a){Faye.ENV[k]=undefined;try{delete Faye.ENV[k]}catch(e){}f.removeChild(g);if(c)c.call(d,a)};i.params.jsonp=k;g.type='text/javascript';g.src=i.toURL();f.appendChild(g)}}),{_o:0,getCallbackName:function(){this._o+=1;return'__jsonp'+this._o+'__'}});Faye.Transport.register('callback-polling',Faye.JSONPTransport);Faye.Client=Faye.Class({_e:{},_x:{},_8:{},_y:{},_p:'handshake',_z:'retry',_q:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._0=this._e;this._k=[];this._f=new Faye.Channel.Tree();this._7={reconnect:this._z,interval:this.INTERVAL};Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this._q)return;if(this._0!==this._e)return;this._0=this._x;var d=this,f=this.generateId();this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes(),id:f},function(a){if(a.id!==f)return;if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._0=this._e}this._0=this._8;this._9=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this._q)return;if(this._7.reconnect===this._p||this._0===this._e)return this.handshake(function(){this.connect(b,c)},this);if(this._0!==this._8)return;if(this._g)return;this._g=this.generateId();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._9,connectionType:this._4.connectionType,id:this._g},function(a){if(a.id!==this._g)return;delete this._g;if(a.successful)this.connect();else setTimeout(function(){d.connect()},this._7.interval)},this);if(b)b.call(c)},disconnect:function(){if(this._0!==this._8)return;this._0=this._y;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._9});this._f=new Faye.Channel.Tree()},subscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,[d,f])},this)},this)},unsubscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,null)},this)},this)},publish:function(a,b){if(this._0!==this._8)return;this._l([a]);this.enqueue({channel:a,data:b,clientId:this._9});if(this._r)return;var c=this;this._r=setTimeout(function(){delete c._r;c.flush()},this.MAX_DELAY*1000)},generateId:function(a){a=a||32;return Math.floor(Math.pow(2,a)*Math.random()).toString(16)},enqueue:function(a){this._k.push(a)},flush:function(){this._4.send(this._k);this._k=[]},_l:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})},_v:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this._p)this._9=null},_w:function(b){var c=this._f.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})}});if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());
|
data/lib/faye.rb
CHANGED
@@ -5,10 +5,10 @@ require 'rubygems'
|
|
5
5
|
require 'eventmachine'
|
6
6
|
|
7
7
|
module Faye
|
8
|
-
VERSION = '0.
|
8
|
+
VERSION = '0.2.2'
|
9
9
|
|
10
10
|
ROOT = File.expand_path(File.dirname(__FILE__))
|
11
|
-
CLIENT_SCRIPT = File.join(ROOT, 'faye-min.js')
|
11
|
+
CLIENT_SCRIPT = File.join(ROOT, 'faye-client-min.js')
|
12
12
|
|
13
13
|
BAYEUX_VERSION = '1.0'
|
14
14
|
ID_LENGTH = 128
|
data/lib/faye/rack_adapter.rb
CHANGED
@@ -4,6 +4,10 @@ require 'json'
|
|
4
4
|
|
5
5
|
module Faye
|
6
6
|
class RackAdapter
|
7
|
+
|
8
|
+
# Only supported under Thin
|
9
|
+
ASYNC_RESPONSE = [-1, {}, []].freeze
|
10
|
+
|
7
11
|
DEFAULT_ENDPOINT = '/bayeux'
|
8
12
|
|
9
13
|
TYPE_JSON = {'Content-Type' => 'text/json'}
|
@@ -24,19 +28,20 @@ module Faye
|
|
24
28
|
case request.path_info
|
25
29
|
|
26
30
|
when @endpoint then
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
begin
|
32
|
+
message = JSON.parse(request.params['message'])
|
33
|
+
jsonp = request.params['jsonp'] || JSONP_CALLBACK
|
34
|
+
|
35
|
+
@server.flush_connection(message) if request.get?
|
36
|
+
|
37
|
+
on_response(env, message) do |replies|
|
38
|
+
response = JSON.unparse(replies)
|
39
|
+
response = "#{ jsonp }(#{ response });" if request.get?
|
40
|
+
response
|
41
|
+
end
|
42
|
+
rescue
|
43
|
+
[400, {'Content-Type' => 'text/plain'}, 'Bad request']
|
35
44
|
end
|
36
|
-
|
37
|
-
# TODO support Thin's async responses
|
38
|
-
sleep(0.1) while response.nil?
|
39
|
-
[200, type, [response]]
|
40
45
|
|
41
46
|
when @script then
|
42
47
|
[200, TYPE_SCRIPT, File.new(CLIENT_SCRIPT)]
|
@@ -48,6 +53,33 @@ module Faye
|
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
56
|
+
private
|
57
|
+
|
58
|
+
def on_response(env, message, &block)
|
59
|
+
request = Rack::Request.new(env)
|
60
|
+
type = request.get? ? TYPE_SCRIPT : TYPE_JSON
|
61
|
+
callback = env['async.callback']
|
62
|
+
|
63
|
+
EM.run unless EM.reactor_running?
|
64
|
+
|
65
|
+
if callback
|
66
|
+
body = DeferredBody.new
|
67
|
+
callback.call [200, type, body]
|
68
|
+
@server.process(message, false) { |r| body.succeed block.call(r) }
|
69
|
+
return ASYNC_RESPONSE
|
70
|
+
end
|
71
|
+
|
72
|
+
response = nil
|
73
|
+
@server.process(message, false) { |r| response = block.call(r) }
|
74
|
+
sleep(0.1) while response.nil?
|
75
|
+
[200, type, [response]]
|
76
|
+
end
|
77
|
+
|
78
|
+
class DeferredBody
|
79
|
+
include EventMachine::Deferrable
|
80
|
+
alias :each :callback
|
81
|
+
end
|
82
|
+
|
51
83
|
end
|
52
84
|
end
|
53
85
|
|
data/lib/faye/server.rb
CHANGED
@@ -4,7 +4,16 @@ module Faye
|
|
4
4
|
@options = options
|
5
5
|
@channels = Channel::Tree.new
|
6
6
|
@clients = {}
|
7
|
-
|
7
|
+
end
|
8
|
+
|
9
|
+
# Notifies the server of stale connections that should be deleted
|
10
|
+
def update(message, client)
|
11
|
+
return unless message == :stale_client
|
12
|
+
destroy_client(client)
|
13
|
+
end
|
14
|
+
|
15
|
+
def client_ids
|
16
|
+
@clients.keys
|
8
17
|
end
|
9
18
|
|
10
19
|
def process(messages, local = false, &callback)
|
@@ -21,6 +30,34 @@ module Faye
|
|
21
30
|
end
|
22
31
|
end
|
23
32
|
|
33
|
+
def flush_connection(messages)
|
34
|
+
[messages].flatten.each do |message|
|
35
|
+
client = @clients[message['clientId']]
|
36
|
+
client.flush! if client
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def generate_id
|
43
|
+
id = Faye.random
|
44
|
+
id = Faye.random while @clients.has_key?(id)
|
45
|
+
connection(id).id
|
46
|
+
end
|
47
|
+
|
48
|
+
def connection(id)
|
49
|
+
return @clients[id] if @clients.has_key?(id)
|
50
|
+
client = Connection.new(id, @options)
|
51
|
+
client.add_observer(self)
|
52
|
+
@clients[id] = client
|
53
|
+
end
|
54
|
+
|
55
|
+
def destroy_client(client)
|
56
|
+
client.disconnect!
|
57
|
+
client.delete_observer(self)
|
58
|
+
@clients.delete(client.id)
|
59
|
+
end
|
60
|
+
|
24
61
|
def handle(message, local = false, &callback)
|
25
62
|
client_id = message['clientId']
|
26
63
|
channel = message['channel']
|
@@ -196,36 +233,6 @@ module Faye
|
|
196
233
|
response
|
197
234
|
end
|
198
235
|
|
199
|
-
# Notifies the server of stale connections that should be deleted
|
200
|
-
def update(message, client)
|
201
|
-
return unless message == :stale_client
|
202
|
-
destroy_client(client)
|
203
|
-
end
|
204
|
-
|
205
|
-
def client_ids
|
206
|
-
@clients.keys
|
207
|
-
end
|
208
|
-
|
209
|
-
private
|
210
|
-
|
211
|
-
def generate_id
|
212
|
-
id = Faye.random
|
213
|
-
id = Faye.random while @clients.has_key?(id)
|
214
|
-
connection(id).id
|
215
|
-
end
|
216
|
-
|
217
|
-
def connection(id)
|
218
|
-
return @clients[id] if @clients.has_key?(id)
|
219
|
-
client = Connection.new(id, @options)
|
220
|
-
client.add_observer(self)
|
221
|
-
@clients[id] = client
|
222
|
-
end
|
223
|
-
|
224
|
-
def destroy_client(client)
|
225
|
-
client.disconnect!
|
226
|
-
client.delete_observer(self)
|
227
|
-
@clients.delete(client.id)
|
228
|
-
end
|
229
236
|
end
|
230
237
|
end
|
231
238
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faye
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Coglan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-02-11 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,6 +42,26 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: "0"
|
44
44
|
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rubyforge
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.0.3
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: gemcutter
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.3.0
|
64
|
+
version:
|
45
65
|
- !ruby/object:Gem::Dependency
|
46
66
|
name: hoe
|
47
67
|
type: :development
|
@@ -50,7 +70,7 @@ dependencies:
|
|
50
70
|
requirements:
|
51
71
|
- - ">="
|
52
72
|
- !ruby/object:Gem::Version
|
53
|
-
version: 2.
|
73
|
+
version: 2.5.0
|
54
74
|
version:
|
55
75
|
description: ""
|
56
76
|
email:
|
@@ -63,6 +83,7 @@ extra_rdoc_files:
|
|
63
83
|
- History.txt
|
64
84
|
- Manifest.txt
|
65
85
|
- README.txt
|
86
|
+
- examples/shared/public/robots.txt
|
66
87
|
files:
|
67
88
|
- History.txt
|
68
89
|
- Manifest.txt
|
@@ -70,16 +91,21 @@ files:
|
|
70
91
|
- Rakefile
|
71
92
|
- jake.yml
|
72
93
|
- Jakefile
|
73
|
-
-
|
74
|
-
- client
|
75
|
-
-
|
76
|
-
-
|
77
|
-
-
|
78
|
-
-
|
79
|
-
-
|
80
|
-
-
|
81
|
-
-
|
82
|
-
-
|
94
|
+
- build/faye.js
|
95
|
+
- build/faye-client-min.js
|
96
|
+
- examples/README.rdoc
|
97
|
+
- examples/shared/public/index.html
|
98
|
+
- examples/shared/public/favicon.ico
|
99
|
+
- examples/shared/public/jquery.js
|
100
|
+
- examples/shared/public/robots.txt
|
101
|
+
- examples/shared/public/soapbox.js
|
102
|
+
- examples/shared/public/style.css
|
103
|
+
- examples/node/app.js
|
104
|
+
- examples/node/faye.js
|
105
|
+
- examples/node/faye-client-min.js
|
106
|
+
- examples/rack/app.rb
|
107
|
+
- examples/rack/config.ru
|
108
|
+
- lib/faye-client-min.js
|
83
109
|
- lib/faye.rb
|
84
110
|
- lib/faye/channel.rb
|
85
111
|
- lib/faye/connection.rb
|
@@ -87,18 +113,13 @@ files:
|
|
87
113
|
- lib/faye/grammar.rb
|
88
114
|
- lib/faye/rack_adapter.rb
|
89
115
|
- lib/faye/server.rb
|
90
|
-
- examples/soapbox/README
|
91
|
-
- examples/soapbox/app.rb
|
92
|
-
- examples/soapbox/config.ru
|
93
|
-
- examples/soapbox/public/jquery.js
|
94
|
-
- examples/soapbox/public/soapbox.js
|
95
|
-
- examples/soapbox/public/style.css
|
96
|
-
- examples/soapbox/views/index.erb
|
97
116
|
- test/test_channel.rb
|
98
117
|
- test/test_grammar.rb
|
99
118
|
- test/test_server.rb
|
100
119
|
has_rdoc: true
|
101
120
|
homepage: http://github.com/jcoglan/faye
|
121
|
+
licenses: []
|
122
|
+
|
102
123
|
post_install_message:
|
103
124
|
rdoc_options:
|
104
125
|
- --main
|
@@ -120,11 +141,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
141
|
requirements: []
|
121
142
|
|
122
143
|
rubyforge_project: faye
|
123
|
-
rubygems_version: 1.3.
|
144
|
+
rubygems_version: 1.3.5
|
124
145
|
signing_key:
|
125
|
-
specification_version:
|
146
|
+
specification_version: 3
|
126
147
|
summary: ""
|
127
148
|
test_files:
|
149
|
+
- test/test_grammar.rb
|
128
150
|
- test/test_server.rb
|
129
151
|
- test/test_channel.rb
|
130
|
-
- test/test_grammar.rb
|
data/client/channel.js
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
Faye.Channel = {
|
2
|
-
HANDSHAKE: '<%= Faye::Channel::HANDSHAKE %>',
|
3
|
-
CONNECT: '<%= Faye::Channel::CONNECT %>',
|
4
|
-
SUBSCRIBE: '<%= Faye::Channel::SUBSCRIBE %>',
|
5
|
-
UNSUBSCRIBE: '<%= Faye::Channel::UNSUBSCRIBE %>',
|
6
|
-
DISCONNECT: '<%= Faye::Channel::DISCONNECT %>',
|
7
|
-
|
8
|
-
META: '<%= Faye::Channel::META %>',
|
9
|
-
SERVICE: '<%= Faye::Channel::SERVICE %>',
|
10
|
-
|
11
|
-
isValid: function(name) {
|
12
|
-
return Faye.Grammar.CHANNEL_NAME.test(name) ||
|
13
|
-
Faye.Grammar.CHANNEL_PATTERN.test(name);
|
14
|
-
},
|
15
|
-
|
16
|
-
parse: function(name) {
|
17
|
-
if (!this.isValid(name)) return null;
|
18
|
-
return name.split('/').slice(1);
|
19
|
-
},
|
20
|
-
|
21
|
-
isMeta: function(name) {
|
22
|
-
var segments = this.parse(name);
|
23
|
-
return segments ? (segments[0] === this.META) : null;
|
24
|
-
},
|
25
|
-
|
26
|
-
isService: function(name) {
|
27
|
-
var segments = this.parse(name);
|
28
|
-
return segments ? (segments[0] === this.SERVICE) : null;
|
29
|
-
},
|
30
|
-
|
31
|
-
isSubscribable: function(name) {
|
32
|
-
if (!this.isValid(name)) return null;
|
33
|
-
return !this.isMeta(name) && !this.isService(name);
|
34
|
-
},
|
35
|
-
|
36
|
-
Tree: Faye.Class({
|
37
|
-
initialize: function(value) {
|
38
|
-
this._value = value;
|
39
|
-
this._children = {};
|
40
|
-
},
|
41
|
-
|
42
|
-
eachChild: function(block, context) {
|
43
|
-
Faye.each(this._children, function(key, subtree) {
|
44
|
-
block.call(context, key, subtree);
|
45
|
-
});
|
46
|
-
},
|
47
|
-
|
48
|
-
each: function(prefix, block, context) {
|
49
|
-
this.eachChild(function(path, subtree) {
|
50
|
-
path = prefix.concat(path);
|
51
|
-
subtree.each(path, block, context);
|
52
|
-
});
|
53
|
-
if (this._value !== undefined) block.call(context, prefix, this._value);
|
54
|
-
},
|
55
|
-
|
56
|
-
map: function(block, context) {
|
57
|
-
var result = [];
|
58
|
-
this.each([], function(path, value) {
|
59
|
-
result.push(block.call(context, path, value));
|
60
|
-
});
|
61
|
-
return result;
|
62
|
-
},
|
63
|
-
|
64
|
-
get: function(name) {
|
65
|
-
var tree = this.traverse(name);
|
66
|
-
return tree ? tree._value : null;
|
67
|
-
},
|
68
|
-
|
69
|
-
set: function(name, value) {
|
70
|
-
var subtree = this.traverse(name, true);
|
71
|
-
if (subtree) subtree._value = value;
|
72
|
-
},
|
73
|
-
|
74
|
-
traverse: function(path, createIfAbsent) {
|
75
|
-
if (typeof path === 'string') path = Faye.Channel.parse(path);
|
76
|
-
|
77
|
-
if (path === null) return null;
|
78
|
-
if (path.length === 0) return this;
|
79
|
-
|
80
|
-
var subtree = this._children[path[0]];
|
81
|
-
if (!subtree && !createIfAbsent) return null;
|
82
|
-
if (!subtree) subtree = this._children[path[0]] = new Faye.Channel.Tree();
|
83
|
-
|
84
|
-
return subtree.traverse(path.slice(1), createIfAbsent);
|
85
|
-
},
|
86
|
-
|
87
|
-
glob: function(path) {
|
88
|
-
if (typeof path === 'string') path = Faye.Channel.parse(path);
|
89
|
-
|
90
|
-
if (path === null) return [];
|
91
|
-
if (path.length === 0) return (this._value === undefined) ? [] : [this._value];
|
92
|
-
|
93
|
-
var list = [];
|
94
|
-
|
95
|
-
if (Faye.enumEqual(path, ['*'])) {
|
96
|
-
Faye.each(this._children, function(key, subtree) {
|
97
|
-
if (subtree._value !== undefined) list.push(subtree._value);
|
98
|
-
});
|
99
|
-
return list;
|
100
|
-
}
|
101
|
-
|
102
|
-
if (Faye.enumEqual(path, ['**'])) {
|
103
|
-
list = this.map(function(key, value) { return value });
|
104
|
-
list.pop();
|
105
|
-
return list;
|
106
|
-
}
|
107
|
-
|
108
|
-
Faye.each(this._children, function(key, subtree) {
|
109
|
-
if (key !== path[0] && key !== '*') return;
|
110
|
-
var sublist = subtree.glob(path.slice(1));
|
111
|
-
Faye.each(sublist, function(channel) { list.push(channel) });
|
112
|
-
});
|
113
|
-
|
114
|
-
if (this._children['**']) list.push(this._children['**']._value);
|
115
|
-
return list;
|
116
|
-
}
|
117
|
-
|
118
|
-
/**
|
119
|
-
Tests
|
120
|
-
|
121
|
-
glob = new Faye.Channel.Tree();
|
122
|
-
list = '/foo/bar /foo/boo /foo /foobar /foo/bar/boo /foobar/boo /foo/* /foo/**'.split(' ');
|
123
|
-
|
124
|
-
Faye.each(list, function(c, i) {
|
125
|
-
glob.set(c, i + 1);
|
126
|
-
});
|
127
|
-
|
128
|
-
console.log(glob.glob('/foo/*').sort()); // 1,2,7,8
|
129
|
-
console.log(glob.glob('/foo/bar').sort()); // 1,7,8
|
130
|
-
console.log(glob.glob('/foo/**').sort()); // 1,2,5,7,8
|
131
|
-
console.log(glob.glob('/foo/bar/boo').sort()); // 5,8
|
132
|
-
**/
|
133
|
-
})
|
134
|
-
};
|
135
|
-
|