faye 0.3.4 → 0.5.0

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

Potentially problematic release.


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

Files changed (49) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +16 -33
  3. data/README.txt +9 -274
  4. data/Rakefile +4 -4
  5. data/lib/faye-browser-min.js +1 -0
  6. data/lib/faye.rb +26 -9
  7. data/lib/faye/{rack_adapter.rb → adapters/rack_adapter.rb} +38 -25
  8. data/lib/faye/error.rb +0 -7
  9. data/lib/faye/{logging.rb → mixins/logging.rb} +0 -0
  10. data/lib/faye/mixins/publisher.rb +29 -0
  11. data/lib/faye/{timeouts.rb → mixins/timeouts.rb} +1 -0
  12. data/lib/faye/{transport.rb → network/transport.rb} +32 -43
  13. data/lib/faye/{channel.rb → protocol/channel.rb} +23 -3
  14. data/lib/faye/{client.rb → protocol/client.rb} +124 -90
  15. data/lib/faye/{connection.rb → protocol/connection.rb} +41 -23
  16. data/lib/faye/protocol/extensible.rb +47 -0
  17. data/lib/faye/{grammar.rb → protocol/grammar.rb} +0 -0
  18. data/lib/faye/{server.rb → protocol/server.rb} +98 -54
  19. data/lib/faye/protocol/subscription.rb +23 -0
  20. data/lib/faye/{namespace.rb → util/namespace.rb} +0 -0
  21. data/lib/faye/util/web_socket.rb +119 -0
  22. data/lib/thin_extensions.rb +86 -0
  23. data/test/scenario.rb +68 -14
  24. data/test/test_clients.rb +215 -2
  25. data/test/test_server.rb +10 -10
  26. metadata +102 -71
  27. data/Jakefile +0 -13
  28. data/build/faye-client-min.js +0 -1
  29. data/build/faye.js +0 -1488
  30. data/examples/README.rdoc +0 -41
  31. data/examples/node/app.js +0 -26
  32. data/examples/node/client.js +0 -23
  33. data/examples/node/faye-client-min.js +0 -1
  34. data/examples/node/faye.js +0 -1488
  35. data/examples/rack/app.rb +0 -16
  36. data/examples/rack/client.rb +0 -25
  37. data/examples/rack/config.ru +0 -8
  38. data/examples/shared/public/favicon.ico +0 -0
  39. data/examples/shared/public/index.html +0 -49
  40. data/examples/shared/public/jquery.js +0 -19
  41. data/examples/shared/public/mootools.js +0 -4329
  42. data/examples/shared/public/prototype.js +0 -4874
  43. data/examples/shared/public/robots.txt +0 -0
  44. data/examples/shared/public/soapbox.js +0 -100
  45. data/examples/shared/public/style.css +0 -43
  46. data/jake.yml +0 -40
  47. data/lib/faye-client-min.js +0 -1
  48. data/test/scenario.js +0 -138
  49. data/test/test_clients.js +0 -195
