faye 0.3.4 → 0.5.0

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

Potentially problematic release.


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

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
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: faye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ hash: 11
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - James Coglan
@@ -9,80 +15,117 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-06-20 00:00:00 +01:00
18
+ date: 2010-07-17 00:00:00 +01:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: eventmachine
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 19
30
+ segments:
31
+ - 0
32
+ - 12
23
33
  version: "0.12"
24
- version:
34
+ type: :runtime
35
+ version_requirements: *id001
25
36
  - !ruby/object:Gem::Dependency
26
37
  name: em-http-request
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
30
41
  requirements:
31
42
  - - ">="
32
43
  - !ruby/object:Gem::Version
44
+ hash: 15
45
+ segments:
46
+ - 0
47
+ - 2
33
48
  version: "0.2"
34
- version:
49
+ type: :runtime
50
+ version_requirements: *id002
35
51
  - !ruby/object:Gem::Dependency
36
52
  name: rack
37
- type: :runtime
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
40
56
  requirements:
41
57
  - - ">="
42
58
  - !ruby/object:Gem::Version
59
+ hash: 15
60
+ segments:
61
+ - 1
62
+ - 0
43
63
  version: "1.0"
44
- version:
64
+ type: :runtime
65
+ version_requirements: *id003
45
66
  - !ruby/object:Gem::Dependency
46
67
  name: thin
47
- type: :runtime
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
50
71
  requirements:
51
72
  - - ">="
52
73
  - !ruby/object:Gem::Version
74
+ hash: 11
75
+ segments:
76
+ - 1
77
+ - 2
53
78
  version: "1.2"
54
- version:
79
+ type: :runtime
80
+ version_requirements: *id004
55
81
  - !ruby/object:Gem::Dependency
56
82
  name: json
57
- type: :runtime
58
- version_requirement:
59
- version_requirements: !ruby/object:Gem::Requirement
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
60
86
  requirements:
61
87
  - - ">="
62
88
  - !ruby/object:Gem::Version
89
+ hash: 15
90
+ segments:
91
+ - 1
92
+ - 0
63
93
  version: "1.0"
64
- version:
94
+ type: :runtime
95
+ version_requirements: *id005
65
96
  - !ruby/object:Gem::Dependency
66
97
  name: rubyforge
67
- type: :development
68
- version_requirement:
69
- version_requirements: !ruby/object:Gem::Requirement
98
+ prerelease: false
99
+ requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
70
101
  requirements:
71
102
  - - ">="
72
103
  - !ruby/object:Gem::Version
73
- version: 2.0.3
74
- version:
104
+ hash: 7
105
+ segments:
106
+ - 2
107
+ - 0
108
+ - 4
109
+ version: 2.0.4
110
+ type: :development
111
+ version_requirements: *id006
75
112
  - !ruby/object:Gem::Dependency
76
113
  name: hoe
77
- type: :development
78
- version_requirement:
79
- version_requirements: !ruby/object:Gem::Requirement
114
+ prerelease: false
115
+ requirement: &id007 !ruby/object:Gem::Requirement
116
+ none: false
80
117
  requirements:
81
118
  - - ">="
82
119
  - !ruby/object:Gem::Version
120
+ hash: 23
121
+ segments:
122
+ - 2
123
+ - 6
124
+ - 0
83
125
  version: 2.6.0
84
- version:
85
- description: ""
126
+ type: :development
127
+ version_requirements: *id007
128
+ description: Simple pub/sub messaging for the web
86
129
  email:
87
130
  - jcoglan@googlemail.com
88
131
  executables: []
@@ -93,54 +136,36 @@ extra_rdoc_files:
93
136
  - History.txt
94
137
  - Manifest.txt
95
138
  - README.txt
96
- - examples/shared/public/robots.txt
97
139
  files:
98
140
  - History.txt
99
141
  - Manifest.txt
100
142
  - README.txt
101
143
  - Rakefile
