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
File without changes
@@ -1,100 +0,0 @@
1
- Soapbox = {
2
- /**
3
- * Initializes the application, passing in the globally shared Comet
4
- * client. Apps on the same page should share a Comet client so
5
- * that they may share an open HTTP connection with the server.
6
- */
7
- init: function(comet) {
8
- var self = this;
9
- this._comet = comet;
10
-
11
- this._login = $('#enterUsername');
12
- this._app = $('#app');
13
- this._follow = $('#addFollowee');
14
- this._post = $('#postMessage');
15
- this._stream = $('#stream');
16
-
17
- this._app.hide();
18
-
19
- // When the user enters a username, store it and start the app
20
- this._login.submit(function() {
21
- self._username = $('#username').val();
22
- self.launch();
23
- return false;
24
- });
25
- },
26
-
27
- /**
28
- * Starts the application after a username has been entered. A
29
- * subscription is made to receive messages that mention this user,
30
- * and forms are set up to accept new followers and send messages.
31
- */
32
- launch: function() {
33
- var self = this;
34
- this._comet.subscribe('/mentioning/' + this._username, this.accept, this);
35
-
36
- // Hide login form, show main application UI
37
- this._login.fadeOut('slow', function() {
38
- self._app.fadeIn('slow');
39
- });
40
-
41
- // When we add a follower, subscribe to a channel to which the
42
- // followed user will publish messages
43
- this._follow.submit(function() {
44
- var follow = $('#followee'),
45
- name = follow.val();
46
-
47
- self._comet.subscribe('/from/' + name, self.accept, self);
48
- follow.val('');
49
- return false;
50
- });
51
-
52
- // When we enter a message, send it and clear the message field.
53
- this._post.submit(function() {
54
- var msg = $('#message');
55
- self.post(msg.val());
56
- msg.val('');
57
- return false;
58
- });
59
- },
60
-
61
- /**
62
- * Sends messages that the user has entered. The message is scanned for
63
- * @reply-style mentions of other users, and the message is sent to those
64
- * users' channels.
65
- */
66
- post: function(message) {
67
- var mentions = [],
68
- words = message.split(/\s+/),
69
- self = this,
70
- pattern = /\@[a-z0-9]+/i;
71
-
72
- // Extract @replies from the message
73
- $.each(words, function(i, word) {
74
- if (!pattern.test(word)) return;
75
- word = word.replace(/[^a-z0-9]/ig, '');
76
- if (word !== self._username) mentions.push(word);
77
- });
78
-
79
- // Message object to transmit over Comet channels
80
- message = {user: this._username, message: message};
81
-
82
- // Publish to this user's 'from' channel, and to channels for any
83
- // @replies found in the message
84
- this._comet.publish('/from/' + this._username, message);
85
- $.each(mentions, function(i, name) {
86
- self._comet.publish('/mentioning/' + name, message);
87
- });
88
- },
89
-
90
- /**
91
- * Handler for messages received over subscribed channels. Takes the
92
- * message object sent by the post() method and displays it in
93
- * the user's message list.
94
- */
95
- accept: function(message) {
96
- this._stream.prepend('<li><b>' + message.user + ':</b> ' +
97
- message.message + '</li>');
98
- }
99
- };
100
-
@@ -1,43 +0,0 @@
1
- body {
2
- background: #c9eb70;
3
- margin: 0;
4
- padding: 0;
5
- font: 16px/1.5 Helvetica, Arial, sans-serif;
6
- text-align: center;
7
- }
8
-
9
- .container {
10
- text-align: left;
11
- width: 400px;
12
- margin: 40px auto;
13
- }
14
-
15
- h1, form, ul li {
16
- background: #fff;
17
- padding: 24px;
18
- border: 1px solid #9dba4f;
19
- }
20
-
21
- h1 {
22
- font-size: 20px;
23
- }
24
-
25
- h1 em {
26
- font-style: normal;
27
- font-weight: normal;
28
- color: #444;
29
- text-transform: uppercase;
30
- letter-spacing: -0.06em;
31
- }
32
-
33
- label {
34
- color: #444;
35
- font-weight: bold;
36
- }
37
-
38
- ul, li {
39
- list-style: none;
40
- margin: 0;
41
- padding: 0;
42
- }
43
-
data/jake.yml DELETED
@@ -1,40 +0,0 @@
1
- ---
2
- source_directory: javascript
3
- build_directory: build
4
- builds:
5
- src:
6
- packer: false
7
- suffix: false
8
- min:
9
- shrink_vars: true
10
- private: true
11
- packages:
12
- core:
13
- - faye
14
- - util/class
15
- - util/deferrable
16
- - util/observable
17
- - logging
18
- - timeouts
19
- - channel
20
- - namespace
21
- - transport
22
- - client
23
- faye:
24
- extends: core
25
- files:
26
- - util/set
27
- - server
28
- - connection
29
- - error
30
- - node_adapter
31
- - transports/node
32
- faye-client:
33
- extends: core
34
- files:
35
- - util/event
36
- - util/uri
37
- - util/xhr
38
- - util/json
39
- - transports/browser
40
-
@@ -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,138 +0,0 @@
1
- var sys = require('sys'),
2
- path = require('path'),
3
- http = require('http'),
4
- assert = require('assert'),
5
- faye = require('../build/faye');
6
-
7
- Faye.Logging.logLevel = 'info';
8
-
9
- AsyncScenario = Faye.Class({
10
- initialize: function(name) {
11
- this._name = name;
12
- this._clients = {};
13
- this._inbox = {};
14
- this._pool = 0;
15
- },
16
-
17
- wait: function(time, Continue) {
18
- setTimeout(Continue, 1000 * time);
19
- },
20
-
21
- server: function(port, Continue) {
22
- this._endpoint = 'http://0.0.0.0:' + port + '/comet';
23
- var comet = this._comet = new faye.NodeAdapter({mount: '/comet', timeout: 30});
24
- this._server = http.createServer(function(request, response) {
25
- comet.call(request, response);
26
- });
27
- this._server.listen(port);
28
- Continue();
29
- },
30
-
31
- killServer: function(Continue) {
32
- if (this._server) this._server.close();
33
- this._server = undefined;
34
- setTimeout(Continue, 500);
35
- },
36
-
37
- httpClient: function(name, channels, Continue) {
38
- this._setupClient(new faye.Client(this._endpoint, {timeout: 5}), name, channels, Continue);
39
- },
40
-
41
- localClient: function(name, channels, Continue) {
42
- this._setupClient(this._comet.getClient(), name, channels, Continue);
43
- },
44
-
45
- _setupClient: function(client, name, channels, Continue) {
46
- Faye.each(channels, function(channel) {
47
- client.subscribe(channel, function(message) {
48
- var box = this._inbox[name];
49
- box[channel] = box[channel] || [];
50
- box[channel].push(message);
51
- }, this);
52
- }, this);
53
- this._clients[name] = client;
54
- this._inbox[name] = {};
55
- this._pool += 1;
56
- setTimeout(Continue, 500 * channels.length);
57
- },
58
-
59
- publish: function(from, channel, message, Continue) {
60
- this._clients[from].publish(channel, message);
61
- setTimeout(Continue, 500);
62
- },
63
-
64
- checkInbox: function(expectedInbox, Continue) {
65
- assert.deepEqual(this._inbox, expectedInbox);
66
- Continue();
67
- },
68
-
69
- finish: function(Continue) {
70
- Faye.each(this._clients, function(name, client) { client.disconnect() });
71
- var server = this._server;
72
- setTimeout(function() {
73
- server.close();
74
- Continue();
75
- }, 1000);
76
- },
77
- });
78
-
79
- SyncScenario = Faye.Class({
80
- initialize: function(name, block) {
81
- this._name = name;
82
- this._commands = [];
83
- this._scenario = new AsyncScenario();
84
- block.call(this);
85
- },
86
-
87
- run: function() {
88
- sys.puts('\n' + this._name);
89
- sys.puts('----------------------------------------------------------------');
90
- this._runNextCommand();
91
- },
92
-
93
- _runNextCommand: function() {
94
- if (this._commands.length === 0) return this._finish();
95
-
96
- var command = this._commands.shift(),
97
- method = command[0],
98
- args = Array.prototype.slice.call(command[1]),
99
- self = this;
100
-
101
- this._scenario[method].apply(this._scenario, args.concat(function() {
102
- self._runNextCommand();
103
- }));
104
- },
105
-
106
- _finish: function() {
107
- sys.puts('No errors; Shutting down server\n');
108
- this._scenario.finish(function() { SyncScenario.runNext() });
109
- }
110
- });
111
-
112
- ['wait', 'server', 'killServer', 'httpClient', 'localClient', 'publish', 'checkInbox'].
113
- forEach(function(method) {
114
- SyncScenario.prototype[method] = function() {
115
- this._commands.push([method, arguments]);
116
- }
117
- });
118
-
119
- Faye.extend(SyncScenario, {
120
- _queue: [],
121
-
122
- enqueue: function(name, block) {
123
- this._queue.push(new this(name, block));
124
- },
125
-
126
- runNext: function() {
127
- this.running = true;
128
- var scenario = this._queue.shift();
129
- if (!scenario) return;
130
- scenario.run();
131
- }
132
- });
133
-
134
- exports.run = function(name, block) {
135
- SyncScenario.enqueue(name, block);
136
- if (!SyncScenario.running) SyncScenario.runNext();
137
- };
138
-
@@ -1,195 +0,0 @@
1
- var Scenario = require('./scenario'),
2
- faye = require('../build/faye'),
3
- assert = require('assert');
4
-
5
- (function() {
6
- var tree = new Faye.Channel.Tree();
7
- var list = '/foo/bar /foo/boo /foo /foobar /foo/bar/boo /foobar/boo /foo/* /foo/**'.split(' ');
8
-
9
- Faye.each(list, function(c, i) { tree.set(c, i + 1) });
10
-
11
- assert.deepEqual(tree.glob('/foo/*').sort(), [1,2,7,8]);
12
- assert.deepEqual(tree.glob('/foo/bar').sort(), [1,7,8]);
13
- assert.deepEqual(tree.glob('/foo/**').sort(), [1,2,5,7,8]);
14
- assert.deepEqual(tree.glob('/foo/bar/boo').sort(), [5,8]);
15
-
16
- tree.set('/channels/hello', 'A');
17
- tree.set('/channels/name', 'B');
18
- tree.set('/channels/nested/hello', 'C');
19
-
20
- assert.deepEqual(tree.glob('/channels/**').sort(), ['A','B','C']);
21
- })();
22
-
23
- Scenario.run("Server goes away, subscriptions should be revived",
24
- function() { with(this) {
25
- server(8000);
26
- httpClient('A', ['/channels/a']);
27
- httpClient('B', []);
28
- killServer();
29
- wait(6);
30
- server(8000);
31
- wait(22);
32
- publish('B', '/channels/a', {hello: 'world'});
33
- checkInbox({
34
- A: {
35
- '/channels/a': [{hello: 'world'}]
36
- },
37
- B: {}
38
- });
39
- }});
40
-
41
- Scenario.run("Two HTTP clients, no messages delivered",
42
- function() { with(this) {
43
- server(8000);
44
- httpClient('A', ['/channels/a']);
45
- httpClient('B', []);
46
- publish('B', '/channels/b', {hello: 'world'});
47
- checkInbox({
48
- A: {},
49
- B: {}
50
- });
51
- }});
52
-
53
- Scenario.run("Two HTTP clients, single subscription",
54
- function() { with(this) {
55
- server(8000);
56
- httpClient('A', ['/channels/a']);
57
- httpClient('B', []);
58
- publish('B', '/channels/a', {hello: 'world'});
59
- checkInbox({
60
- A: {
61
- '/channels/a': [{hello: 'world'}]
62
- },
63
- B: {}
64
- });
65
- }});
66
-
67
- Scenario.run("Two HTTP clients, multiple subscriptions",
68
- function() { with(this) {
69
- server(8000);
70
- httpClient('A', ['/channels/a', '/channels/*']);
71
- httpClient('B', []);
72
- publish('B', '/channels/a', {hello: 'world'});
73
- checkInbox({
74
- A: {
75
- '/channels/a': [{hello: 'world'}],
76
- '/channels/*': [{hello: 'world'}]
77
- },
78
- B: {}
79
- });
80
- }});
81
-
82
- Scenario.run("Three HTTP clients, single receiver",
83
- function() { with(this) {
84
- server(8000);
85
- httpClient('A', ['/channels/a']);
86
- httpClient('B', []);
87
- httpClient('C', ['/channels/c']);
88
- publish('B', '/channels/a', {chunky: 'bacon'});
89
- checkInbox({
90
- A: {
91
- '/channels/a': [{chunky: 'bacon'}]
92
- },
93
- B: {},
94
- C: {}
95
- });
96
- }});
97
-
98
- Scenario.run("Three HTTP clients, multiple receivers",
99
- function() { with(this) {
100
- server(8000);
101
- httpClient('A', ['/channels/shared']);
102
- httpClient('B', []);
103
- httpClient('C', ['/channels/shared']);
104
- publish('B', '/channels/shared', {chunky: 'bacon'});
105
- checkInbox({
106
- A: {
107
- '/channels/shared': [{chunky: 'bacon'}]
108
- },
109
- B: {},
110
- C: {
111
- '/channels/shared': [{chunky: 'bacon'}]
112
- }
113
- });
114
- }});
115
-
116
- Scenario.run("Two HTTP clients, single wildcard on receiver",
117
- function() { with(this) {
118
- server(8000);
119
- httpClient('A', ['/channels/*']);
120
- httpClient('B', []);
121
- publish('B', '/channels/anything', {msg: 'hey'});
122
- checkInbox({
123
- A: {
124
- '/channels/*': [{msg: 'hey'}]
125
- },
126
- B: {}
127
- });
128
- }});
129
-
130
- Scenario.run("Two HTTP clients, single wildcard on sender",
131
- function() { with(this) {
132
- server(8000);
133
- httpClient('A', ['/channels/name', '/channels/hello', '/channels/nested/hello']);
134
- httpClient('B', []);
135
- publish('B', '/channels/*', {msg: 'hey'});
136
- checkInbox({
137
- A: {
138
- '/channels/name': [{msg: 'hey'}],
139
- '/channels/hello': [{msg: 'hey'}]
140
- },
141
- B: {}
142
- });
143
- }});
144
-
145
- Scenario.run("Two HTTP clients, single wildcard on both",
146
- function() { with(this) {
147
- server(8000);
148
- httpClient('A', ['/channels/*']);
149
- httpClient('B', []);
150
- publish('B', '/channels/*', {msg: 'hey'});
151
- checkInbox({
152
- A: {
153
- '/channels/*': [{msg: 'hey'}]
154
- },
155
- B: {}
156
- });
157
- }});
158
-
159
- Scenario.run("Two local clients, double wildcard on sender",
160
- function() { with(this) {
161
- server(8000);
162
- localClient('A', ['/channels/name', '/channels/hello', '/channels/nested/hello']);
163
- localClient('B', []);
164
- publish('B', '/channels/**', {msg: 'hey'});
165
- checkInbox({
166
- A: {
167
- '/channels/name': [{msg: 'hey'}],
168
- '/channels/hello': [{msg: 'hey'}],
169
- '/channels/nested/hello': [{msg: 'hey'}]
170
- },
171
- B: {}
172
- });
173
- }});
174
-
175
- Scenario.run("Two local clients, one HTTP, double wildcard on sender and one subscription",
176
- function() { with(this) {
177
- server(8000);
178
- localClient('A', ['/channels/hello', '/channels/nested/hello']);
179
- localClient('B', []);
180
- httpClient('C', ['/channels/name', '/channels/foo/**']);
181
- publish('B', '/channels/**', {msg: 'hey'});
182
- checkInbox({
183
- A: {
184
- '/channels/hello': [{msg: 'hey'}],
185
- '/channels/nested/hello': [{msg: 'hey'}]
186
- },
187
- B: {},
188
- C: {
189
- '/channels/name': [{msg: 'hey'}],
190
- '/channels/foo/**': [{msg: 'hey'}],
191
- '/channels/name': [{msg: 'hey'}],
192
- }
193
- });
194
- }});
195
-