@@ -1,41 +0,0 @@
1
- = Soapbox -- a Twitter-style chat app
2
-
3
- Soapbox is a chat app written using Faye and jQuery, with functionality
4
- modelled on that of Twitter. You can pick a username, type in some users
5
- to follow, and enter messages. You receive messages from anyone you're
6
- following, and any messages that mention you using the <tt>@username</tt>
7
- syntax.
8
-
9
-
10
- == Running the demo
11
-
12
- There are two backends that handle message routing; one for Node.js
13
- and one for Rack. To run the Node.js version:
14
-
15
- node examples/node/app.js
16
-
17
- To run the Rack version you need a few gems first:
18
-
19
- sudo gem install eventmachine rack json sinatra
20
- rackup -s mongrel examples/rack/config.ru
21
-
22
- You can also use Thin to run the app as long as <tt>Rack::Lint</tt>
23
- is not being used (it complains about the status codes Thin uses
24
- for async responses).
25
-
26
- rackup -s thin -E production examples/rack/config.ru
27
-
28
- Note that Faye does not depend on Sinatra; the demo just uses it to
29
- provide a concrete app behind the Faye middleware.
30
-
31
-
32
- == Source code
33
-
34
- There is no server-side logic for this app; the Faye server simply
35
- handles message routing between clients and all subscriptions are set
36
- up on the client side. Since this is a simple demo of client-side
37
- messaging, your username and followees are not persisted across page
38
- reloads. The source code for the client is at:
39
-
40
- shared/public/soapbox.js
41
-
@@ -1,26 +0,0 @@
1
- var fs = require('fs'),
2
- path = require('path'),
3
- sys = require('sys'),
4
- http = require('http'),
5
- faye = require('./faye');
6
-
7
- var PUBLIC_DIR = path.dirname(__filename) + '/../shared/public',
8
- comet = new faye.NodeAdapter({mount: '/comet', timeout: 45}),
9
-
10
- port = process.ARGV[2] || '8000';
11
-
12
- sys.puts('Listening on ' + port);
13
-
14
- http.createServer(function(request, response) {
15
- sys.puts(request.method + ' ' + request.url);
16
- if (comet.call(request, response)) return;
17
-
18
- var path = (request.url === '/') ? '/index.html' : request.url;
19
-
20
- fs.readFile(PUBLIC_DIR + path, function(err, content) {
21
- response.writeHead(200, {'Content-Type': 'text/html'});
22
- response.write(content);
23
- response.end();
24
- });
25
- }).listen(Number(port));
26
-
@@ -1,23 +0,0 @@
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 +0,0 @@
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.4',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}},toJSON:function(a){if(this.stringify)return this.stringify(a,function(key,value){return(this[key]instanceof Array)?this[key]:value});return JSON.stringify(a)},timestamp:function(){var b=new Date(),c=b.getFullYear(),d=b.getMonth()+1,f=b.getDate(),g=b.getHours(),j=b.getMinutes(),i=b.getSeconds();var h=function(a){return a<10?'0'+a:String(a)};return h(c)+'-'+h(d)+'-'+h(f)+' '+h(g)+':'+h(j)+':'+h(i)}});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.Deferrable={callback:function(a,b){if(this._v==='succeeded')return a.apply(b,this._o);this._a=this._a||[];this._a.push([a,b])},setDeferredStatus:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();this._v=c;this._o=b;if(c!=='succeeded')return;if(!this._a)return;Faye.each(this._a,function(a){a[0].apply(a[1],this._o)},this);this._a=[]}};Faye.Observable={on:function(a,b,c){this._2=this._2||{};var d=this._2[a]=this._2[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._2||!this._2[a])return;if(!b){delete this._2[a];return}var d=this._2[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},trigger:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._2||!this._2[c])return;Faye.each(this._2[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Logging={LOG_LEVELS:{error:3,warn:2,info:1,debug:0},logLevel:'error',log:function(a,b){if(!Faye.logger)return;var c=Faye.Logging.LOG_LEVELS;if(c[Faye.Logging.logLevel]>c[b])return;var a=Array.prototype.slice.apply(a),d=' ['+b.toUpperCase()+'] [Faye',f=null,g=a.shift().replace(/\?/g,function(){return Faye.toJSON(a.shift())});for(var j in Faye){if(f)continue;if(typeof Faye[j]!=='function')continue;if(this instanceof Faye[j])f=j}if(f)d+='.'+f;d+='] ';Faye.logger(Faye.timestamp()+d+g)}};Faye.each(Faye.Logging.LOG_LEVELS,function(a,b){Faye.Logging[a]=function(){this.log(arguments,a)}});Faye.Timeouts={addTimeout:function(a,b,c,d){this._6=this._6||{};if(this._6.hasOwnProperty(a))return;var f=this;this._6[a]=setTimeout(function(){delete f._6[a];c.call(d)},1000*b)},removeTimeout:function(a){this._6=this._6||{};var b=this._6[a];if(!b)return;clearTimeout(b);delete this._6[a]}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.trigger('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._8={}},eachChild:function(c,d){Faye.each(this._8,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)},getKeys:function(){return this.map(function(a,b){return'/'+a.join('/')})},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._8[a[0]];if(!c&&!b)return null;if(!c)c=this._8[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._8,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});if(this._3!==undefined)g.pop();return g}Faye.each(this._8,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._8['**'])g.push(this._8['**']._3);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._p={}},generate:function(){var a=Faye.random();while(this._p.hasOwnProperty(a))a=Faye.random();return this._p[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this.debug('Created new transport for ?',b);this._b=a;this._4=b},send:function(f,g,j){if(!(f instanceof Array)&&!f.id)f.id=this._b._q.generate();this.debug('Client ? sending message to ?: ?',this._b._0,this._4,f);this.request(f,function(b){this.debug('Client ? received from ?: ?',this._b._0,this._4,b);if(!g)return;var c=[],d=true;Faye.each([].concat(b),function(a){if(a.id===f.id){if(g.call(j,a)===false)d=false}if(a.advice)this._b.handleAdvice(a.advice);if(a.data&&a.channel)c.push(a)},this);if(d)this._b.deliverMessages(c)},this)}}),{get:function(c,d){var f=c._4;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._i,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._i[a]=b;b.prototype.connectionType=a},_i:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._i,function(a,b){c.push(a)});return c}});Faye.extend(Faye.Transport.prototype,Faye.Logging);Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',CONNECTION_TIMEOUT:60.0,DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a,b){this.info('New client created for ?',a);this._4=a||this.DEFAULT_ENDPOINT;this._w=b||{};this._r=this._w.timeout||this.CONNECTION_TIMEOUT;this._7=Faye.Transport.get(this);this._1=this.UNCONNECTED;this._q=new Faye.Namespace();this._j=[];this._c=new Faye.Channel.Tree();this._9={reconnect:this.RETRY,interval:this.INTERVAL};if(Faye.Event)Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1!==this.UNCONNECTED)return;this._1=this.CONNECTING;var d=this;this.info('Initiating handshake with ?',this._4);this._7.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(a.successful){this._1=this.CONNECTED;this._0=a.clientId;this._7=Faye.Transport.get(this,a.supportedConnectionTypes);this.info('Handshake successful: ?',this._0);if(b)b.call(c)}else{this.info('Handshake unsuccessful');setTimeout(function(){d.handshake(b,c)},this._9.interval);this._1=this.UNCONNECTED}},this)},connect:function(b,c){if(this._9.reconnect===this.NONE)return;if(this._1===this.DISCONNECTED)return;if(this._9.reconnect===this.HANDSHAKE||this._1===this.UNCONNECTED){this._s();return this.handshake(function(){this.connect(b,c)},this)}if(this._1===this.CONNECTING)return this.callback(b,c);if(this._1!==this.CONNECTED)return;this.info('Calling deferred actions for ?',this._0);this.setDeferredStatus('succeeded');this.setDeferredStatus('deferred');if(b)b.call(c);if(this._d)return;this._d=this._q.generate();var d=this;this.info('Initiating connection for ?',this._0);this._7.send({channel:Faye.Channel.CONNECT,clientId:this._0,connectionType:this._7.connectionType,id:this._d},this._k(function(a){this._d=null;this.removeTimeout('reconnect');this.info('Closed connection for ?',this._0);setTimeout(function(){d.connect()},this._9.interval)}));this._s()},disconnect:function(){if(this._1!==this.CONNECTED)return;this._1=this.DISCONNECTED;this.info('Disconnecting ?',this._0);this._7.send({channel:Faye.Channel.DISCONNECT,clientId:this._0});this.info('Clearing channel listeners for ?',this._0);this._c=new Faye.Channel.Tree();this.removeTimeout('reconnect')},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client ? attempting to subscribe to ?',this._0,c);this._7.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful||!d)return;this.info('Subscription acknowledged for ? to ?',this._0,c);c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,[d,f])},this)}))},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._l(c);this.info('Client ? attempting to unsubscribe from ?',this._0,c);this._7.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._0,subscription:c},this._k(function(b){if(!b.successful)return;this.info('Unsubscription acknowledged for ? from ?',this._0,c);c=[].concat(b.subscription);Faye.each(c,function(a){this._c.set(a,undefined)},this)}))},this)},publish:function(a,b){this.connect(function(){this._l([a]);this.info('Client ? queueing published message to ?: ?',this._0,a,b);this._x({channel:a,data:b,clientId:this._0});this.addTimeout('publish',this.MAX_DELAY,this._y,this)},this)},handleAdvice:function(a){Faye.extend(this._9,a);if(this._9.reconnect===this.HANDSHAKE)this._0=null},deliverMessages:function(d){Faye.each(d,function(b){this.info('Client ? calling listeners for ? with ?',this._0,b.channel,b.data);var c=this._c.glob(b.channel);Faye.each(c,function(a){a[0].call(a[1],b.data)})},this)},_s:function(){this.addTimeout('reconnect',this._r,function(){this._d=null;this._0=null;this._1=this.UNCONNECTED;this.info('Server took >?s to reply to connection for ?: attempting to reconnect',this._r,this._0);this.subscribe(this._c.getKeys())},this)},_x:function(a){this._j.push(a)},_y:function(){this._7.send(this._j);this._j=[]},_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+'"';})},_k:function(b){var c=this;return function(a){if(a.clientId!==c._0)return false;b.call(c,a);return true}}});Faye.extend(Faye.Client.prototype,Faye.Deferrable);Faye.extend(Faye.Client.prototype,Faye.Timeouts);Faye.extend(Faye.Client.prototype,Faye.Logging);Faye.Event={_e:[],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._e.push({_f:a,_m:b,_z:c,_g:d,_t:f})},detach:function(a,b,c,d){var f=this._e.length,g;while(f--){g=this._e[f];if((a&&a!==g._f)||(b&&b!==g._m)||(c&&c!==g._z)||(d&&d!==g._g))continue;if(g._f.removeEventListener)g._f.removeEventListener(g._m,g._t,false);else g._f.detachEvent('on'+g._m,g._t);this._e.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 j=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};j('protocol',/^https?\:\/+/);j('hostname',/^[^\/\:]+/);j('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,k={};while(o--){i=n[o].split('=');k[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}if(typeof f==='object')Faye.extend(k,f);g.pathname=h;g.params=k;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._h=a.toUpperCase();this._4=Faye.URI.parse(b,c);this._A=(typeof c==='string')?c:null;this._B=(typeof d==='function')?{success:d}:d;this._g=f||null;this._5=null},send:function(){if(this._n)return;var a=this._4.pathname,b=this._4.queryString();if(this._h==='GET')a+='?'+b;var c=(this._h==='POST')?(this._A||b):'';this._n=true;this._5=Faye.XHR.getXhrObject();this._5.open(this._h,a,true);if(this._h==='POST')this._5.setRequestHeader('Content-Type','application/json');var d=this,f=function(){if(d._5.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._n=false;d._C();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._5.send(c)},abort:function(){this._5.abort()},_C:function(){var a=this._B;if(!a)return;return this.success()?a.success&&a.success.call(this._g,this):a.failure&&a.failure.call(this._g,this)},waiting:function(){return!!this._n},complete:function(){return this._5&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._5.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._5.responseText},status:function(){if(!this.complete())return null;return this._5.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,k,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,j=k,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'}k+=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?'[]':k?'[\n'+k+i.join(',\n'+k)+'\n'+j+']':'['+i.join(',')+']';k=j;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)+(k?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(k?': ':':')+f)}}}}f=i.length===0?'{}':k?'{\n'+k+i.join(',\n'+k)+'\n'+j+'}':'{'+i.join(',')+'}';k=j;return f}}Faye.stringify=function(a,b,c){var d;k='';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.stringify!=='function'){JSON.stringify=Faye.stringify}if(typeof JSON.parse!=='function'){JSON.parse=function(g,j){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 j.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 j==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._4,Faye.toJSON(b),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:Faye.toJSON(b)},g=document.getElementsByTagName('head')[0],j=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._4,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(j);if(c)c.call(d,a)};h.params.jsonp=i;j.type='text/javascript';j.src=h.toURL();g.appendChild(j)}}),{_u:0,getCallbackName:function(){this._u+=1;return'__jsonp'+this._u+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
@@ -1,1488 +0,0 @@
1
- if (!this.Faye) Faye = {};
2
-
3
- Faye.extend = function(dest, source, overwrite) {
4
- if (!source) return dest;
5
- for (var key in source) {
6
- if (!source.hasOwnProperty(key)) continue;
7
- if (dest.hasOwnProperty(key) && overwrite === false) continue;
8
- if (dest[key] !== source[key])
9
- dest[key] = source[key];
10
- }
11
- return dest;
12
- };
13
-
14
- Faye.extend(Faye, {
15
- VERSION: '0.3.4',
16
-
17
- BAYEUX_VERSION: '1.0',
18
- ID_LENGTH: 128,
19
- JSONP_CALLBACK: 'jsonpcallback',
20
- CONNECTION_TYPES: ["long-polling", "callback-polling"],
21
-
22
- ENV: this,
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
-
36
- Grammar: {
37
-
38
- LOWALPHA: /^[a-z]$/,
39
-
40
- UPALPHA: /^[A-Z]$/,
41
-
42
- ALPHA: /^([a-z]|[A-Z])$/,
43
-
44
- DIGIT: /^[0-9]$/,
45
-
46
- ALPHANUM: /^(([a-z]|[A-Z])|[0-9])$/,
47
-
48
- MARK: /^(\-|\_|\!|\~|\(|\)|\$|\@)$/,
49
-
50
- STRING: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
51
-
52
- TOKEN: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
53
-
54
- INTEGER: /^([0-9])+$/,
55
-
56
- CHANNEL_SEGMENT: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,
57
-
58
- CHANNEL_SEGMENTS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
59
-
60
- CHANNEL_NAME: /^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,
61
-
62
- WILD_CARD: /^\*{1,2}$/,
63
-
64
- CHANNEL_PATTERN: /^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,
65
-
66
- VERSION_ELEMENT: /^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,
67
-
68
- VERSION: /^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,
69
-
70
- CLIENT_ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
71
-
72
- ID: /^((([a-z]|[A-Z])|[0-9]))+$/,
73
-
74
- ERROR_MESSAGE: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,
75
-
76
- ERROR_ARGS: /^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,
77
-
78
- ERROR_CODE: /^[0-9][0-9][0-9]$/,
79
-
80
- 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])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/
81
-
82
- },
83
-
84
- commonElement: function(lista, listb) {
85
- for (var i = 0, n = lista.length; i < n; i++) {
86
- if (this.indexOf(listb, lista[i]) !== -1)
87
- return lista[i];
88
- }
89
- return null;
90
- },
91
-
92
- indexOf: function(list, needle) {
93
- for (var i = 0, n = list.length; i < n; i++) {
94
- if (list[i] === needle) return i;
95
- }
96
- return -1;
97
- },
98
-
99
- each: function(object, callback, scope) {
100
- if (object instanceof Array) {
101
- for (var i = 0, n = object.length; i < n; i++) {
102
- if (object[i] !== undefined)
103
- callback.call(scope || null, object[i], i);
104
- }
105
- } else {
106
- for (var key in object) {
107
- if (object.hasOwnProperty(key))
108
- callback.call(scope || null, key, object[key]);
109
- }
110
- }
111
- },
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
-
122
- size: function(object) {
123
- var size = 0;
124
- this.each(object, function() { size += 1 });
125
- return size;
126
- },
127
-
128
- enumEqual: function(actual, expected) {
129
- if (expected instanceof Array) {
130
- if (!(actual instanceof Array)) return false;
131
- var i = actual.length;
132
- if (i !== expected.length) return false;
133
- while (i--) {
134
- if (actual[i] !== expected[i]) return false;
135
- }
136
- return true;
137
- } else {
138
- if (!(actual instanceof Object)) return false;
139
- if (this.size(expected) !== this.size(actual)) return false;
140
- var result = true;
141
- this.each(actual, function(key, value) {
142
- result = result && (expected[key] === value);
143
- });
144
- return result;
145
- }
146
- },
147
-
148
- // http://assanka.net/content/tech/2009/09/02/json2-js-vs-prototype/
149
- toJSON: function(object) {
150
- if (this.stringify)
151
- return this.stringify(object, function(key, value) {
152
- return (this[key] instanceof Array)
153
- ? this[key]
154
- : value;
155
- });
156
-
157
- return JSON.stringify(object);
158
- },
159
-
160
- timestamp: function() {
161
- var date = new Date(),
162
- year = date.getFullYear(),
163
- month = date.getMonth() + 1,
164
- day = date.getDate(),
165
- hour = date.getHours(),
166
- minute = date.getMinutes(),
167
- second = date.getSeconds();
168
-
169
- var pad = function(n) {
170
- return n < 10 ? '0' + n : String(n);
171
- };
172
-
173
- return pad(year) + '-' + pad(month) + '-' + pad(day) + ' ' +
174
- pad(hour) + ':' + pad(minute) + ':' + pad(second);
175
- }
176
- });
177
-
178
-
179
- Faye.Class = function(parent, methods) {
180
- if (typeof parent !== 'function') {
181
- methods = parent;
182
- parent = Object;
183
- }
184
-
185
- var klass = function() {
186
- if (!this.initialize) return this;
187
- return this.initialize.apply(this, arguments) || this;
188
- };
189
-
190
- var bridge = function() {};
191
- bridge.prototype = parent.prototype;
192
-
193
- klass.prototype = new bridge();
194
- Faye.extend(klass.prototype, methods);
195
-
196
- return klass;
197
- };
198
-
199
-
200
- Faye.Deferrable = {
201
- callback: function(callback, scope) {
202
- if (this._deferredStatus === 'succeeded')
203
- return callback.apply(scope, this._deferredArgs);
204
-
205
- this._waiters = this._waiters || [];
206
- this._waiters.push([callback, scope]);
207
- },
208
-
209
- setDeferredStatus: function() {
210
- var args = Array.prototype.slice.call(arguments),
211
- status = args.shift();
212
-
213
- this._deferredStatus = status;
214
- this._deferredArgs = args;
215
-
216
- if (status !== 'succeeded') return;
217
- if (!this._waiters) return;
218
-
219
- Faye.each(this._waiters, function(callback) {
220
- callback[0].apply(callback[1], this._deferredArgs);
221
- }, this);
222
-
223
- this._waiters = [];
224
- }
225
- };
226
-
227
-
228
- Faye.Observable = {
229
- on: function(eventType, block, scope) {
230
- this._observers = this._observers || {};
231
- var list = this._observers[eventType] = this._observers[eventType] || [];
232
- list.push([block, scope]);
233
- },
234
-
235
- stopObserving: function(eventType, block, scope) {
236
- if (!this._observers || !this._observers[eventType]) return;
237
-
238
- if (!block) {
239
- delete this._observers[eventType];
240
- return;
241
- }
242
- var list = this._observers[eventType],
243
- i = list.length;
244
-
245
- while (i--) {
246
- if (block && list[i][0] !== block) continue;
247
- if (scope && list[i][1] !== scope) continue;
248
- list.splice(i,1);
249
- }
250
- },
251
-
252
- trigger: function() {
253
- var args = Array.prototype.slice.call(arguments),
254
- eventType = args.shift();
255
-
256
- if (!this._observers || !this._observers[eventType]) return;
257
-
258
- Faye.each(this._observers[eventType], function(listener) {
259
- listener[0].apply(listener[1], args.slice());
260
- });
261
- }
262
- };
263
-
264
-
265
- Faye.Logging = {
266
- LOG_LEVELS: {
267
- error: 3,
268
- warn: 2,
269
- info: 1,
270
- debug: 0
271
- },
272
-
273
- logLevel: 'error',
274
-
275
- log: function(messageArgs, level) {
276
- if (!Faye.logger) return;
277
-
278
- var levels = Faye.Logging.LOG_LEVELS;
279
- if (levels[Faye.Logging.logLevel] > levels[level]) return;
280
-
281
- var messageArgs = Array.prototype.slice.apply(messageArgs),
282
- banner = ' [' + level.toUpperCase() + '] [Faye',
283
- klass = null,
284
-
285
- message = messageArgs.shift().replace(/\?/g, function() {
286
- return Faye.toJSON(messageArgs.shift());
287
- });
288
-
289
- for (var key in Faye) {
290
- if (klass) continue;
291
- if (typeof Faye[key] !== 'function') continue;
292
- if (this instanceof Faye[key]) klass = key;
293
- }
294
- if (klass) banner += '.' + klass;
295
- banner += '] ';
296
-
297
- Faye.logger(Faye.timestamp() + banner + message);
298
- }
299
- };
300
-
301
- Faye.each(Faye.Logging.LOG_LEVELS, function(level, value) {
302
- Faye.Logging[level] = function() {
303
- this.log(arguments, level);
304
- };
305
- });
306
-
307
-
308
- Faye.Timeouts = {
309
- addTimeout: function(name, delay, callback, scope) {
310
- this._timeouts = this._timeouts || {};
311
- if (this._timeouts.hasOwnProperty(name)) return;
312
- var self = this;
313
- this._timeouts[name] = setTimeout(function() {
314
- delete self._timeouts[name];
315
- callback.call(scope);
316
- }, 1000 * delay);
317
- },
318
-
319
- removeTimeout: function(name) {
320
- this._timeouts = this._timeouts || {};
321
- var timeout = this._timeouts[name];
322
- if (!timeout) return;
323
- clearTimeout(timeout);
324
- delete this._timeouts[name];
325
- }
326
- };
327
-
328
-
329
- Faye.Channel = Faye.Class({
330
- initialize: function(name) {
331
- this.__id = this.name = name;
332
- },
333
-
334
- push: function(message) {
335
- this.trigger('message', message);
336
- }
337
- });
338
-
339
- Faye.extend(Faye.Channel.prototype, Faye.Observable);
340
-
341
- Faye.extend(Faye.Channel, {
342
- HANDSHAKE: '/meta/handshake',
343
- CONNECT: '/meta/connect',
344
- SUBSCRIBE: '/meta/subscribe',
345
- UNSUBSCRIBE: '/meta/unsubscribe',
346
- DISCONNECT: '/meta/disconnect',
347
-
348
- META: 'meta',
349
- SERVICE: 'service',
350
-
351
- isValid: function(name) {
352
- return Faye.Grammar.CHANNEL_NAME.test(name) ||
353
- Faye.Grammar.CHANNEL_PATTERN.test(name);
354
- },
355
-
356
- parse: function(name) {
357
- if (!this.isValid(name)) return null;
358
- return name.split('/').slice(1);
359
- },
360
-
361
- isMeta: function(name) {
362
- var segments = this.parse(name);
363
- return segments ? (segments[0] === this.META) : null;
364
- },
365
-
366
- isService: function(name) {
367
- var segments = this.parse(name);
368
- return segments ? (segments[0] === this.SERVICE) : null;
369
- },
370
-
371
- isSubscribable: function(name) {
372
- if (!this.isValid(name)) return null;
373
- return !this.isMeta(name) && !this.isService(name);
374
- },
375
-
376
- Tree: Faye.Class({
377
- initialize: function(value) {
378
- this._value = value;
379
- this._children = {};
380
- },
381
-
382
- eachChild: function(block, context) {
383
- Faye.each(this._children, function(key, subtree) {
384
- block.call(context, key, subtree);
385
- });
386
- },
387
-
388
- each: function(prefix, block, context) {
389
- this.eachChild(function(path, subtree) {
390
- path = prefix.concat(path);
391
- subtree.each(path, block, context);
392
- });
393
- if (this._value !== undefined) block.call(context, prefix, this._value);
394
- },
395
-
396
- getKeys: function() {
397
- return this.map(function(key, value) { return '/' + key.join('/') });
398
- },
399
-
400
- map: function(block, context) {
401
- var result = [];
402
- this.each([], function(path, value) {
403
- result.push(block.call(context, path, value));
404
- });
405
- return result;
406
- },
407
-
408
- get: function(name) {
409
- var tree = this.traverse(name);
410
- return tree ? tree._value : null;
411
- },
412
-
413
- set: function(name, value) {
414
- var subtree = this.traverse(name, true);
415
- if (subtree) subtree._value = value;
416
- },
417
-
418
- traverse: function(path, createIfAbsent) {
419
- if (typeof path === 'string') path = Faye.Channel.parse(path);
420
-
421
- if (path === null) return null;
422
- if (path.length === 0) return this;
423
-
424
- var subtree = this._children[path[0]];
425
- if (!subtree && !createIfAbsent) return null;
426
- if (!subtree) subtree = this._children[path[0]] = new Faye.Channel.Tree();
427
-
428
- return subtree.traverse(path.slice(1), createIfAbsent);
429
- },
430
-
431
- findOrCreate: function(channel) {
432
- var existing = this.get(channel);
433
- if (existing) return existing;
434
- existing = new Faye.Channel(channel);
435
- this.set(channel, existing);
436
- return existing;
437
- },
438
-
439
- glob: function(path) {
440
- if (typeof path === 'string') path = Faye.Channel.parse(path);
441
-
442
- if (path === null) return [];
443
- if (path.length === 0) return (this._value === undefined) ? [] : [this._value];
444
-
445
- var list = [];
446
-
447
- if (Faye.enumEqual(path, ['*'])) {
448
- Faye.each(this._children, function(key, subtree) {
449
- if (subtree._value !== undefined) list.push(subtree._value);
450
- });
451
- return list;
452
- }
453
-
454
- if (Faye.enumEqual(path, ['**'])) {
455
- list = this.map(function(key, value) { return value });
456
- if (this._value !== undefined) list.pop();
457
- return list;
458
- }
459
-
460
- Faye.each(this._children, function(key, subtree) {
461
- if (key !== path[0] && key !== '*') return;
462
- var sublist = subtree.glob(path.slice(1));
463
- Faye.each(sublist, function(channel) { list.push(channel) });
464
- });
465
-
466
- if (this._children['**']) list.push(this._children['**']._value);
467
- return list;
468
- }
469
- })
470
- });
471
-
472
-
473
- Faye.Namespace = Faye.Class({
474
- initialize: function() {
475
- this._used = {};
476
- },
477
-
478
- generate: function() {
479
- var name = Faye.random();
480
- while (this._used.hasOwnProperty(name))
481
- name = Faye.random();
482
- return this._used[name] = name;
483
- }
484
- });
485
-
486
-
487
- Faye.Transport = Faye.extend(Faye.Class({
488
- initialize: function(client, endpoint) {
489
- this.debug('Created new transport for ?', endpoint);
490
- this._client = client;
491
- this._endpoint = endpoint;
492
- },
493
-
494
- send: function(message, callback, scope) {
495
- if (!(message instanceof Array) && !message.id)
496
- message.id = this._client._namespace.generate();
497
-
498
- this.debug('Client ? sending message to ?: ?',
499
- this._client._clientId, this._endpoint, message);
500
-
501
- this.request(message, function(responses) {
502
- this.debug('Client ? received from ?: ?',
503
- this._client._clientId, this._endpoint, responses);
504
-
505
- if (!callback) return;
506
-
507
- var messages = [], deliverable = true;
508
- Faye.each([].concat(responses), function(response) {
509
-
510
- if (response.id === message.id) {
511
- if (callback.call(scope, response) === false)
512
- deliverable = false;
513
- }
514
-
515
- if (response.advice)
516
- this._client.handleAdvice(response.advice);
517
-
518
- if (response.data && response.channel)
519
- messages.push(response);
520
-
521
- }, this);
522
-
523
- if (deliverable) this._client.deliverMessages(messages);
524
- }, this);
525
- }
526
- }), {
527
- get: function(client, connectionTypes) {
528
- var endpoint = client._endpoint;
529
- if (connectionTypes === undefined) connectionTypes = this.supportedConnectionTypes();
530
-
531
- var candidateClass = null;
532
- Faye.each(this._transports, function(connType, klass) {
533
- if (Faye.indexOf(connectionTypes, connType) < 0) return;
534
- if (candidateClass) return;
535
- if (klass.isUsable(endpoint)) candidateClass = klass;
536
- });
537
-
538
- if (!candidateClass) throw 'Could not find a usable connection type for ' + endpoint;
539
-
540
- return new candidateClass(client, endpoint);
541
- },
542
-
543
- register: function(type, klass) {
544
- this._transports[type] = klass;
545
- klass.prototype.connectionType = type;
546
- },
547
-
548
- _transports: {},
549
-
550
- supportedConnectionTypes: function() {
551
- var list = [], key;
552
- Faye.each(this._transports, function(key, type) { list.push(key) });
553
- return list;
554
- }
555
- });
556
-
557
- Faye.extend(Faye.Transport.prototype, Faye.Logging);
558
-
559
-
560
- Faye.Client = Faye.Class({
561
- UNCONNECTED: 1,
562
- CONNECTING: 2,
563
- CONNECTED: 3,
564
- DISCONNECTED: 4,
565
-
566
- HANDSHAKE: 'handshake',
567
- RETRY: 'retry',
568
- NONE: 'none',
569
-
570
- CONNECTION_TIMEOUT: 60.0,
571
-
572
- DEFAULT_ENDPOINT: '/bayeux',
573
- MAX_DELAY: 0.1,
574
- INTERVAL: 1000.0,
575
-
576
- initialize: function(endpoint, options) {
577
- this.info('New client created for ?', endpoint);
578
-
579
- this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
580
- this._options = options || {};
581
- this._timeout = this._options.timeout || this.CONNECTION_TIMEOUT;
582
-
583
- this._transport = Faye.Transport.get(this);
584
- this._state = this.UNCONNECTED;
585
- this._namespace = new Faye.Namespace();
586
- this._outbox = [];
587
- this._channels = new Faye.Channel.Tree();
588
-
589
- this._advice = {reconnect: this.RETRY, interval: this.INTERVAL};
590
-
591
- if (Faye.Event) Faye.Event.on(Faye.ENV, 'beforeunload',
592
- this.disconnect, this);
593
- },
594
-
595
- // Request
596
- // MUST include: * channel
597
- // * version
598
- // * supportedConnectionTypes
599
- // MAY include: * minimumVersion
600
- // * ext
601
- // * id
602
- //
603
- // Success Response Failed Response
604
- // MUST include: * channel MUST include: * channel
605
- // * version * successful
606
- // * supportedConnectionTypes * error
607
- // * clientId MAY include: * supportedConnectionTypes
608
- // * successful * advice
609
- // MAY include: * minimumVersion * version
610
- // * advice * minimumVersion
611
- // * ext * ext
612
- // * id * id
613
- // * authSuccessful
614
- handshake: function(callback, scope) {
615
- if (this._advice.reconnect === this.NONE) return;
616
- if (this._state !== this.UNCONNECTED) return;
617
-
618
- this._state = this.CONNECTING;
619
- var self = this;
620
-
621
- this.info('Initiating handshake with ?', this._endpoint);
622
-
623
- this._transport.send({
624
- channel: Faye.Channel.HANDSHAKE,
625
- version: Faye.BAYEUX_VERSION,
626
- supportedConnectionTypes: Faye.Transport.supportedConnectionTypes()
627
-
628
- }, function(response) {
629
-
630
- if (response.successful) {
631
- this._state = this.CONNECTED;
632
- this._clientId = response.clientId;
633
- this._transport = Faye.Transport.get(this, response.supportedConnectionTypes);
634
-
635
- this.info('Handshake successful: ?', this._clientId);
636
- if (callback) callback.call(scope);
637
-
638
- } else {
639
- this.info('Handshake unsuccessful');
640
- setTimeout(function() { self.handshake(callback, scope) }, this._advice.interval);
641
- this._state = this.UNCONNECTED;
642
- }
643
- }, this);
644
- },
645
-
646
- // Request Response
647
- // MUST include: * channel MUST include: * channel
648
- // * clientId * successful
649
- // * connectionType * clientId
650
- // MAY include: * ext MAY include: * error
651
- // * id * advice
652
- // * ext
653
- // * id
654
- // * timestamp
655
- connect: function(callback, scope) {
656
- if (this._advice.reconnect === this.NONE) return;
657
- if (this._state === this.DISCONNECTED) return;
658
-
659
- if (this._advice.reconnect === this.HANDSHAKE || this._state === this.UNCONNECTED) {
660
- this._beginReconnectTimeout();
661
- return this.handshake(function() { this.connect(callback, scope) }, this);
662
- }
663
-
664
- if (this._state === this.CONNECTING)
665
- return this.callback(callback, scope);
666
-
667
- if (this._state !== this.CONNECTED) return;
668
-
669
- this.info('Calling deferred actions for ?', this._clientId);
670
- this.setDeferredStatus('succeeded');
671
- this.setDeferredStatus('deferred');
672
- if (callback) callback.call(scope);
673
-
674
- if (this._connectionId) return;
675
- this._connectionId = this._namespace.generate();
676
- var self = this;
677
- this.info('Initiating connection for ?', this._clientId);
678
-
679
- this._transport.send({
680
- channel: Faye.Channel.CONNECT,
681
- clientId: this._clientId,
682
- connectionType: this._transport.connectionType,
683
- id: this._connectionId
684
-
685
- }, this._verifyClientId(function(response) {
686
- this._connectionId = null;
687
- this.removeTimeout('reconnect');
688
-
689
- this.info('Closed connection for ?', this._clientId);
690
- setTimeout(function() { self.connect() }, this._advice.interval);
691
- }));
692
-
693
- this._beginReconnectTimeout();
694
- },
695
-
696
- // Request Response
697
- // MUST include: * channel MUST include: * channel
698
- // * clientId * successful
699
- // MAY include: * ext * clientId
700
- // * id MAY include: * error
701
- // * ext
702
- // * id
703
- disconnect: function() {
704
- if (this._state !== this.CONNECTED) return;
705
- this._state = this.DISCONNECTED;
706
-
707
- this.info('Disconnecting ?', this._clientId);
708
-
709
- this._transport.send({
710
- channel: Faye.Channel.DISCONNECT,
711
- clientId: this._clientId
712
- });
713
-
714
- this.info('Clearing channel listeners for ?', this._clientId);
715
- this._channels = new Faye.Channel.Tree();
716
- this.removeTimeout('reconnect');
717
- },
718
-
719
- // Request Response
720
- // MUST include: * channel MUST include: * channel
721
- // * clientId * successful
722
- // * subscription * clientId
723
- // MAY include: * ext * subscription
724
- // * id MAY include: * error
725
- // * advice
726
- // * ext
727
- // * id
728
- // * timestamp
729
- subscribe: function(channels, callback, scope) {
730
- this.connect(function() {
731
-
732
- channels = [].concat(channels);
733
- this._validateChannels(channels);
734
-
735
- this.info('Client ? attempting to subscribe to ?', this._clientId, channels);
736
-
737
- this._transport.send({
738
- channel: Faye.Channel.SUBSCRIBE,
739
- clientId: this._clientId,
740
- subscription: channels
741
-
742
- }, this._verifyClientId(function(response) {
743
- if (!response.successful || !callback) return;
744
-
745
- this.info('Subscription acknowledged for ? to ?', this._clientId, channels);
746
-
747
- channels = [].concat(response.subscription);
748
- Faye.each(channels, function(channel) {
749
- this._channels.set(channel, [callback, scope]);
750
- }, this);
751
- }));
752
-
753
- }, this);
754
- },
755
-
756
- // Request Response
757
- // MUST include: * channel MUST include: * channel
758
- // * clientId * successful
759
- // * subscription * clientId
760
- // MAY include: * ext * subscription
761
- // * id MAY include: * error
762
- // * advice
763
- // * ext
764
- // * id
765
- // * timestamp
766
- unsubscribe: function(channels, callback, scope) {
767
- this.connect(function() {
768
-
769
- channels = [].concat(channels);
770
- this._validateChannels(channels);
771
-
772
- this.info('Client ? attempting to unsubscribe from ?', this._clientId, channels);
773
-
774
- this._transport.send({
775
- channel: Faye.Channel.UNSUBSCRIBE,
776
- clientId: this._clientId,
777
- subscription: channels
778
-
779
- }, this._verifyClientId(function(response) {
780
- if (!response.successful) return;
781
-
782
- this.info('Unsubscription acknowledged for ? from ?', this._clientId, channels);
783
-
784
- channels = [].concat(response.subscription);
785
- Faye.each(channels, function(channel) {
786
- this._channels.set(channel, undefined);
787
- }, this);
788
- }));
789
-
790
- }, this);
791
- },
792
-
793
- // Request Response
794
- // MUST include: * channel MUST include: * channel
795
- // * data * successful
796
- // MAY include: * clientId MAY include: * id
797
- // * id * error
798
- // * ext * ext
799
- publish: function(channel, data) {
800
- this.connect(function() {
801
-
802
- this._validateChannels([channel]);
803
-
804
- this.info('Client ? queueing published message to ?: ?', this._clientId, channel, data);
805
-
806
- this._enqueue({
807
- channel: channel,
808
- data: data,
809
- clientId: this._clientId
810
- });
811
-
812
- this.addTimeout('publish', this.MAX_DELAY, this._flush, this);
813
-
814
- }, this);
815
- },
816
-
817
- handleAdvice: function(advice) {
818
- Faye.extend(this._advice, advice);
819
- if (this._advice.reconnect === this.HANDSHAKE) this._clientId = null;
820
- },
821
-
822
- deliverMessages: function(messages) {
823
- Faye.each(messages, function(message) {
824
- this.info('Client ? calling listeners for ? with ?', this._clientId, message.channel, message.data);
825
-
826
- var channels = this._channels.glob(message.channel);
827
- Faye.each(channels, function(callback) {
828
- callback[0].call(callback[1], message.data);
829
- });
830
- }, this);
831
- },
832
-
833
- _beginReconnectTimeout: function() {
834
- this.addTimeout('reconnect', this._timeout, function() {
835
- this._connectionId = null;
836
- this._clientId = null;
837
- this._state = this.UNCONNECTED;
838
-
839
- this.info('Server took >?s to reply to connection for ?: attempting to reconnect',
840
- this._timeout, this._clientId);
841
-
842
- this.subscribe(this._channels.getKeys());
843
- }, this);
844
- },
845
-
846
- _enqueue: function(message) {
847
- this._outbox.push(message);
848
- },
849
-
850
- _flush: function() {
851
- this._transport.send(this._outbox);
852
- this._outbox = [];
853
- },
854
-
855
- _validateChannels: function(channels) {
856
- Faye.each(channels, function(channel) {
857
- if (!Faye.Channel.isValid(channel))
858
- throw '"' + channel + '" is not a valid channel name';
859
- if (!Faye.Channel.isSubscribable(channel))
860
- throw 'Clients may not subscribe to channel "' + channel + '"';
861
- });
862
- },
863
-
864
- _verifyClientId: function(callback) {
865
- var self = this;
866
- return function(response) {
867
- if (response.clientId !== self._clientId) return false;
868
- callback.call(self, response);
869
- return true;
870
- };
871
- }
872
- });
873
-
874
- Faye.extend(Faye.Client.prototype, Faye.Deferrable);
875
- Faye.extend(Faye.Client.prototype, Faye.Timeouts);
876
- Faye.extend(Faye.Client.prototype, Faye.Logging);
877
-
878
-
879
- Faye.Set = Faye.Class({
880
- initialize: function() {
881
- this._index = {};
882
- },
883
-
884
- add: function(item) {
885
- var key = (item.__id !== undefined) ? item.__id : item;
886
- if (this._index.hasOwnProperty(key)) return false;
887
- this._index[key] = item;
888
- return true;
889
- },
890
-
891
- forEach: function(block, scope) {
892
- for (var key in this._index) {
893
- if (this._index.hasOwnProperty(key))
894
- block.call(scope, this._index[key]);
895
- }
896
- },
897
-
898
- isEmpty: function() {
899
- for (var key in this._index) {
900
- if (this._index.hasOwnProperty(key)) return false;
901
- }
902
- return true;
903
- },
904
-
905
- member: function(item) {
906
- for (var key in this._index) {
907
- if (this._index[key] === item) return true;
908
- }
909
- return false;
910
- },
911
-
912
- remove: function(item) {
913
- var key = (item.__id !== undefined) ? item.__id : item;
914
- delete this._index[key];
915
- },
916
-
917
- toArray: function() {
918
- var array = [];
919
- this.forEach(function(item) { array.push(item) });
920
- return array;
921
- }
922
- });
923
-
924
-
925
- Faye.Server = Faye.Class({
926
- initialize: function(options) {
927
- this.info('New server created');
928
- this._options = options || {};
929
- this._channels = new Faye.Channel.Tree();
930
- this._connections = {};
931
- this._namespace = new Faye.Namespace();
932
- },
933
-
934
- clientIds: function() {
935
- var ids = [];
936
- Faye.each(this._connections, function(key, value) { ids.push(key) });
937
- return ids;
938
- },
939
-
940
- process: function(messages, local, callback) {
941
- this.debug('Processing messages from ? client', local ? 'LOCAL' : 'REMOTE');
942
-
943
- messages = [].concat(messages);
944
- var processed = 0, responses = [];
945
-
946
- Faye.each(messages, function(message) {
947
- this._handle(message, local, function(reply) {
948
- responses = responses.concat(reply);
949
- processed += 1;
950
- if (processed < messages.length) return;
951
- callback(responses);
952
- }, this);
953
- }, this);
954
- },
955
-
956
- flushConnection: function(messages) {
957
- messages = [].concat(messages);
958
- Faye.each(messages, function(message) {
959
- var connection = this._connections[message.clientId];
960
- if (connection) connection.flush();
961
- }, this);
962
- },
963
-
964
- _connection: function(id) {
965
- if (this._connections.hasOwnProperty(id)) return this._connections[id];
966
- var connection = new Faye.Connection(id, this._options);
967
- connection.on('staleConnection', this._destroyConnection, this);
968
- return this._connections[id] = connection;
969
- },
970
-
971
- _destroyConnection: function(connection) {
972
- connection.disconnect();
973
- connection.stopObserving('staleConnection', this._destroyConnection, this);
974
- delete this._connections[connection.id];
975
- },
976
-
977
- _handle: function(message, local, callback, scope) {
978
- var channelName = message.channel,
979
- response;
980
-
981
- message.__id = Faye.random();
982
- Faye.each(this._channels.glob(channelName), function(channel) {
983
- channel.push(message);
984
- this.info('Publishing message ? from client ? to ?', message.data, message.clientId, channel.name);
985
- }, this);
986
-
987
- if (Faye.Channel.isMeta(channelName)) {
988
- response = this[Faye.Channel.parse(channelName)[1]](message, local);
989
-
990
- var clientId = response.clientId;
991
- response.advice = response.advice || {};
992
- Faye.extend(response.advice, {
993
- reconnect: this._connections.hasOwnProperty(clientId) ? 'retry' : 'handshake',
994
- interval: Math.floor(Faye.Connection.prototype.INTERVAL * 1000)
995
- }, false);
996
-
997
- if (response.channel !== Faye.Channel.CONNECT ||
998
- response.successful !== true)
999
- return callback.call(scope, response);
1000
-
1001
- this.info('Accepting connection from ?', response.clientId);
1002
-
1003
- return this._connection(response.clientId).connect(function(events) {
1004
- this.info('Sending event messages to ?', response.clientId);
1005
- this.debug('Events for ?: ?', response.clientId, events);
1006
- Faye.each(events, function(e) { delete e.__id });
1007
- callback.call(scope, [response].concat(events));
1008
- }, this);
1009
- }
1010
-
1011
- if (!message.clientId || Faye.Channel.isService(channelName))
1012
- return callback([]);
1013
-
1014
- response = this._makeResponse(message);
1015
- response.successful = true;
1016
- callback(response);
1017
- },
1018
-
1019
- _makeResponse: function(message) {
1020
- var response = {};
1021
- Faye.each(['id', 'clientId', 'channel'], function(field) {
1022
- if (message[field]) response[field] = message[field];
1023
- });
1024
- return response;
1025
- },
1026
-
1027
- // MUST contain * version
1028
- // * supportedConnectionTypes
1029
- // MAY contain * minimumVersion
1030
- // * ext
1031
- // * id
1032
- handshake: function(message, local) {
1033
- var response = this._makeResponse(message);
1034
- response.version = Faye.BAYEUX_VERSION;
1035
-
1036
- if (!message.version)
1037
- response.error = Faye.Error.parameterMissing('version');
1038
-
1039
- var clientConns = message.supportedConnectionTypes,
1040
- commonConns;
1041
-
1042
- if (!local) {
1043
- response.supportedConnectionTypes = Faye.CONNECTION_TYPES;
1044
-
1045
- if (clientConns) {
1046
- commonConns = Faye.filter(clientConns, function(conn) {
1047
- return Faye.indexOf(Faye.CONNECTION_TYPES, conn) !== -1;
1048
- });
1049
- if (commonConns.length === 0)
1050
- response.error = Faye.Error.conntypeMismatch(clientConns);
1051
- } else {
1052
- response.error = Faye.Error.parameterMissing('supportedConnectionTypes');
1053
- }
1054
- }
1055
-
1056
- response.successful = !response.error;
1057
- if (!response.successful) return response;
1058
-
1059
- var clientId = this._namespace.generate();
1060
- response.clientId = this._connection(clientId).id;
1061
- this.info('Accepting handshake from client ?', response.clientId);
1062
- return response;
1063
- },
1064
-
1065
- // MUST contain * clientId
1066
- // * connectionType
1067
- // MAY contain * ext
1068
- // * id
1069
- connect: function(message, local) {
1070
- var response = this._makeResponse(message);
1071
-
1072
- var clientId = message.clientId,
1073
- connection = clientId ? this._connections[clientId] : null,
1074
- connectionType = message.connectionType;
1075
-
1076
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1077
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1078
- if (!connectionType) response.error = Faye.Error.parameterMissing('connectionType');
1079
-
1080
- response.successful = !response.error;
1081
- if (!response.successful) delete response.clientId;
1082
- if (!response.successful) return response;
1083
-
1084
- response.clientId = connection.id;
1085
- return response;
1086
- },
1087
-
1088
- // MUST contain * clientId
1089
- // MAY contain * ext
1090
- // * id
1091
- disconnect: function(message, local) {
1092
- var response = this._makeResponse(message);
1093
-
1094
- var clientId = message.clientId,
1095
- connection = clientId ? this._connections[clientId] : null;
1096
-
1097
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1098
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1099
-
1100
- response.successful = !response.error;
1101
- if (!response.successful) delete response.clientId;
1102
- if (!response.successful) return response;
1103
-
1104
- this._destroyConnection(connection);
1105
-
1106
- this.info('Disconnected client: ?', clientId);
1107
- response.clientId = clientId;
1108
- return response;
1109
- },
1110
-
1111
- // MUST contain * clientId
1112
- // * subscription
1113
- // MAY contain * ext
1114
- // * id
1115
- subscribe: function(message, local) {
1116
- var response = this._makeResponse(message);
1117
-
1118
- var clientId = message.clientId,
1119
- connection = clientId ? this._connections[clientId] : null,
1120
- subscription = message.subscription;
1121
-
1122
- subscription = [].concat(subscription);
1123
-
1124
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1125
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1126
- if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
1127
-
1128
- response.subscription = subscription;
1129
-
1130
- Faye.each(subscription, function(channel) {
1131
- if (response.error) return;
1132
- if (!local && !Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
1133
- if (!Faye.Channel.isValid(channel)) response.error = Faye.Error.channelInvalid(channel);
1134
-
1135
- if (response.error) return;
1136
- channel = this._channels.findOrCreate(channel);
1137
-
1138
- this.info('Subscribing client ? to ?', clientId, channel.name);
1139
- connection.subscribe(channel);
1140
- }, this);
1141
-
1142
- response.successful = !response.error;
1143
- return response;
1144
- },
1145
-
1146
- // MUST contain * clientId
1147
- // * subscription
1148
- // MAY contain * ext
1149
- // * id
1150
- unsubscribe: function(message, local) {
1151
- var response = this._makeResponse(message);
1152
-
1153
- var clientId = message.clientId,
1154
- connection = clientId ? this._connections[clientId] : null,
1155
- subscription = message.subscription;
1156
-
1157
- subscription = [].concat(subscription);
1158
-
1159
- if (!connection) response.error = Faye.Error.clientUnknown(clientId);
1160
- if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
1161
- if (!message.subscription) response.error = Faye.Error.parameterMissing('subscription');
1162
-
1163
- response.subscription = subscription;
1164
-
1165
- Faye.each(subscription, function(channel) {
1166
- if (response.error) return;
1167
-
1168
- if (!Faye.Channel.isValid(channel))
1169
- return response.error = Faye.Error.channelInvalid(channel);
1170
-
1171
- channel = this._channels.get(channel);
1172
- if (!channel) return;
1173
-
1174
- this.info('Unsubscribing client ? from ?', clientId, channel.name);
1175
- connection.unsubscribe(channel);
1176
- }, this);
1177
-
1178
- response.successful = !response.error;
1179
- return response;
1180
- }
1181
- });
1182
-
1183
- Faye.extend(Faye.Server.prototype, Faye.Logging);
1184
-
1185
-
1186
- Faye.Connection = Faye.Class({
1187
- MAX_DELAY: 0.1,
1188
- INTERVAL: 1.0,
1189
- TIMEOUT: 60.0,
1190
-
1191
- initialize: function(id, options) {
1192
- this.id = id;
1193
- this._options = options;
1194
- this._timeout = this._options.timeout || this.TIMEOUT;
1195
- this._channels = new Faye.Set();
1196
- this._inbox = new Faye.Set();
1197
- this._connected = false
1198
- },
1199
-
1200
- _onMessage: function(event) {
1201
- this._inbox.add(event);
1202
- this._beginDeliveryTimeout();
1203
- },
1204
-
1205
- subscribe: function(channel) {
1206
- if (!this._channels.add(channel)) return;
1207
- channel.on('message', this._onMessage, this);
1208
- },
1209
-
1210
- unsubscribe: function(channel) {
1211
- if (channel === 'all') return this._channels.forEach(this.unsubscribe, this);
1212
- if (!this._channels.member(channel)) return;
1213
- this._channels.remove(channel);
1214
- channel.stopObserving('message', this._onMessage, this);
1215
- },
1216
-
1217
- connect: function(callback, scope) {
1218
- this.setDeferredStatus('deferred');
1219
-
1220
- this.callback(callback, scope);
1221
- if (this._connected) return;
1222
-
1223
- this._connected = true;
1224
- this.removeTimeout('deletion');
1225
-
1226
- this._beginDeliveryTimeout();
1227
- this._beginConnectionTimeout();
1228
- },
1229
-
1230
- flush: function() {
1231
- if (!this._connected) return;
1232
- this._releaseConnection();
1233
-
1234
- var events = this._inbox.toArray();
1235
- this._inbox = new Faye.Set();
1236
-
1237
- this.setDeferredStatus('succeeded', events);
1238
- this.setDeferredStatus('deferred');
1239
- },
1240
-
1241
- disconnect: function() {
1242
- this.unsubscribe('all');
1243
- this.flush();
1244
- },
1245
-
1246
- _beginDeliveryTimeout: function() {
1247
- if (!this._connected || this._inbox.isEmpty()) return;
1248
- this.addTimeout('delivery', this.MAX_DELAY, this.flush, this);
1249
- },
1250
-
1251
- _beginConnectionTimeout: function() {
1252
- if (!this._connected) return;
1253
- this.addTimeout('connection', this._timeout, this.flush, this);
1254
- },
1255
-
1256
- _releaseConnection: function() {
1257
- this.removeTimeout('connection');
1258
- this.removeTimeout('delivery');
1259
- this._connected = false;
1260
-
1261
- this.addTimeout('deletion', 10 * this.INTERVAL, function() {
1262
- this.trigger('staleConnection', this);
1263
- }, this);
1264
- }
1265
- });
1266
-
1267
- Faye.extend(Faye.Connection.prototype, Faye.Deferrable);
1268
- Faye.extend(Faye.Connection.prototype, Faye.Observable);
1269
- Faye.extend(Faye.Connection.prototype, Faye.Timeouts);
1270
-
1271
-
1272
- Faye.Error = Faye.Class({
1273
- initialize: function(code, args, message) {
1274
- this.code = code;
1275
- this.args = Array.prototype.slice.call(args);
1276
- this.message = message;
1277
- },
1278
-
1279
- toString: function() {
1280
- return this.code + ':' +
1281
- this.args.join(',') + ':' +
1282
- this.message;
1283
- }
1284
- });
1285
-
1286
-
1287
- Faye.Error.versionMismatch = function() {
1288
- return new this(300, arguments, "Version mismatch").toString();
1289
- };
1290
-
1291
- Faye.Error.conntypeMismatch = function() {
1292
- return new this(301, arguments, "Connection types not supported").toString();
1293
- };
1294
-
1295
- Faye.Error.extMismatch = function() {
1296
- return new this(302, arguments, "Extension mismatch").toString();
1297
- };
1298
-
1299
- Faye.Error.badRequest = function() {
1300
- return new this(400, arguments, "Bad request").toString();
1301
- };
1302
-
1303
- Faye.Error.clientUnknown = function() {
1304
- return new this(401, arguments, "Unknown client").toString();
1305
- };
1306
-
1307
- Faye.Error.parameterMissing = function() {
1308
- return new this(402, arguments, "Missing required parameter").toString();
1309
- };
1310
-
1311
- Faye.Error.channelForbidden = function() {
1312
- return new this(403, arguments, "Forbidden channel").toString();
1313
- };
1314
-
1315
- Faye.Error.channelUnknown = function() {
1316
- return new this(404, arguments, "Unknown channel").toString();
1317
- };
1318
-
1319
- Faye.Error.channelInvalid = function() {
1320
- return new this(405, arguments, "Invalid channel").toString();
1321
- };
1322
-
1323
- Faye.Error.extUnknown = function() {
1324
- return new this(406, arguments, "Unknown extension").toString();
1325
- };
1326
-
1327
- Faye.Error.publishFailed = function() {
1328
- return new this(407, arguments, "Failed to publish").toString();
1329
- };
1330
-
1331
- Faye.Error.serverError = function() {
1332
- return new this(500, arguments, "Internal server error").toString();
1333
- };
1334
-
1335
-
1336
-
1337
- var path = require('path'),
1338
- fs = require('fs'),
1339
- sys = require('sys'),
1340
- url = require('url'),
1341
- http = require('http'),
1342
- querystring = require('querystring');
1343
-
1344
- Faye.logger = function(message) {
1345
- sys.puts(message);
1346
- };
1347
-
1348
- Faye.withDataFor = function(transport, callback, scope) {
1349
- var data = '';
1350
- transport.addListener('data', function(chunk) { data += chunk });
1351
- transport.addListener('end', function() {
1352
- callback.call(scope, data);
1353
- });
1354
- };
1355
-
1356
- Faye.NodeAdapter = Faye.Class({
1357
- DEFAULT_ENDPOINT: '/bayeux',
1358
- SCRIPT_PATH: path.dirname(__filename) + '/faye-client-min.js',
1359
-
1360
- TYPE_JSON: {'Content-Type': 'application/json'},
1361
- TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
1362
- TYPE_TEXT: {'Content-Type': 'text/plain'},
1363
-
1364
- initialize: function(options) {
1365
- this._options = options || {};
1366
- this._endpoint = this._options.mount || this.DEFAULT_ENDPOINT;
1367
- this._endpointRe = new RegExp('^' + this._endpoint + '(/[^/]+)*(\\.js)?$');
1368
- this._server = new Faye.Server(this._options);
1369
- },
1370
-
1371
- getClient: function() {
1372
- return this._client = this._client || new Faye.Client(this._server);
1373
- },
1374
-
1375
- run: function(port) {
1376
- var self = this;
1377
- http.createServer(function(request, response) {
1378
- self.call(request, response);
1379
- }).listen(Number(port));
1380
- },
1381
-
1382
- call: function(request, response) {
1383
- var requestUrl = url.parse(request.url, true),
1384
- self = this, data;
1385
-
1386
- if (!this._endpointRe.test(requestUrl.pathname))
1387
- return false;
1388
-
1389
- if (/\.js$/.test(requestUrl.pathname)) {
1390
- fs.readFile(this.SCRIPT_PATH, function(err, content) {
1391
- response.writeHead(200, self.TYPE_SCRIPT);
1392
- response.write(content);
1393
- response.end();
1394
- });
1395
-
1396
- } else {
1397
- var isGet = (request.method === 'GET');
1398
-
1399
- if (isGet)
1400
- this._callWithParams(request, response, requestUrl.query);
1401
-
1402
- else
1403
- Faye.withDataFor(request, function(data) {
1404
- self._callWithParams(request, response, {message: data});
1405
- });
1406
- }
1407
- return true;
1408
- },
1409
-
1410
- _callWithParams: function(request, response, params) {
1411
- try {
1412
- var message = JSON.parse(params.message),
1413
- jsonp = params.jsonp || Faye.JSONP_CALLBACK,
1414
- isGet = (request.method === 'GET'),
1415
- type = isGet ? this.TYPE_SCRIPT : this.TYPE_JSON;
1416
-
1417
- if (isGet) this._server.flushConnection(message);
1418
-
1419
- this._server.process(message, false, function(replies) {
1420
- var body = JSON.stringify(replies);
1421
- if (isGet) body = jsonp + '(' + body + ');';
1422
- response.writeHead(200, type);
1423
- response.write(body);
1424
- response.end();
1425
- });
1426
- } catch (e) {
1427
- response.writeHead(400, this.TYPE_TEXT);
1428
- response.write('Bad request');
1429
- response.end();
1430
- }
1431
- }
1432
- });
1433
-
1434
- exports.NodeAdapter = Faye.NodeAdapter;
1435
- exports.Client = Faye.Client;
1436
-
1437
-
1438
- Faye.NodeHttpTransport = Faye.Class(Faye.Transport, {
1439
- request: function(message, callback, scope) {
1440
- var request = this.createRequestForMessage(message);
1441
-
1442
- request.addListener('response', function(response) {
1443
- if (!callback) return;
1444
- Faye.withDataFor(response, function(data) {
1445
- callback.call(scope, JSON.parse(data));
1446
- });
1447
- });
1448
- request.end();
1449
- },
1450
-
1451
- createRequestForMessage: function(message) {
1452
- var content = JSON.stringify(message),
1453
- uri = url.parse(this._endpoint),
1454
- client = http.createClient(uri.port, uri.hostname);
1455
-
1456
- client.addListener('error', function() { /* catch ECONNREFUSED */ });
1457
-
1458
- if (parseInt(uri.port) === 443) client.setSecure('X509_PEM');
1459
-
1460
- var request = client.request('POST', uri.pathname, {
1461
- 'Content-Type': 'application/json',
1462
- 'host': uri.hostname,
1463
- 'Content-Length': content.length
1464
- });
1465
- request.write(content);
1466
- return request;
1467
- }
1468
- });
1469
-
1470
- Faye.NodeHttpTransport.isUsable = function(endpoint) {
1471
- return typeof endpoint === 'string';
1472
- };
1473
-
1474
- Faye.Transport.register('long-polling', Faye.NodeHttpTransport);
1475
-
1476
- Faye.NodeLocalTransport = Faye.Class(Faye.Transport, {
1477
- request: function(message, callback, scope) {
1478
- this._endpoint.process(message, true, function(response) {
1479
- callback.call(scope, response);
1480
- });
1481
- }
1482
- });
1483
-
1484
- Faye.NodeLocalTransport.isUsable = function(endpoint) {
1485
- return endpoint instanceof Faye.Server;
1486
- };
1487
-
1488
- Faye.Transport.register('in-process', Faye.NodeLocalTransport);