102
- - jake.yml
103
- - Jakefile
104
- - build/faye.js
105
- - build/faye-client-min.js
106
- - examples/README.rdoc
107
- - examples/shared/public/index.html
108
- - examples/shared/public/favicon.ico
109
- - examples/shared/public/jquery.js
110
- - examples/shared/public/mootools.js
111
- - examples/shared/public/prototype.js
112
- - examples/shared/public/robots.txt
113
- - examples/shared/public/soapbox.js
114
- - examples/shared/public/style.css
115
- - examples/node/app.js
116
- - examples/node/client.js
117
- - examples/node/faye.js
118
- - examples/node/faye-client-min.js
119
- - examples/rack/app.rb
120
- - examples/rack/client.rb
121
- - examples/rack/config.ru
122
- - lib/faye-client-min.js
144
+ - lib/faye-browser-min.js
123
145
  - lib/faye.rb
124
- - lib/faye/channel.rb
125
- - lib/faye/client.rb
126
- - lib/faye/connection.rb
146
+ - lib/thin_extensions.rb
147
+ - lib/faye/adapters/rack_adapter.rb
148
+ - lib/faye/mixins/logging.rb
149
+ - lib/faye/mixins/publisher.rb
150
+ - lib/faye/mixins/timeouts.rb
151
+ - lib/faye/network/transport.rb
152
+ - lib/faye/protocol/channel.rb
153
+ - lib/faye/protocol/client.rb
154
+ - lib/faye/protocol/connection.rb
155
+ - lib/faye/protocol/extensible.rb
156
+ - lib/faye/protocol/grammar.rb
157
+ - lib/faye/protocol/server.rb
158
+ - lib/faye/protocol/subscription.rb
159
+ - lib/faye/util/namespace.rb
160
+ - lib/faye/util/web_socket.rb
127
161
  - lib/faye/error.rb
128
- - lib/faye/grammar.rb
129
- - lib/faye/logging.rb
130
- - lib/faye/namespace.rb
131
- - lib/faye/rack_adapter.rb
132
- - lib/faye/server.rb
133
- - lib/faye/timeouts.rb
134
- - lib/faye/transport.rb
135
- - test/scenario.js
136
162
  - test/scenario.rb
137
163
  - test/test_channel.rb
138
- - test/test_clients.js
139
164
  - test/test_clients.rb
140
165
  - test/test_grammar.rb
141
166
  - test/test_server.rb
142
167
  has_rdoc: true
143
- homepage: http://github.com/jcoglan/faye
168
+ homepage: http://faye.jcoglan.com
144
169
  licenses: []
145
170
 
146
171
  post_install_message:
@@ -150,26 +175,32 @@ rdoc_options:
150
175
  require_paths:
151
176
  - lib
152
177
  required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
153
179
  requirements:
154
180
  - - ">="
155
181
  - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
156
185
  version: "0"
157
- version:
158
186
  required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
159
188
  requirements:
160
189
  - - ">="
161
190
  - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
162
194
  version: "0"
163
- version:
164
195
  requirements: []
165
196
 
166
197
  rubyforge_project: faye
167
- rubygems_version: 1.3.5
198
+ rubygems_version: 1.3.7
168
199
  signing_key:
169
200
  specification_version: 3
170
201
  summary: ""
171
202
  test_files:
172
203
  - test/test_grammar.rb
173
204
  - test/test_server.rb
174
- - test/test_clients.rb
175
205
  - test/test_channel.rb
206
+ - test/test_clients.rb
data/Jakefile DELETED
@@ -1,13 +0,0 @@
1
- require File.join('lib', 'faye')
2
- DIR = File.dirname(__FILE__)
3
-
4
- jake_hook :build_complete do |build|
5
- FileUtils.cp build.package('faye-client').build_path(:min), DIR + '/lib/faye-client-min.js'
6
- FileUtils.cp build.package('faye-client').build_path(:min), DIR + '/examples/node/faye-client-min.js'
7
- FileUtils.cp build.package(:faye).build_path(:src), DIR + '/examples/node/faye.js'
8
-
9
- [['faye-client', :src], [:faye, :min], [:core, :src], [:core, :min]].each do |(pkg,typ)|
10
- FileUtils.rm build.package(pkg).build_path(typ)
11
- end
12
- end
13
-
@@ -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);