faye 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye might be problematic. Click here for more details.
- data/History.txt +11 -0
- data/Manifest.txt +7 -0
- data/README.txt +116 -34
- data/Rakefile +6 -1
- data/build/faye-client-min.js +1 -1
- data/build/faye.js +515 -103
- data/examples/node/app.js +4 -4
- data/examples/node/client.js +23 -0
- data/examples/node/faye-client-min.js +1 -1
- data/examples/node/faye.js +515 -103
- data/examples/rack/client.rb +25 -0
- data/examples/shared/public/index.html +0 -2
- data/jake.yml +5 -2
- data/lib/faye-client-min.js +1 -1
- data/lib/faye.rb +2 -3
- data/lib/faye/channel.rb +14 -13
- data/lib/faye/client.rb +246 -0
- data/lib/faye/connection.rb +18 -17
- data/lib/faye/namespace.rb +16 -0
- data/lib/faye/rack_adapter.rb +12 -2
- data/lib/faye/server.rb +19 -20
- data/lib/faye/transport.rb +103 -0
- data/test/scenario.js +99 -0
- data/test/test_channel.rb +19 -13
- data/test/test_clients.js +177 -0
- data/test/test_server.rb +42 -0
- metadata +23 -6
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 0.3.0 / 2010-03-01
|
2
|
+
|
3
|
+
* Add server-side clients for Node.js and Ruby environments
|
4
|
+
* Clients support both HTTP and in-process transports
|
5
|
+
* Fix ID generation in JavaScript version to 128-bit IDs
|
6
|
+
* Fix bug in interpretation of ** channel wildcard
|
7
|
+
* Users don't have to call #connect() on clients any more
|
8
|
+
* Fix timeout race conditions that were killing active connections
|
9
|
+
* Support new Node APIs from 0.1.29.
|
10
|
+
|
11
|
+
|
1
12
|
=== 0.2.2 / 2010-02-10
|
2
13
|
|
3
14
|
* Kick out requests with malformed JSON as 400s
|
data/Manifest.txt
CHANGED
@@ -14,18 +14,25 @@ examples/shared/public/robots.txt
|
|
14
14
|
examples/shared/public/soapbox.js
|
15
15
|
examples/shared/public/style.css
|
16
16
|
examples/node/app.js
|
17
|
+
examples/node/client.js
|
17
18
|
examples/node/faye.js
|
18
19
|
examples/node/faye-client-min.js
|
19
20
|
examples/rack/app.rb
|
21
|
+
examples/rack/client.rb
|
20
22
|
examples/rack/config.ru
|
21
23
|
lib/faye-client-min.js
|
22
24
|
lib/faye.rb
|
23
25
|
lib/faye/channel.rb
|
26
|
+
lib/faye/client.rb
|
24
27
|
lib/faye/connection.rb
|
25
28
|
lib/faye/error.rb
|
26
29
|
lib/faye/grammar.rb
|
30
|
+
lib/faye/namespace.rb
|
27
31
|
lib/faye/rack_adapter.rb
|
28
32
|
lib/faye/server.rb
|
33
|
+
lib/faye/transport.rb
|
34
|
+
test/scenario.js
|
29
35
|
test/test_channel.rb
|
36
|
+
test/test_clients.js
|
30
37
|
test/test_grammar.rb
|
31
38
|
test/test_server.rb
|
data/README.txt
CHANGED
@@ -2,29 +2,45 @@
|
|
2
2
|
|
3
3
|
* http://github.com/jcoglan/faye
|
4
4
|
|
5
|
-
Faye
|
6
|
-
It ships with
|
7
|
-
|
5
|
+
Faye is a set of tools for dirt-simple publish-subscribe messaging
|
6
|
+
between web clients. It ships with easy-to-use message routing servers
|
7
|
+
for Node.js and Rack applications, and clients that can be used on
|
8
|
+
the server and in the browser.
|
8
9
|
|
9
10
|
|
10
11
|
== Introduction
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
Faye is an implementation of the Bayeux prototcol (http://svn.cometd.com/trunk/bayeux/bayeux.html),
|
14
|
+
a publish-subscribe messaging protocol designed primarily to allow
|
15
|
+
client-side JavaScript programs to send messages to each other with
|
16
|
+
low latency over HTTP. It also allows for server-side clients that let
|
17
|
+
your backend applications push data to the client side.
|
18
|
+
|
19
|
+
Bayeux works by letting clients publish and subscribe to named data
|
20
|
+
channels. For example, one client may publish a message:
|
21
|
+
|
22
|
+
clientA.publish('/foo', {hello: 'world'});
|
23
|
+
|
24
|
+
And another client can subscribe to that channel to receive messages
|
25
|
+
that are published to it:
|
26
|
+
|
27
|
+
// alerts "world"
|
28
|
+
clientB.subscribe('/foo', function(message) {
|
29
|
+
alert(message.hello);
|
30
|
+
});
|
18
31
|
|
19
32
|
Faye's messaging backend was originally developed in Ruby for a toy
|
20
33
|
project of mine, but was not written to scale across multiple processes
|
21
|
-
as required for
|
22
|
-
which
|
34
|
+
as required for deployment under Passenger. It has since been ported to
|
35
|
+
Node.js which is better designed for handling highly concurrent traffic.
|
36
|
+
If you use the Ruby version, I recommend deploying it behind Thin, an
|
37
|
+
event-driver Ruby web server.
|
23
38
|
|
24
39
|
The two backends are architecturally identical, using evented messaging
|
25
|
-
throughout and maintaining subscription data in memory.
|
26
|
-
|
27
|
-
|
40
|
+
throughout and maintaining subscription data in memory. Neither is geared
|
41
|
+
up yet for running multi-process servers, but their event-driven setup
|
42
|
+
should let them handle more concurrent connections that a typical
|
43
|
+
threaded server.
|
28
44
|
|
29
45
|
|
30
46
|
== Installation
|
@@ -39,17 +55,16 @@ The Rack server is distributed as a Ruby gem:
|
|
39
55
|
|
40
56
|
== Using the client
|
41
57
|
|
42
|
-
Both backends allow you to specify a 'mount point' that the
|
43
|
-
accepts requests on. Say you set this to <tt>/
|
44
|
-
will be available from <tt>/
|
58
|
+
Both backends allow you to specify a 'mount point' that the message server
|
59
|
+
accepts requests on. Say you set this to <tt>/faye</tt>, the client script
|
60
|
+
will be available from <tt>/faye.js</tt> and should connect to <tt>/faye</tt>.
|
45
61
|
|
46
62
|
You should set up the client as follows:
|
47
63
|
|
48
|
-
<script type="text/javascript" src="/
|
64
|
+
<script type="text/javascript" src="/faye.js"></script>
|
49
65
|
|
50
66
|
<script type="text/javascript">
|
51
|
-
|
52
|
-
CometClient.connect();
|
67
|
+
fayeClient = new Faye.Client('/faye');
|
53
68
|
</script>
|
54
69
|
|
55
70
|
Take care only to have one instance of the client per page; since each one
|
@@ -58,11 +73,11 @@ and block all other Ajax calls if you use more than one client.
|
|
58
73
|
|
59
74
|
This client object can be used to publish and subscribe to named channels:
|
60
75
|
|
61
|
-
|
76
|
+
fayeClient.subscribe('/path/to/channel', function(message) {
|
62
77
|
// process received message object
|
63
78
|
});
|
64
79
|
|
65
|
-
|
80
|
+
fayeClient.publish('/some/other/channel', {foo: 'bar'});
|
66
81
|
|
67
82
|
You can publish arbitrary JavaScript objects to a channel, and the object will
|
68
83
|
be transmitted as the +message+ parameter to any subscribers to that channel.
|
@@ -75,7 +90,7 @@ supports callback polling (see below under 'Transports'). Just pass in the
|
|
75
90
|
full path to the endpoint including the domain. Faye figures out whether the
|
76
91
|
server is on the same domain and uses an appropriate transport.
|
77
92
|
|
78
|
-
|
93
|
+
fayeClient = new Faye.Client('http://example.com/faye');
|
79
94
|
|
80
95
|
|
81
96
|
=== Transports
|
@@ -87,7 +102,7 @@ low-latency connections with the server, the two required types being
|
|
87
102
|
<tt>long-polling</tt> is where the client makes an <tt>XMLHttpRequest</tt>
|
88
103
|
to the server, and the server waits until it has new messages for that client
|
89
104
|
before it returns a response. Faye's client and server backends all support
|
90
|
-
this transport. Since it uses XHR, the
|
105
|
+
this transport. Since it uses XHR, the server endpoint must be on the same
|
91
106
|
domain as the client page.
|
92
107
|
|
93
108
|
<tt>callback-polling</tt> involves the client using JSON-P to make the request.
|
@@ -96,6 +111,10 @@ client then executes. This transport does not require the client and server
|
|
96
111
|
to be on the same domain. Faye's client supports this transport, as does the
|
97
112
|
Node.js backend. The Rack backend supports it if running under Thin.
|
98
113
|
|
114
|
+
Faye also supports an <tt>in-process</tt> transport, which is used when a
|
115
|
+
server-side client has direct in-memory access to the server without going
|
116
|
+
over HTTP.
|
117
|
+
|
99
118
|
|
100
119
|
== Using the backend
|
101
120
|
|
@@ -119,8 +138,8 @@ responses and is a better choice for long-running concurrent connections.
|
|
119
138
|
|
120
139
|
Both backends support the following initialization options:
|
121
140
|
|
122
|
-
* +mount+ - the path at which the
|
123
|
-
set to <tt>/faye</tt>, the
|
141
|
+
* +mount+ - the path at which the Faye service is accessible. e.g. if
|
142
|
+
set to <tt>/faye</tt>, the Faye endpoint will be at <tt>http://yoursite.com/faye</tt>
|
124
143
|
and the client script at <tt>http://yoursite.com/faye.js</tt>.
|
125
144
|
* +timeout+ - the maximum time (seconds) to hold a long-running request
|
126
145
|
open before returning a response. This must be smaller than the timeout
|
@@ -132,7 +151,7 @@ Usage examples and a demo app are in the +examples+ directory.
|
|
132
151
|
|
133
152
|
=== Node.js backend
|
134
153
|
|
135
|
-
Here's a very simple Node web server that offloads requests to the
|
154
|
+
Here's a very simple Node web server that offloads requests to the messaging
|
136
155
|
service to Faye and deals with all other requests itself. The Faye object
|
137
156
|
returns +true+ or +false+ to indicate whether it handled the request.
|
138
157
|
You'll need <tt>faye.js</tt> and <tt>faye-client-min.js</tt> in the same
|
@@ -141,18 +160,36 @@ directory.
|
|
141
160
|
var http = require('http')
|
142
161
|
faye = require('./faye');
|
143
162
|
|
144
|
-
var
|
163
|
+
var server = new faye.NodeAdapter({mount: '/faye', timeout: 45});
|
145
164
|
|
146
165
|
http.createServer(function(request, response) {
|
147
|
-
if (
|
166
|
+
if (server.call(request, response)) return;
|
148
167
|
|
149
168
|
response.sendHeader(200, {'Content-Type': 'text/plain'});
|
150
|
-
response.
|
151
|
-
response.
|
169
|
+
response.write('Hello, non-Faye request!');
|
170
|
+
response.close();
|
152
171
|
|
153
172
|
}).listen(9292);
|
154
173
|
|
155
174
|
|
175
|
+
=== Node.js client
|
176
|
+
|
177
|
+
Faye's JavaScript client can be used server-side under Node. There are
|
178
|
+
two ways you can set a client up: either connect to as remote server
|
179
|
+
over HTTP or connect directly to the <tt>NodeAdapter</tt>. Either way,
|
180
|
+
the API for the client is exactly as it is in the browser.
|
181
|
+
|
182
|
+
// Remote client
|
183
|
+
client = new Faye.Client('http://example.com/faye');
|
184
|
+
|
185
|
+
// Local client
|
186
|
+
server = new Faye.NodeAdapter(options);
|
187
|
+
client = server.getClient();
|
188
|
+
|
189
|
+
Note <tt>getClient()</tt> returns the same client object every time you
|
190
|
+
call it, so any subscriptions you make with it are retained.
|
191
|
+
|
192
|
+
|
156
193
|
=== Rack backend
|
157
194
|
|
158
195
|
Faye can be installed as middleware in front of any Rack application. The
|
@@ -169,21 +206,66 @@ Here's a <tt>config.ru</tt> for running it with Sinatra:
|
|
169
206
|
require 'sinatra'
|
170
207
|
require 'path/to/sinatra/app'
|
171
208
|
|
172
|
-
use Faye::RackAdapter, :mount => '/
|
209
|
+
use Faye::RackAdapter, :mount => '/faye',
|
173
210
|
:timeout => 25
|
174
211
|
|
175
212
|
run Sinatra::Application
|
176
213
|
|
177
|
-
This functions much the same as the Node.js example; Faye catches
|
214
|
+
This functions much the same as the Node.js example; Faye catches messaging
|
178
215
|
requests and deals with them, letting all other requests fall down the
|
179
216
|
stack of Rack middlewares.
|
180
217
|
|
181
218
|
|
219
|
+
=== Rack client
|
220
|
+
|
221
|
+
Again mirroring the Node tools, Faye has a client-side Ruby client that
|
222
|
+
cna be used under EventMachine. Setup is identical:
|
223
|
+
|
224
|
+
# Remote client
|
225
|
+
client = Faye::Client.new('http://example.com/faye')
|
226
|
+
|
227
|
+
# Local client
|
228
|
+
server = Faye::RackAdapter.new(options)
|
229
|
+
client = server.get_client
|
230
|
+
|
231
|
+
Both clients must be run inside EventMachine, and can publish and
|
232
|
+
subscribe just like the JavaScript client:
|
233
|
+
|
234
|
+
EM.run {
|
235
|
+
client.subscribe('/from/*') do |message|
|
236
|
+
# do something with message hash
|
237
|
+
end
|
238
|
+
|
239
|
+
client.publish('/from/jcoglan', 'hello' => 'world')
|
240
|
+
}
|
241
|
+
|
242
|
+
|
243
|
+
== Development
|
244
|
+
|
245
|
+
If you want to hack on Faye, you'll need Node.js, Ruby and the following
|
246
|
+
gems installed:
|
247
|
+
|
248
|
+
sudo gem install eventmachine em-http-request rack thin json jake
|
249
|
+
|
250
|
+
DO NOT edit any JavaScript files outside the +javascript+ and +test+
|
251
|
+
directories. They are generated using Jake, which you should run after
|
252
|
+
editing the JavaScript source.
|
253
|
+
|
254
|
+
jake -f
|
255
|
+
|
256
|
+
Ordinarily I would keep generated files out of the repo but I'm keeping
|
257
|
+
some in here as it's currently the only place to download them.
|
258
|
+
|
259
|
+
If you want to submit patches, they're far more likely to make it in
|
260
|
+
if you update both the Ruby and JavaScript versions with equivalent
|
261
|
+
changes where appropriate.
|
262
|
+
|
263
|
+
|
182
264
|
== To-do
|
183
265
|
|
266
|
+
* Investigate WebSockets as a possible message transport
|
184
267
|
* Provide support for user-defined <tt>/service/*</tt> channels
|
185
268
|
* Allow server to scale to multiple nodes
|
186
|
-
* Provide a server-side client
|
187
269
|
|
188
270
|
|
189
271
|
== License
|
data/Rakefile
CHANGED
@@ -7,7 +7,12 @@ require './lib/faye.rb'
|
|
7
7
|
Hoe.spec('faye') do |p|
|
8
8
|
# p.rubyforge_name = 'fayex' # if different than lowercase project name
|
9
9
|
p.developer('James Coglan', 'jcoglan@googlemail.com')
|
10
|
-
p.extra_deps =
|
10
|
+
p.extra_deps = [
|
11
|
+
['eventmachine', '>= 0.12'],
|
12
|
+
['em-http-request', '>= 0.2'],
|
13
|
+
['rack', '>= 1.0'],
|
14
|
+
['json', '>= 1.0']
|
15
|
+
]
|
11
16
|
end
|
12
17
|
|
13
18
|
# vim: syntax=Ruby
|
data/build/faye-client-min.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(b.hasOwnProperty(d)&&a[d]!==b[d]){if(!a.hasOwnProperty(d)||c!==false)a[d]=b[d]}}return a};Faye.extend(Faye,{BAYEUX_VERSION:'1.0',VERSION:'0.2.2',JSONP_CALLBACK:'jsonpcallback',ID_LENGTH:128,CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},size:function(a){var b=0;this.each(a,function(){b+=1});return b},random:function(){var a=Math.pow(2,this.ID_LENGTH);return(Math.random()*a).toString(16).replace(/0*$/,'')},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Observable={on:function(a,b,c){this._1=this._1||{};var d=this._1[a]=this._1[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._1||!this._1[a])return;if(!b){delete this._1[a];return}var d=this._1[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._1||!this._1[c])return;Faye.each(this._1[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this._A=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._3=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._3!==undefined)d.call(f,c,this._3)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._3:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._3=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._3===undefined)?[]:[this._3];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._3!==undefined)g.push(b._3)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._3);return g}})});Faye.Event={_a:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._a.push({_b:a,_h:b,_s:c,_c:d,_m:f})},detach:function(a,b,c,d){var f=this._a.length,g;while(f--){g=this._a[f];if((a&&a!==g._b)||(b&&b!==g._h)||(c&&c!==g._s)||(d&&d!==g._c))continue;if(g._b.removeEventListener)g._b.removeEventListener(g._h,g._m,false);else g._b.detachEvent('on'+g._h,g._m);this._a.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._d=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._t=(typeof d==='function')?{success:d}:d;this._c=f||null;this._2=null},send:function(){if(this._i)return;var a=this._6.pathname,b=this._6.queryString();if(this._d==='GET')a+='?'+b;var c=this._d==='POST'?b:'';this._i=true;this._2=Faye.XHR.getXhrObject();this._2.open(this._d,a,true);if(this._d==='POST')this._2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._2.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._i=false;d._u();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._2.send(c)},abort:function(){this._2.abort()},_u:function(){var a=this._t;if(!a)return;return this.success()?a.success&&a.success.call(this._c,this):a.failure&&a.failure.call(this._c,this)},waiting:function(){return!!this._i},complete:function(){return this._2&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._2.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._2.responseText},status:function(){if(!this.complete())return null;return this._2.status}})};Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._n=a;this._6=b},send:function(c,d,f){c={message:JSON.stringify(c)};return this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){d.call(f,a);if(a.advice)this._n._v(a.advice);if(a.data&&a.channel)this._n._w(a)},this)},this)}}),{get:function(a,b){var c=a._6;if(b===undefined)b=this.supportedConnectionTypes();var d=Faye.URI.parse(c).isLocal()?['long-polling','callback-polling']:['callback-polling'];var f=Faye.commonElement(d,b);if(!f)throw'Could not find a usable connection type for '+c;var g=this._j[f];return new g(a,c)},register:function(a,b){this._j[a]=b;b.prototype.connectionType=a},_j:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._j,function(a,b){c.push(a)});return c}});Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){Faye.XHR.request('post',this._6,b,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f=document.getElementsByTagName('head')[0],g=document.createElement('script'),k=Faye.JSONPTransport.getCallbackName(),i=Faye.URI.parse(this._6,b);Faye.ENV[k]=function(a){Faye.ENV[k]=undefined;try{delete Faye.ENV[k]}catch(e){}f.removeChild(g);if(c)c.call(d,a)};i.params.jsonp=k;g.type='text/javascript';g.src=i.toURL();f.appendChild(g)}}),{_o:0,getCallbackName:function(){this._o+=1;return'__jsonp'+this._o+'__'}});Faye.Transport.register('callback-polling',Faye.JSONPTransport);Faye.Client=Faye.Class({_e:{},_x:{},_8:{},_y:{},_p:'handshake',_z:'retry',_q:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._0=this._e;this._k=[];this._f=new Faye.Channel.Tree();this._7={reconnect:this._z,interval:this.INTERVAL};Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this._q)return;if(this._0!==this._e)return;this._0=this._x;var d=this,f=this.generateId();this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes(),id:f},function(a){if(a.id!==f)return;if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._0=this._e}this._0=this._8;this._9=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this._q)return;if(this._7.reconnect===this._p||this._0===this._e)return this.handshake(function(){this.connect(b,c)},this);if(this._0!==this._8)return;if(this._g)return;this._g=this.generateId();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._9,connectionType:this._4.connectionType,id:this._g},function(a){if(a.id!==this._g)return;delete this._g;if(a.successful)this.connect();else setTimeout(function(){d.connect()},this._7.interval)},this);if(b)b.call(c)},disconnect:function(){if(this._0!==this._8)return;this._0=this._y;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._9});this._f=new Faye.Channel.Tree()},subscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,[d,f])},this)},this)},unsubscribe:function(c,d,f){if(this._0!==this._8)return;c=[].concat(c);this._l(c);var g=this.generateId();this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._9,subscription:c,id:g},function(b){if(b.id!==g)return;if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._f.set(a,null)},this)},this)},publish:function(a,b){if(this._0!==this._8)return;this._l([a]);this.enqueue({channel:a,data:b,clientId:this._9});if(this._r)return;var c=this;this._r=setTimeout(function(){delete c._r;c.flush()},this.MAX_DELAY*1000)},generateId:function(a){a=a||32;return Math.floor(Math.pow(2,a)*Math.random()).toString(16)},enqueue:function(a){this._k.push(a)},flush:function(){this._4.send(this._k);this._k=[]},_l:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})},_v:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this._p)this._9=null},_w:function(b){var c=this._f.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})}});if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());
|
1
|
+
if(!this.Faye)Faye={};Faye.extend=function(a,b,c){if(!b)return a;for(var d in b){if(!b.hasOwnProperty(d))continue;if(a.hasOwnProperty(d)&&c===false)continue;if(a[d]!==b[d])a[d]=b[d]}return a};Faye.extend(Faye,{VERSION:'0.3.0',BAYEUX_VERSION:'1.0',ID_LENGTH:128,JSONP_CALLBACK:'jsonpcallback',CONNECTION_TYPES:["long-polling","callback-polling"],ENV:this,random:function(a){a=a||this.ID_LENGTH;if(a>32){var b=Math.ceil(a/32),c='';while(b--)c+=this.random(32);return c}var d=Math.pow(2,a);return Math.floor(Math.random()*d).toString(16)},Grammar:{LOWALPHA:/^[a-z]$/,UPALPHA:/^[A-Z]$/,ALPHA:/^([a-z]|[A-Z])$/,DIGIT:/^[0-9]$/,ALPHANUM:/^(([a-z]|[A-Z])|[0-9])$/,MARK:/^(\-|\_|\!|\~|\(|\)|\$|\@)$/,STRING:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,TOKEN:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,INTEGER:/^([0-9])+$/,CHANNEL_SEGMENT:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+$/,CHANNEL_SEGMENTS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,CHANNEL_NAME:/^\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*$/,WILD_CARD:/^\*{1,2}$/,CHANNEL_PATTERN:/^(\/(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)))+)*\/\*{1,2}$/,VERSION_ELEMENT:/^(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*$/,VERSION:/^([0-9])+(\.(([a-z]|[A-Z])|[0-9])(((([a-z]|[A-Z])|[0-9])|\-|\_))*)*$/,CLIENT_ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ID:/^((([a-z]|[A-Z])|[0-9]))+$/,ERROR_MESSAGE:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*$/,ERROR_ARGS:/^(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*$/,ERROR_CODE:/^[0-9][0-9][0-9]$/,ERROR:/^([0-9][0-9][0-9]:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*(,(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)*:(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*|[0-9][0-9][0-9]::(((([a-z]|[A-Z])|[0-9])|(\-|\_|\!|\~|\(|\)|\$|\@)| |\/|\*|\.))*)$/},commonElement:function(a,b){for(var c=0,d=a.length;c<d;c++){if(this.indexOf(b,a[c])!==-1)return a[c]}return null},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},each:function(a,b,c){if(a instanceof Array){for(var d=0,f=a.length;d<f;d++){if(a[d]!==undefined)b.call(c||null,a[d],d)}}else{for(var g in a){if(a.hasOwnProperty(g))b.call(c||null,g,a[g])}}},filter:function(a,b,c){var d=[];this.each(a,function(){if(b.apply(c,arguments))d.push(arguments[0])});return d},size:function(a){var b=0;this.each(a,function(){b+=1});return b},enumEqual:function(c,d){if(d instanceof Array){if(!(c instanceof Array))return false;var f=c.length;if(f!==d.length)return false;while(f--){if(c[f]!==d[f])return false}return true}else{if(!(c instanceof Object))return false;if(this.size(d)!==this.size(c))return false;var g=true;this.each(c,function(a,b){g=g&&(d[a]===b)});return g}}});Faye.Class=function(a,b){if(typeof a!=='function'){b=a;a=Object}var c=function(){if(!this.initialize)return this;return this.initialize.apply(this,arguments)||this};var d=function(){};d.prototype=a.prototype;c.prototype=new d();Faye.extend(c.prototype,b);return c};Faye.Observable={on:function(a,b,c){this._0=this._0||{};var d=this._0[a]=this._0[a]||[];d.push([b,c])},stopObserving:function(a,b,c){if(!this._0||!this._0[a])return;if(!b){delete this._0[a];return}var d=this._0[a],f=d.length;while(f--){if(b&&d[f][0]!==b)continue;if(c&&d[f][1]!==c)continue;d.splice(f,1)}},fire:function(){var b=Array.prototype.slice.call(arguments),c=b.shift();if(!this._0||!this._0[c])return;Faye.each(this._0[c],function(a){a[0].apply(a[1],b.slice())})}};Faye.Channel=Faye.Class({initialize:function(a){this.__id=this.name=a},push:function(a){this.fire('message',a)}});Faye.extend(Faye.Channel.prototype,Faye.Observable);Faye.extend(Faye.Channel,{HANDSHAKE:'/meta/handshake',CONNECT:'/meta/connect',SUBSCRIBE:'/meta/subscribe',UNSUBSCRIBE:'/meta/unsubscribe',DISCONNECT:'/meta/disconnect',META:'meta',SERVICE:'service',isValid:function(a){return Faye.Grammar.CHANNEL_NAME.test(a)||Faye.Grammar.CHANNEL_PATTERN.test(a)},parse:function(a){if(!this.isValid(a))return null;return a.split('/').slice(1)},isMeta:function(a){var b=this.parse(a);return b?(b[0]===this.META):null},isService:function(a){var b=this.parse(a);return b?(b[0]===this.SERVICE):null},isSubscribable:function(a){if(!this.isValid(a))return null;return!this.isMeta(a)&&!this.isService(a)},Tree:Faye.Class({initialize:function(a){this._1=a;this._5={}},eachChild:function(c,d){Faye.each(this._5,function(a,b){c.call(d,a,b)})},each:function(c,d,f){this.eachChild(function(a,b){a=c.concat(a);b.each(a,d,f)});if(this._1!==undefined)d.call(f,c,this._1)},map:function(c,d){var f=[];this.each([],function(a,b){f.push(c.call(d,a,b))});return f},get:function(a){var b=this.traverse(a);return b?b._1:null},set:function(a,b){var c=this.traverse(a,true);if(c)c._1=b},traverse:function(a,b){if(typeof a==='string')a=Faye.Channel.parse(a);if(a===null)return null;if(a.length===0)return this;var c=this._5[a[0]];if(!c&&!b)return null;if(!c)c=this._5[a[0]]=new Faye.Channel.Tree();return c.traverse(a.slice(1),b)},findOrCreate:function(a){var b=this.get(a);if(b)return b;b=new Faye.Channel(a);this.set(a,b);return b},glob:function(f){if(typeof f==='string')f=Faye.Channel.parse(f);if(f===null)return[];if(f.length===0)return(this._1===undefined)?[]:[this._1];var g=[];if(Faye.enumEqual(f,['*'])){Faye.each(this._5,function(a,b){if(b._1!==undefined)g.push(b._1)});return g}if(Faye.enumEqual(f,['**'])){g=this.map(function(a,b){return b});if(this._1!==undefined)g.pop();return g}Faye.each(this._5,function(b,c){if(b!==f[0]&&b!=='*')return;var d=c.glob(f.slice(1));Faye.each(d,function(a){g.push(a)})});if(this._5['**'])g.push(this._5['**']._1);return g}})});Faye.Namespace=Faye.Class({initialize:function(){this._m={}},generate:function(){var a=Faye.random();while(this._m.hasOwnProperty(a))a=Faye.random();return this._m[a]=a}});Faye.Transport=Faye.extend(Faye.Class({initialize:function(a,b){this._f=a;this._6=b},send:function(c,d,f){if(!(c instanceof Array)&&!c.id)c.id=this._f._n.generate();this.request(c,function(b){if(!d)return;Faye.each([].concat(b),function(a){if(a.id===c.id)d.call(f,a);if(a.advice)this._f.handleAdvice(a.advice);if(a.data&&a.channel)this._f.sendToSubscribers(a)},this)},this)}}),{get:function(c,d){var f=c._6;if(d===undefined)d=this.supportedConnectionTypes();var g=null;Faye.each(this._g,function(a,b){if(Faye.indexOf(d,a)<0)return;if(g)return;if(b.isUsable(f))g=b});if(!g)throw'Could not find a usable connection type for '+f;return new g(c,f)},register:function(a,b){this._g[a]=b;b.prototype.connectionType=a},_g:{},supportedConnectionTypes:function(){var c=[],d;Faye.each(this._g,function(a,b){c.push(a)});return c}});Faye.Client=Faye.Class({UNCONNECTED:1,CONNECTING:2,CONNECTED:3,DISCONNECTED:4,HANDSHAKE:'handshake',RETRY:'retry',NONE:'none',DEFAULT_ENDPOINT:'/bayeux',MAX_DELAY:0.1,INTERVAL:1000.0,initialize:function(a){this._6=a||this.DEFAULT_ENDPOINT;this._4=Faye.Transport.get(this);this._2=this.UNCONNECTED;this._n=new Faye.Namespace();this._h=[];this._a=new Faye.Channel.Tree();this._9=[];this._7={reconnect:this.RETRY,interval:this.INTERVAL};if(!Faye.Event)return;Faye.Event.on(Faye.ENV,'beforeunload',this.disconnect,this)},handshake:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2!==this.UNCONNECTED)return;this._2=this.CONNECTING;var d=this;this._4.send({channel:Faye.Channel.HANDSHAKE,version:Faye.BAYEUX_VERSION,supportedConnectionTypes:Faye.Transport.supportedConnectionTypes()},function(a){if(!a.successful){setTimeout(function(){d.handshake(b,c)},this._7.interval);return this._2=this.UNCONNECTED}this._2=this.CONNECTED;this._8=a.clientId;this._4=Faye.Transport.get(this,a.supportedConnectionTypes);if(b)b.call(c)},this)},connect:function(b,c){if(this._7.reconnect===this.NONE)return;if(this._2===this.DISCONNECTED)return;if(this._7.reconnect===this.HANDSHAKE||this._2===this.UNCONNECTED)return this.handshake(function(){this.connect(b,c)},this);if(this._2===this.CONNECTING)return this._9.push([b,c]);if(this._2!==this.CONNECTED)return;Faye.each(this._9,function(a){a[0].call(a[1])});this._9=[];if(b)b.call(c);if(this._i)return;this._i=this._n.generate();var d=this;this._4.send({channel:Faye.Channel.CONNECT,clientId:this._8,connectionType:this._4.connectionType,id:this._i},function(a){delete this._i;setTimeout(function(){d.connect()},this._7.interval)},this)},disconnect:function(){if(this._2!==this.CONNECTED)return;this._2=this.DISCONNECTED;this._4.send({channel:Faye.Channel.DISCONNECT,clientId:this._8});this._a=new Faye.Channel.Tree()},subscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.SUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,[d,f])},this)},this)},this)},unsubscribe:function(c,d,f){this.connect(function(){c=[].concat(c);this._j(c);this._4.send({channel:Faye.Channel.UNSUBSCRIBE,clientId:this._8,subscription:c},function(b){if(!b.successful)return;c=[].concat(b.subscription);Faye.each(c,function(a){this._a.set(a,null)},this)},this)},this)},publish:function(b,c){this.connect(function(){this._j([b]);this._r({channel:b,data:c,clientId:this._8});if(this._o)return;var a=this;this._o=setTimeout(function(){delete a._o;a._s()},this.MAX_DELAY*1000)},this)},handleAdvice:function(a){Faye.extend(this._7,a);if(this._7.reconnect===this.HANDSHAKE)this._8=null},sendToSubscribers:function(b){var c=this._a.glob(b.channel);Faye.each(c,function(a){if(!a)return;a[0].call(a[1],b.data)})},_r:function(a){this._h.push(a)},_s:function(){this._4.send(this._h);this._h=[]},_j:function(b){Faye.each(b,function(a){if(!Faye.Channel.isValid(a))throw'"'+a+'" is not a valid channel name';if(!Faye.Channel.isSubscribable(a))throw'Clients may not subscribe to channel "'+a+'"';})}});Faye.Event={_b:[],on:function(a,b,c,d){var f=function(){c.call(d)};if(a.addEventListener)a.addEventListener(b,f,false);else a.attachEvent('on'+b,f);this._b.push({_c:a,_k:b,_t:c,_d:d,_p:f})},detach:function(a,b,c,d){var f=this._b.length,g;while(f--){g=this._b[f];if((a&&a!==g._c)||(b&&b!==g._k)||(c&&c!==g._t)||(d&&d!==g._d))continue;if(g._c.removeEventListener)g._c.removeEventListener(g._k,g._p,false);else g._c.detachEvent('on'+g._k,g._p);this._b.splice(f,1);g=null}}};Faye.Event.on(Faye.ENV,'unload',Faye.Event.detach,Faye.Event);Faye.URI=Faye.extend(Faye.Class({queryString:function(){var c=[],d;Faye.each(this.params,function(a,b){c.push(encodeURIComponent(a)+'='+encodeURIComponent(b))});return c.join('&')},isLocal:function(){var a=Faye.URI.parse(Faye.ENV.location.href);var b=(a.hostname!==this.hostname)||(a.port!==this.port)||(a.protocol!==this.protocol);return!b},toURL:function(){return this.protocol+this.hostname+':'+this.port+this.pathname+'?'+this.queryString()}}),{parse:function(d,f){if(typeof d!=='string')return d;var g=new this();var k=function(b,c){d=d.replace(c,function(a){if(a)g[b]=a;return''})};k('protocol',/^https?\:\/+/);k('hostname',/^[^\/\:]+/);k('port',/^:[0-9]+/);Faye.extend(g,{protocol:'http://',hostname:Faye.ENV.location.hostname,port:Faye.ENV.location.port},false);if(!g.port)g.port=(g.protocol==='https://')?'443':'80';g.port=g.port.replace(/\D/g,'');var i=d.split('?'),h=i.shift(),l=i.join('?'),n=l?l.split('&'):[],o=n.length,j={};while(o--){i=n[o].split('=');j[decodeURIComponent(i[0]||'')]=decodeURIComponent(i[1]||'')}Faye.extend(j,f);g.pathname=h;g.params=j;return g}});Faye.XHR={request:function(a,b,c,d,f){var g=new this.Request(a,b,c,d,f);g.send();return g},getXhrObject:function(){return Faye.ENV.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},Request:Faye.Class({initialize:function(a,b,c,d,f){this._e=a.toUpperCase();this._6=Faye.URI.parse(b,c);this._9=(typeof d==='function')?{success:d}:d;this._d=f||null;this._3=null},send:function(){if(this._l)return;var a=this._6.pathname,b=this._6.queryString();if(this._e==='GET')a+='?'+b;var c=this._e==='POST'?b:'';this._l=true;this._3=Faye.XHR.getXhrObject();this._3.open(this._e,a,true);if(this._e==='POST')this._3.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var d=this,f=function(){if(d._3.readyState!==4)return;if(g){clearInterval(g);g=null}Faye.Event.detach(Faye.ENV,'beforeunload',d.abort,d);d._l=false;d._u();d=null};var g=setInterval(f,10);Faye.Event.on(Faye.ENV,'beforeunload',this.abort,this);this._3.send(c)},abort:function(){this._3.abort()},_u:function(){var a=this._9;if(!a)return;return this.success()?a.success&&a.success.call(this._d,this):a.failure&&a.failure.call(this._d,this)},waiting:function(){return!!this._l},complete:function(){return this._3&&!this.waiting()},success:function(){if(!this.complete())return false;var a=this._3.status;return(a>=200&&a<300)||a===304||a===1223},failure:function(){if(!this.complete())return false;return!this.success()},text:function(){if(!this.complete())return null;return this._3.responseText},status:function(){if(!this.complete())return null;return this._3.status}})};if(!this.JSON){JSON={}}(function(){function l(a){return a<10?'0'+a:a}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(a){return this.getUTCFullYear()+'-'+l(this.getUTCMonth()+1)+'-'+l(this.getUTCDate())+'T'+l(this.getUTCHours())+':'+l(this.getUTCMinutes())+':'+l(this.getUTCSeconds())+'Z'};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()}}var n=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,o=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j,p,s={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},m;function r(c){o.lastIndex=0;return o.test(c)?'"'+c.replace(o,function(a){var b=s[a];return typeof b==='string'?b:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+c+'"'}function q(a,b){var c,d,f,g,k=j,i,h=b[a];if(h&&typeof h==='object'&&typeof h.toJSON==='function'){h=h.toJSON(a)}if(typeof m==='function'){h=m.call(b,a,h)}switch(typeof h){case'string':return r(h);case'number':return isFinite(h)?String(h):'null';case'boolean':case'null':return String(h);case'object':if(!h){return'null'}j+=p;i=[];if(Object.prototype.toString.apply(h)==='[object Array]'){g=h.length;for(c=0;c<g;c+=1){i[c]=q(c,h)||'null'}f=i.length===0?'[]':j?'[\n'+j+i.join(',\n'+j)+'\n'+k+']':'['+i.join(',')+']';j=k;return f}if(m&&typeof m==='object'){g=m.length;for(c=0;c<g;c+=1){d=m[c];if(typeof d==='string'){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}else{for(d in h){if(Object.hasOwnProperty.call(h,d)){f=q(d,h);if(f){i.push(r(d)+(j?': ':':')+f)}}}}f=i.length===0?'{}':j?'{\n'+j+i.join(',\n'+j)+'\n'+k+'}':'{'+i.join(',')+'}';j=k;return f}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(a,b,c){var d;j='';p='';if(typeof c==='number'){for(d=0;d<c;d+=1){p+=' '}}else if(typeof c==='string'){p=c}m=b;if(b&&typeof b!=='function'&&(typeof b!=='object'||typeof b.length!=='number')){throw new Error('JSON.stringify');}return q('',{'':a})}}if(typeof JSON.parse!=='function'){JSON.parse=function(g,k){var i;function h(a,b){var c,d,f=a[b];if(f&&typeof f==='object'){for(c in f){if(Object.hasOwnProperty.call(f,c)){d=h(f,c);if(d!==undefined){f[c]=d}else{delete f[c]}}}}return k.call(a,b,f)}n.lastIndex=0;if(n.test(g)){g=g.replace(n,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(g.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){i=eval('('+g+')');return typeof k==='function'?h({'':i},''):i}throw new SyntaxError('JSON.parse');}}}());Faye.XHRTransport=Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)};Faye.XHR.request('post',this._6,f,function(a){if(c)c.call(d,JSON.parse(a.text()))})}});Faye.XHRTransport.isUsable=function(a){return Faye.URI.parse(a).isLocal()};Faye.Transport.register('long-polling',Faye.XHRTransport);Faye.JSONPTransport=Faye.extend(Faye.Class(Faye.Transport,{request:function(b,c,d){var f={message:JSON.stringify(b)},g=document.getElementsByTagName('head')[0],k=document.createElement('script'),i=Faye.JSONPTransport.getCallbackName(),h=Faye.URI.parse(this._6,f);Faye.ENV[i]=function(a){Faye.ENV[i]=undefined;try{delete Faye.ENV[i]}catch(e){}g.removeChild(k);if(c)c.call(d,a)};h.params.jsonp=i;k.type='text/javascript';k.src=h.toURL();g.appendChild(k)}}),{_q:0,getCallbackName:function(){this._q+=1;return'__jsonp'+this._q+'__'}});Faye.JSONPTransport.isUsable=function(a){return true};Faye.Transport.register('callback-polling',Faye.JSONPTransport);
|
data/build/faye.js
CHANGED
@@ -3,23 +3,36 @@ if (!this.Faye) Faye = {};
|
|
3
3
|
Faye.extend = function(dest, source, overwrite) {
|
4
4
|
if (!source) return dest;
|
5
5
|
for (var key in source) {
|
6
|
-
if (source.hasOwnProperty(key)
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
if (!source.hasOwnProperty(key)) continue;
|
7
|
+
if (dest.hasOwnProperty(key) && overwrite === false) continue;
|
8
|
+
if (dest[key] !== source[key])
|
9
|
+
dest[key] = source[key];
|
10
10
|
}
|
11
11
|
return dest;
|
12
12
|
};
|
13
13
|
|
14
14
|
Faye.extend(Faye, {
|
15
|
+
VERSION: '0.3.0',
|
16
|
+
|
15
17
|
BAYEUX_VERSION: '1.0',
|
16
|
-
VERSION: '0.2.2',
|
17
|
-
JSONP_CALLBACK: 'jsonpcallback',
|
18
18
|
ID_LENGTH: 128,
|
19
|
+
JSONP_CALLBACK: 'jsonpcallback',
|
19
20
|
CONNECTION_TYPES: ["long-polling", "callback-polling"],
|
20
21
|
|
21
22
|
ENV: this,
|
22
23
|
|
24
|
+
random: function(bitlength) {
|
25
|
+
bitlength = bitlength || this.ID_LENGTH;
|
26
|
+
if (bitlength > 32) {
|
27
|
+
var parts = Math.ceil(bitlength / 32),
|
28
|
+
string = '';
|
29
|
+
while (parts--) string += this.random(32);
|
30
|
+
return string;
|
31
|
+
}
|
32
|
+
var field = Math.pow(2, bitlength);
|
33
|
+
return Math.floor(Math.random() * field).toString(16);
|
34
|
+
},
|
35
|
+
|
23
36
|
Grammar: {
|
24
37
|
|
25
38
|
LOWALPHA: /^[a-z]$/,
|
@@ -97,17 +110,21 @@ Faye.extend(Faye, {
|
|
97
110
|
}
|
98
111
|
},
|
99
112
|
|
113
|
+
filter: function(array, callback, scope) {
|
114
|
+
var result = [];
|
115
|
+
this.each(array, function() {
|
116
|
+
if (callback.apply(scope, arguments))
|
117
|
+
result.push(arguments[0]);
|
118
|
+
});
|
119
|
+
return result;
|
120
|
+
},
|
121
|
+
|
100
122
|
size: function(object) {
|
101
123
|
var size = 0;
|
102
124
|
this.each(object, function() { size += 1 });
|
103
125
|
return size;
|
104
126
|
},
|
105
127
|
|
106
|
-
random: function() {
|
107
|
-
var field = Math.pow(2, this.ID_LENGTH);
|
108
|
-
return (Math.random() * field).toString(16).replace(/0*$/, '');
|
109
|
-
},
|
110
|
-
|
111
128
|
enumEqual: function(actual, expected) {
|
112
129
|
if (expected instanceof Array) {
|
113
130
|
if (!(actual instanceof Array)) return false;
|
@@ -190,7 +207,7 @@ Faye.Observable = {
|
|
190
207
|
|
191
208
|
Faye.Channel = Faye.Class({
|
192
209
|
initialize: function(name) {
|
193
|
-
this.__id = this.
|
210
|
+
this.__id = this.name = name;
|
194
211
|
},
|
195
212
|
|
196
213
|
push: function(message) {
|
@@ -311,7 +328,7 @@ Faye.extend(Faye.Channel, {
|
|
311
328
|
|
312
329
|
if (Faye.enumEqual(path, ['**'])) {
|
313
330
|
list = this.map(function(key, value) { return value });
|
314
|
-
list.pop();
|
331
|
+
if (this._value !== undefined) list.pop();
|
315
332
|
return list;
|
316
333
|
}
|
317
334
|
|
@@ -324,23 +341,341 @@ Faye.extend(Faye.Channel, {
|
|
324
341
|
if (this._children['**']) list.push(this._children['**']._value);
|
325
342
|
return list;
|
326
343
|
}
|
344
|
+
})
|
345
|
+
});
|
346
|
+
|
347
|
+
|
348
|
+
Faye.Namespace = Faye.Class({
|
349
|
+
initialize: function() {
|
350
|
+
this._used = {};
|
351
|
+
},
|
352
|
+
|
353
|
+
generate: function() {
|
354
|
+
var name = Faye.random();
|
355
|
+
while (this._used.hasOwnProperty(name))
|
356
|
+
name = Faye.random();
|
357
|
+
return this._used[name] = name;
|
358
|
+
}
|
359
|
+
});
|
360
|
+
|
361
|
+
|
362
|
+
Faye.Transport = Faye.extend(Faye.Class({
|
363
|
+
initialize: function(client, endpoint) {
|
364
|
+
this._client = client;
|
365
|
+
this._endpoint = endpoint;
|
366
|
+
},
|
367
|
+
|
368
|
+
send: function(message, callback, scope) {
|
369
|
+
if (!(message instanceof Array) && !message.id)
|
370
|
+
message.id = this._client._namespace.generate();
|
327
371
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
372
|
+
this.request(message, function(responses) {
|
373
|
+
if (!callback) return;
|
374
|
+
Faye.each([].concat(responses), function(response) {
|
375
|
+
|
376
|
+
if (response.id === message.id)
|
377
|
+
callback.call(scope, response);
|
378
|
+
|
379
|
+
if (response.advice)
|
380
|
+
this._client.handleAdvice(response.advice);
|
381
|
+
|
382
|
+
if (response.data && response.channel)
|
383
|
+
this._client.sendToSubscribers(response);
|
384
|
+
|
385
|
+
}, this);
|
386
|
+
}, this);
|
387
|
+
}
|
388
|
+
}), {
|
389
|
+
get: function(client, connectionTypes) {
|
390
|
+
var endpoint = client._endpoint;
|
391
|
+
if (connectionTypes === undefined) connectionTypes = this.supportedConnectionTypes();
|
392
|
+
|
393
|
+
var candidateClass = null;
|
394
|
+
Faye.each(this._transports, function(connType, klass) {
|
395
|
+
if (Faye.indexOf(connectionTypes, connType) < 0) return;
|
396
|
+
if (candidateClass) return;
|
397
|
+
if (klass.isUsable(endpoint)) candidateClass = klass;
|
398
|
+
});
|
399
|
+
|
400
|
+
if (!candidateClass) throw 'Could not find a usable connection type for ' + endpoint;
|
401
|
+
|
402
|
+
return new candidateClass(client, endpoint);
|
403
|
+
},
|
404
|
+
|
405
|
+
register: function(type, klass) {
|
406
|
+
this._transports[type] = klass;
|
407
|
+
klass.prototype.connectionType = type;
|
408
|
+
},
|
409
|
+
|
410
|
+
_transports: {},
|
411
|
+
|
412
|
+
supportedConnectionTypes: function() {
|
413
|
+
var list = [], key;
|
414
|
+
Faye.each(this._transports, function(key, type) { list.push(key) });
|
415
|
+
return list;
|
416
|
+
}
|
417
|
+
});
|
333
418
|
|
334
|
-
Faye.each(list, function(c, i) {
|
335
|
-
glob.set(c, i + 1);
|
336
|
-
});
|
337
419
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
420
|
+
Faye.Client = Faye.Class({
|
421
|
+
UNCONNECTED: 1,
|
422
|
+
CONNECTING: 2,
|
423
|
+
CONNECTED: 3,
|
424
|
+
DISCONNECTED: 4,
|
425
|
+
|
426
|
+
HANDSHAKE: 'handshake',
|
427
|
+
RETRY: 'retry',
|
428
|
+
NONE: 'none',
|
429
|
+
|
430
|
+
DEFAULT_ENDPOINT: '/bayeux',
|
431
|
+
MAX_DELAY: 0.1,
|
432
|
+
INTERVAL: 1000.0,
|
433
|
+
|
434
|
+
initialize: function(endpoint) {
|
435
|
+
this._endpoint = endpoint || this.DEFAULT_ENDPOINT;
|
436
|
+
this._transport = Faye.Transport.get(this);
|
437
|
+
this._state = this.UNCONNECTED;
|
438
|
+
this._namespace = new Faye.Namespace();
|
439
|
+
this._outbox = [];
|
440
|
+
this._channels = new Faye.Channel.Tree();
|
441
|
+
this._callbacks = [];
|
442
|
+
|
443
|
+
this._advice = {reconnect: this.RETRY, interval: this.INTERVAL};
|
444
|
+
|
445
|
+
if (!Faye.Event) return;
|
446
|
+
Faye.Event.on(Faye.ENV, 'beforeunload', this.disconnect, this);
|
447
|
+
},
|
448
|
+
|
449
|
+
// Request
|
450
|
+
// MUST include: * channel
|
451
|
+
// * version
|
452
|
+
// * supportedConnectionTypes
|
453
|
+
// MAY include: * minimumVersion
|
454
|
+
// * ext
|
455
|
+
// * id
|
456
|
+
//
|
457
|
+
// Success Response Failed Response
|
458
|
+
// MUST include: * channel MUST include: * channel
|
459
|
+
// * version * successful
|
460
|
+
// * supportedConnectionTypes * error
|
461
|
+
// * clientId MAY include: * supportedConnectionTypes
|
462
|
+
// * successful * advice
|
463
|
+
// MAY include: * minimumVersion * version
|
464
|
+
// * advice * minimumVersion
|
465
|
+
// * ext * ext
|
466
|
+
// * id * id
|
467
|
+
// * authSuccessful
|
468
|
+
handshake: function(callback, scope) {
|
469
|
+
if (this._advice.reconnect === this.NONE) return;
|
470
|
+
if (this._state !== this.UNCONNECTED) return;
|
471
|
+
|
472
|
+
this._state = this.CONNECTING;
|
473
|
+
var self = this;
|
474
|
+
|
475
|
+
this._transport.send({
|
476
|
+
channel: Faye.Channel.HANDSHAKE,
|
477
|
+
version: Faye.BAYEUX_VERSION,
|
478
|
+
supportedConnectionTypes: Faye.Transport.supportedConnectionTypes()
|
479
|
+
|
480
|
+
}, function(response) {
|
481
|
+
|
482
|
+
if (!response.successful) {
|
483
|
+
setTimeout(function() { self.handshake(callback, scope) }, this._advice.interval);
|
484
|
+
return this._state = this.UNCONNECTED;
|
485
|
+
}
|
486
|
+
|
487
|
+
this._state = this.CONNECTED;
|
488
|
+
this._clientId = response.clientId;
|
489
|
+
this._transport = Faye.Transport.get(this, response.supportedConnectionTypes);
|
490
|
+
|
491
|
+
if (callback) callback.call(scope);
|
492
|
+
}, this);
|
493
|
+
},
|
494
|
+
|
495
|
+
// Request Response
|
496
|
+
// MUST include: * channel MUST include: * channel
|
497
|
+
// * clientId * successful
|
498
|
+
// * connectionType * clientId
|
499
|
+
// MAY include: * ext MAY include: * error
|
500
|
+
// * id * advice
|
501
|
+
// * ext
|
502
|
+
// * id
|
503
|
+
// * timestamp
|
504
|
+
connect: function(callback, scope) {
|
505
|
+
if (this._advice.reconnect === this.NONE) return;
|
506
|
+
if (this._state === this.DISCONNECTED) return;
|
507
|
+
|
508
|
+
if (this._advice.reconnect === this.HANDSHAKE || this._state === this.UNCONNECTED)
|
509
|
+
return this.handshake(function() { this.connect(callback, scope) }, this);
|
510
|
+
|
511
|
+
if (this._state === this.CONNECTING)
|
512
|
+
return this._callbacks.push([callback, scope]);
|
513
|
+
|
514
|
+
if (this._state !== this.CONNECTED) return;
|
515
|
+
|
516
|
+
Faye.each(this._callbacks, function(listener) { listener[0].call(listener[1]) });
|
517
|
+
this._callbacks = [];
|
518
|
+
if (callback) callback.call(scope);
|
519
|
+
|
520
|
+
if (this._connectionId) return;
|
521
|
+
this._connectionId = this._namespace.generate();
|
522
|
+
var self = this;
|
523
|
+
|
524
|
+
this._transport.send({
|
525
|
+
channel: Faye.Channel.CONNECT,
|
526
|
+
clientId: this._clientId,
|
527
|
+
connectionType: this._transport.connectionType,
|
528
|
+
id: this._connectionId
|
529
|
+
|
530
|
+
}, function(response) {
|
531
|
+
delete this._connectionId;
|
532
|
+
setTimeout(function() { self.connect() }, this._advice.interval);
|
533
|
+
}, this);
|
534
|
+
},
|
535
|
+
|
536
|
+
// Request Response
|
537
|
+
// MUST include: * channel MUST include: * channel
|
538
|
+
// * clientId * successful
|
539
|
+
// MAY include: * ext * clientId
|
540
|
+
// * id MAY include: * error
|
541
|
+
// * ext
|
542
|
+
// * id
|
543
|
+
disconnect: function() {
|
544
|
+
if (this._state !== this.CONNECTED) return;
|
545
|
+
this._state = this.DISCONNECTED;
|
546
|
+
|
547
|
+
this._transport.send({
|
548
|
+
channel: Faye.Channel.DISCONNECT,
|
549
|
+
clientId: this._clientId
|
550
|
+
});
|
551
|
+
|
552
|
+
this._channels = new Faye.Channel.Tree();
|
553
|
+
},
|
554
|
+
|
555
|
+
// Request Response
|
556
|
+
// MUST include: * channel MUST include: * channel
|
557
|
+
// * clientId * successful
|
558
|
+
// * subscription * clientId
|
559
|
+
// MAY include: * ext * subscription
|
560
|
+
// * id MAY include: * error
|
561
|
+
// * advice
|
562
|
+
// * ext
|
563
|
+
// * id
|
564
|
+
// * timestamp
|
565
|
+
subscribe: function(channels, callback, scope) {
|
566
|
+
this.connect(function() {
|
567
|
+
|
568
|
+
channels = [].concat(channels);
|
569
|
+
this._validateChannels(channels);
|
570
|
+
|
571
|
+
this._transport.send({
|
572
|
+
channel: Faye.Channel.SUBSCRIBE,
|
573
|
+
clientId: this._clientId,
|
574
|
+
subscription: channels
|
575
|
+
|
576
|
+
}, function(response) {
|
577
|
+
if (!response.successful) return;
|
578
|
+
|
579
|
+
channels = [].concat(response.subscription);
|
580
|
+
Faye.each(channels, function(channel) {
|
581
|
+
this._channels.set(channel, [callback, scope]);
|
582
|
+
}, this);
|
583
|
+
}, this);
|
584
|
+
|
585
|
+
}, this);
|
586
|
+
},
|
587
|
+
|
588
|
+
// Request Response
|
589
|
+
// MUST include: * channel MUST include: * channel
|
590
|
+
// * clientId * successful
|
591
|
+
// * subscription * clientId
|
592
|
+
// MAY include: * ext * subscription
|
593
|
+
// * id MAY include: * error
|
594
|
+
// * advice
|
595
|
+
// * ext
|
596
|
+
// * id
|
597
|
+
// * timestamp
|
598
|
+
unsubscribe: function(channels, callback, scope) {
|
599
|
+
this.connect(function() {
|
600
|
+
|
601
|
+
channels = [].concat(channels);
|
602
|
+
this._validateChannels(channels);
|
603
|
+
|
604
|
+
this._transport.send({
|
605
|
+
channel: Faye.Channel.UNSUBSCRIBE,
|
606
|
+
clientId: this._clientId,
|
607
|
+
subscription: channels
|
608
|
+
|
609
|
+
}, function(response) {
|
610
|
+
if (!response.successful) return;
|
611
|
+
|
612
|
+
channels = [].concat(response.subscription);
|
613
|
+
Faye.each(channels, function(channel) {
|
614
|
+
this._channels.set(channel, null);
|
615
|
+
}, this);
|
616
|
+
}, this);
|
617
|
+
|
618
|
+
}, this);
|
619
|
+
},
|
620
|
+
|
621
|
+
// Request Response
|
622
|
+
// MUST include: * channel MUST include: * channel
|
623
|
+
// * data * successful
|
624
|
+
// MAY include: * clientId MAY include: * id
|
625
|
+
// * id * error
|
626
|
+
// * ext * ext
|
627
|
+
publish: function(channel, data) {
|
628
|
+
this.connect(function() {
|
629
|
+
|
630
|
+
this._validateChannels([channel]);
|
631
|
+
|
632
|
+
this._enqueue({
|
633
|
+
channel: channel,
|
634
|
+
data: data,
|
635
|
+
clientId: this._clientId
|
636
|
+
});
|
637
|
+
|
638
|
+
if (this._timeout) return;
|
639
|
+
var self = this;
|
640
|
+
|
641
|
+
this._timeout = setTimeout(function() {
|
642
|
+
delete self._timeout;
|
643
|
+
self._flush();
|
644
|
+
}, this.MAX_DELAY * 1000);
|
645
|
+
|
646
|
+
}, this);
|
647
|
+
},
|
648
|
+
|
649
|
+
handleAdvice: function(advice) {
|
650
|
+
Faye.extend(this._advice, advice);
|
651
|
+
if (this._advice.reconnect === this.HANDSHAKE) this._clientId = null;
|
652
|
+
},
|
653
|
+
|
654
|
+
sendToSubscribers: function(message) {
|
655
|
+
var channels = this._channels.glob(message.channel);
|
656
|
+
Faye.each(channels, function(callback) {
|
657
|
+
if (!callback) return;
|
658
|
+
callback[0].call(callback[1], message.data);
|
659
|
+
});
|
660
|
+
},
|
661
|
+
|
662
|
+
_enqueue: function(message) {
|
663
|
+
this._outbox.push(message);
|
664
|
+
},
|
665
|
+
|
666
|
+
_flush: function() {
|
667
|
+
this._transport.send(this._outbox);
|
668
|
+
this._outbox = [];
|
669
|
+
},
|
670
|
+
|
671
|
+
_validateChannels: function(channels) {
|
672
|
+
Faye.each(channels, function(channel) {
|
673
|
+
if (!Faye.Channel.isValid(channel))
|
674
|
+
throw '"' + channel + '" is not a valid channel name';
|
675
|
+
if (!Faye.Channel.isSubscribable(channel))
|
676
|
+
throw 'Clients may not subscribe to channel "' + channel + '"';
|
677
|
+
});
|
678
|
+
}
|
344
679
|
});
|
345
680
|
|
346
681
|
|
@@ -392,9 +727,10 @@ Faye.Set = Faye.Class({
|
|
392
727
|
|
393
728
|
Faye.Server = Faye.Class({
|
394
729
|
initialize: function(options) {
|
395
|
-
this._options
|
396
|
-
this._channels
|
397
|
-
this._clients
|
730
|
+
this._options = options || {};
|
731
|
+
this._channels = new Faye.Channel.Tree();
|
732
|
+
this._clients = {};
|
733
|
+
this._namespace = new Faye.Namespace();
|
398
734
|
},
|
399
735
|
|
400
736
|
clientIds: function() {
|
@@ -404,7 +740,7 @@ Faye.Server = Faye.Class({
|
|
404
740
|
},
|
405
741
|
|
406
742
|
process: function(messages, local, callback) {
|
407
|
-
messages = (messages
|
743
|
+
messages = [].concat(messages);
|
408
744
|
var processed = 0, responses = [];
|
409
745
|
|
410
746
|
Faye.each(messages, function(message) {
|
@@ -417,29 +753,23 @@ Faye.Server = Faye.Class({
|
|
417
753
|
},
|
418
754
|
|
419
755
|
flushConnection: function(messages) {
|
420
|
-
messages = (messages
|
756
|
+
messages = [].concat(messages);
|
421
757
|
Faye.each(messages, function(message) {
|
422
758
|
var client = this._clients[message.clientId];
|
423
759
|
if (client) client.flush();
|
424
760
|
}, this);
|
425
761
|
},
|
426
762
|
|
427
|
-
_generateId: function() {
|
428
|
-
var id = Faye.random();
|
429
|
-
while (this._clients.hasOwnProperty(id)) id = Faye.random();
|
430
|
-
return this._connection(id).id;
|
431
|
-
},
|
432
|
-
|
433
763
|
_connection: function(id) {
|
434
764
|
if (this._clients.hasOwnProperty(id)) return this._clients[id];
|
435
765
|
var client = new Faye.Connection(id, this._options);
|
436
|
-
client.on('
|
766
|
+
client.on('staleClient', this._destroyClient, this);
|
437
767
|
return this._clients[id] = client;
|
438
768
|
},
|
439
769
|
|
440
770
|
_destroyClient: function(client) {
|
441
771
|
client.disconnect();
|
442
|
-
client.stopObserving('
|
772
|
+
client.stopObserving('staleClient', this._destroyClient, this);
|
443
773
|
delete this._clients[client.id];
|
444
774
|
},
|
445
775
|
|
@@ -448,6 +778,9 @@ Faye.Server = Faye.Class({
|
|
448
778
|
channel = message.channel,
|
449
779
|
response;
|
450
780
|
|
781
|
+
message.__id = Faye.random();
|
782
|
+
Faye.each(this._channels.glob(channel), function(c) { c.push(message) });
|
783
|
+
|
451
784
|
if (Faye.Channel.isMeta(channel)) {
|
452
785
|
response = this[Faye.Channel.parse(channel)[1]](message, local);
|
453
786
|
|
@@ -473,18 +806,19 @@ Faye.Server = Faye.Class({
|
|
473
806
|
if (!message.clientId || Faye.Channel.isService(channel))
|
474
807
|
return callback([]);
|
475
808
|
|
476
|
-
message.__id = Faye.random();
|
477
|
-
Faye.each(this._channels.glob(channel), function(c) { c.push(message) });
|
478
|
-
|
479
809
|
callback( { channel: channel,
|
480
810
|
successful: true,
|
481
811
|
id: message.id } );
|
482
812
|
},
|
483
813
|
|
814
|
+
// MUST contain * version
|
815
|
+
// * supportedConnectionTypes
|
816
|
+
// MAY contain * minimumVersion
|
817
|
+
// * ext
|
818
|
+
// * id
|
484
819
|
handshake: function(message, local) {
|
485
820
|
var response = { channel: Faye.Channel.HANDSHAKE,
|
486
821
|
version: Faye.BAYEUX_VERSION,
|
487
|
-
supportedConnectionTypes: Faye.CONNECTION_TYPES,
|
488
822
|
id: message.id };
|
489
823
|
|
490
824
|
if (!message.version)
|
@@ -493,23 +827,32 @@ Faye.Server = Faye.Class({
|
|
493
827
|
var clientConns = message.supportedConnectionTypes,
|
494
828
|
commonConns;
|
495
829
|
|
496
|
-
if (
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
830
|
+
if (!local) {
|
831
|
+
response.supportedConnectionTypes = Faye.CONNECTION_TYPES;
|
832
|
+
|
833
|
+
if (clientConns) {
|
834
|
+
commonConns = Faye.filter(clientConns, function(conn) {
|
835
|
+
return Faye.indexOf(Faye.CONNECTION_TYPES, conn) !== -1;
|
836
|
+
});
|
837
|
+
if (commonConns.length === 0)
|
838
|
+
response.error = Faye.Error.conntypeMismatch(clientConns);
|
839
|
+
} else {
|
840
|
+
response.error = Faye.Error.parameterMissing('supportedConnectionTypes');
|
841
|
+
}
|
504
842
|
}
|
505
843
|
|
506
844
|
response.successful = !response.error;
|
507
845
|
if (!response.successful) return response;
|
508
846
|
|
509
|
-
|
847
|
+
var clientId = this._namespace.generate();
|
848
|
+
response.clientId = this._connection(clientId).id;
|
510
849
|
return response;
|
511
850
|
},
|
512
851
|
|
852
|
+
// MUST contain * clientId
|
853
|
+
// * connectionType
|
854
|
+
// MAY contain * ext
|
855
|
+
// * id
|
513
856
|
connect: function(message, local) {
|
514
857
|
var response = { channel: Faye.Channel.CONNECT,
|
515
858
|
id: message.id };
|
@@ -529,6 +872,9 @@ Faye.Server = Faye.Class({
|
|
529
872
|
return response;
|
530
873
|
},
|
531
874
|
|
875
|
+
// MUST contain * clientId
|
876
|
+
// MAY contain * ext
|
877
|
+
// * id
|
532
878
|
disconnect: function(message, local) {
|
533
879
|
var response = { channel: Faye.Channel.DISCONNECT,
|
534
880
|
id: message.id };
|
@@ -548,6 +894,10 @@ Faye.Server = Faye.Class({
|
|
548
894
|
return response;
|
549
895
|
},
|
550
896
|
|
897
|
+
// MUST contain * clientId
|
898
|
+
// * subscription
|
899
|
+
// MAY contain * ext
|
900
|
+
// * id
|
551
901
|
subscribe: function(message, local) {
|
552
902
|
var response = { channel: Faye.Channel.SUBSCRIBE,
|
553
903
|
clientId: message.clientId,
|
@@ -557,7 +907,7 @@ Faye.Server = Faye.Class({
|
|
557
907
|
client = clientId ? this._clients[clientId] : null,
|
558
908
|
subscription = message.subscription;
|
559
909
|
|
560
|
-
subscription = (subscription
|
910
|
+
subscription = [].concat(subscription);
|
561
911
|
|
562
912
|
if (!client) response.error = Faye.Error.clientUnknown(clientId);
|
563
913
|
if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
|
@@ -567,8 +917,8 @@ Faye.Server = Faye.Class({
|
|
567
917
|
|
568
918
|
Faye.each(subscription, function(channel) {
|
569
919
|
if (response.error) return;
|
570
|
-
if (!Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
|
571
|
-
if (!Faye.Channel.isValid(channel))
|
920
|
+
if (!local && !Faye.Channel.isSubscribable(channel)) response.error = Faye.Error.channelForbidden(channel);
|
921
|
+
if (!Faye.Channel.isValid(channel)) response.error = Faye.Error.channelInvalid(channel);
|
572
922
|
|
573
923
|
if (response.error) return;
|
574
924
|
channel = this._channels.findOrCreate(channel);
|
@@ -579,6 +929,10 @@ Faye.Server = Faye.Class({
|
|
579
929
|
return response;
|
580
930
|
},
|
581
931
|
|
932
|
+
// MUST contain * clientId
|
933
|
+
// * subscription
|
934
|
+
// MAY contain * ext
|
935
|
+
// * id
|
582
936
|
unsubscribe: function(message, local) {
|
583
937
|
var response = { channel: Faye.Channel.UNSUBSCRIBE,
|
584
938
|
clientId: message.clientId,
|
@@ -588,7 +942,7 @@ Faye.Server = Faye.Class({
|
|
588
942
|
client = clientId ? this._clients[clientId] : null,
|
589
943
|
subscription = message.subscription;
|
590
944
|
|
591
|
-
subscription = (subscription
|
945
|
+
subscription = [].concat(subscription);
|
592
946
|
|
593
947
|
if (!client) response.error = Faye.Error.clientUnknown(clientId);
|
594
948
|
if (!clientId) response.error = Faye.Error.parameterMissing('clientId');
|
@@ -611,16 +965,19 @@ Faye.Server = Faye.Class({
|
|
611
965
|
|
612
966
|
|
613
967
|
Faye.Connection = Faye.Class({
|
968
|
+
MAX_DELAY: 0.1,
|
969
|
+
INTERVAL: 1.0,
|
970
|
+
TIMEOUT: 60.0,
|
971
|
+
|
614
972
|
initialize: function(id, options) {
|
615
973
|
this.id = id;
|
616
974
|
this._options = options;
|
617
|
-
this._observers = {};
|
618
975
|
this._channels = new Faye.Set();
|
619
976
|
this._inbox = new Faye.Set();
|
620
977
|
},
|
621
978
|
|
622
|
-
|
623
|
-
return this._options.timeout ||
|
979
|
+
getTimeout: function() {
|
980
|
+
return this._options.timeout || this.TIMEOUT;
|
624
981
|
},
|
625
982
|
|
626
983
|
_onMessage: function(event) {
|
@@ -644,10 +1001,14 @@ Faye.Connection = Faye.Class({
|
|
644
1001
|
this.on('flush', callback);
|
645
1002
|
if (this._connected) return;
|
646
1003
|
|
647
|
-
this.
|
648
|
-
|
1004
|
+
this._connected = true;
|
1005
|
+
|
1006
|
+
if (this._deletionTimeout) {
|
1007
|
+
clearTimeout(this._deletionTimeout);
|
1008
|
+
delete this._deletionTimeout;
|
1009
|
+
}
|
649
1010
|
|
650
|
-
|
1011
|
+
this._beginDeliveryTimeout();
|
651
1012
|
this._beginConnectionTimeout();
|
652
1013
|
},
|
653
1014
|
|
@@ -673,7 +1034,7 @@ Faye.Connection = Faye.Class({
|
|
673
1034
|
|
674
1035
|
var self = this;
|
675
1036
|
this._deliveryTimeout = setTimeout(function () { self.flush() },
|
676
|
-
|
1037
|
+
this.MAX_DELAY * 1000);
|
677
1038
|
},
|
678
1039
|
|
679
1040
|
_beginConnectionTimeout: function() {
|
@@ -682,7 +1043,7 @@ Faye.Connection = Faye.Class({
|
|
682
1043
|
|
683
1044
|
var self = this;
|
684
1045
|
this._connectionTimeout = setTimeout(function() { self.flush() },
|
685
|
-
this.
|
1046
|
+
this.getTimeout() * 1000);
|
686
1047
|
},
|
687
1048
|
|
688
1049
|
_releaseConnection: function() {
|
@@ -701,25 +1062,17 @@ Faye.Connection = Faye.Class({
|
|
701
1062
|
},
|
702
1063
|
|
703
1064
|
_scheduleForDeletion: function() {
|
704
|
-
if (this.
|
705
|
-
this._markForDeletion = true;
|
1065
|
+
if (this._deletionTimeout) return;
|
706
1066
|
var self = this;
|
707
1067
|
|
708
|
-
setTimeout(function() {
|
709
|
-
|
710
|
-
|
711
|
-
}, 10000 * Faye.Connection.INTERVAL);
|
1068
|
+
this._deletionTimeout = setTimeout(function() {
|
1069
|
+
self.fire('staleClient', self);
|
1070
|
+
}, 10 * 1000 * this.INTERVAL);
|
712
1071
|
}
|
713
1072
|
});
|
714
1073
|
|
715
1074
|
Faye.extend(Faye.Connection.prototype, Faye.Observable);
|
716
1075
|
|
717
|
-
Faye.extend(Faye.Connection, {
|
718
|
-
MAX_DELAY: 0.1,
|
719
|
-
INTERVAL: 1.0,
|
720
|
-
TIMEOUT: 60.0
|
721
|
-
});
|
722
|
-
|
723
1076
|
|
724
1077
|
Faye.Error = Faye.Class({
|
725
1078
|
initialize: function(code, args, message) {
|
@@ -786,33 +1139,100 @@ Faye.Error.serverError = function() {
|
|
786
1139
|
|
787
1140
|
|
788
1141
|
|
1142
|
+
Faye.NodeHttpTransport = Faye.Class(Faye.Transport, {
|
1143
|
+
request: function(message, callback, scope) {
|
1144
|
+
var params = {message: JSON.stringify(message)},
|
1145
|
+
request = this.createRequest();
|
1146
|
+
|
1147
|
+
request.write(querystring.stringify(params));
|
1148
|
+
|
1149
|
+
request.addListener('response', function(response) {
|
1150
|
+
if (!callback) return;
|
1151
|
+
response.addListener('data', function(chunk) {
|
1152
|
+
callback.call(scope, JSON.parse(chunk));
|
1153
|
+
});
|
1154
|
+
});
|
1155
|
+
request.close();
|
1156
|
+
},
|
1157
|
+
|
1158
|
+
createRequest: function() {
|
1159
|
+
var uri = url.parse(this._endpoint),
|
1160
|
+
client = http.createClient(uri.port, uri.hostname);
|
1161
|
+
|
1162
|
+
return client.request('POST', uri.pathname, {
|
1163
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
1164
|
+
});
|
1165
|
+
}
|
1166
|
+
});
|
1167
|
+
|
1168
|
+
Faye.NodeHttpTransport.isUsable = function(endpoint) {
|
1169
|
+
return typeof endpoint === 'string';
|
1170
|
+
};
|
1171
|
+
|
1172
|
+
Faye.Transport.register('long-polling', Faye.NodeHttpTransport);
|
1173
|
+
|
1174
|
+
Faye.NodeLocalTransport = Faye.Class(Faye.Transport, {
|
1175
|
+
request: function(message, callback, scope) {
|
1176
|
+
this._endpoint.process(message, true, function(response) {
|
1177
|
+
callback.call(scope, response);
|
1178
|
+
});
|
1179
|
+
}
|
1180
|
+
});
|
1181
|
+
|
1182
|
+
Faye.NodeLocalTransport.isUsable = function(endpoint) {
|
1183
|
+
return endpoint instanceof Faye.Server;
|
1184
|
+
};
|
1185
|
+
|
1186
|
+
Faye.Transport.register('in-process', Faye.NodeLocalTransport);
|
1187
|
+
|
1188
|
+
|
789
1189
|
var path = require('path'),
|
790
|
-
|
1190
|
+
fs = require('fs'),
|
791
1191
|
sys = require('sys'),
|
792
1192
|
url = require('url'),
|
1193
|
+
http = require('http'),
|
793
1194
|
querystring = require('querystring');
|
794
1195
|
|
795
1196
|
Faye.NodeAdapter = Faye.Class({
|
1197
|
+
DEFAULT_ENDPOINT: '/bayeux',
|
1198
|
+
SCRIPT_PATH: path.dirname(__filename) + '/faye-client-min.js',
|
1199
|
+
|
1200
|
+
TYPE_JSON: {'Content-Type': 'text/json'},
|
1201
|
+
TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
|
1202
|
+
TYPE_TEXT: {'Content-Type': 'text/plain'},
|
1203
|
+
|
796
1204
|
initialize: function(options) {
|
797
1205
|
this._options = options || {};
|
798
|
-
this._endpoint = this._options.mount ||
|
1206
|
+
this._endpoint = this._options.mount || this.DEFAULT_ENDPOINT;
|
799
1207
|
this._script = this._endpoint + '.js';
|
800
1208
|
this._server = new Faye.Server(this._options);
|
801
1209
|
},
|
802
1210
|
|
1211
|
+
getClient: function() {
|
1212
|
+
return this._client = this._client || new Faye.Client(this._server);
|
1213
|
+
},
|
1214
|
+
|
1215
|
+
run: function(port) {
|
1216
|
+
var self = this;
|
1217
|
+
http.createServer(function(request, response) {
|
1218
|
+
self.call(request, response);
|
1219
|
+
}).listen(Number(port));
|
1220
|
+
},
|
1221
|
+
|
803
1222
|
call: function(request, response) {
|
804
|
-
var requestUrl = url.parse(request.url, true)
|
1223
|
+
var requestUrl = url.parse(request.url, true),
|
1224
|
+
self = this;
|
1225
|
+
|
805
1226
|
switch (requestUrl.pathname) {
|
806
1227
|
|
807
1228
|
case this._endpoint:
|
808
|
-
var isGet = (request.method === 'GET')
|
809
|
-
self = this;
|
1229
|
+
var isGet = (request.method === 'GET');
|
810
1230
|
|
811
1231
|
if (isGet)
|
812
1232
|
this._callWithParams(request, response, requestUrl.query);
|
813
1233
|
|
814
1234
|
else
|
815
|
-
request.addListener('
|
1235
|
+
request.addListener('data', function(chunk) {
|
816
1236
|
self._callWithParams(request, response, querystring.parse(chunk));
|
817
1237
|
});
|
818
1238
|
|
@@ -820,10 +1240,10 @@ Faye.NodeAdapter = Faye.Class({
|
|
820
1240
|
break;
|
821
1241
|
|
822
1242
|
case this._script:
|
823
|
-
|
824
|
-
response.sendHeader(200,
|
825
|
-
response.
|
826
|
-
response.
|
1243
|
+
fs.readFile(this.SCRIPT_PATH, function(err, content) {
|
1244
|
+
response.sendHeader(200, self.TYPE_SCRIPT);
|
1245
|
+
response.write(content);
|
1246
|
+
response.close();
|
827
1247
|
});
|
828
1248
|
return true;
|
829
1249
|
break;
|
@@ -837,7 +1257,7 @@ Faye.NodeAdapter = Faye.Class({
|
|
837
1257
|
var message = JSON.parse(params.message),
|
838
1258
|
jsonp = params.jsonp || Faye.JSONP_CALLBACK,
|
839
1259
|
isGet = (request.method === 'GET'),
|
840
|
-
type = isGet ?
|
1260
|
+
type = isGet ? this.TYPE_SCRIPT : this.TYPE_JSON;
|
841
1261
|
|
842
1262
|
if (isGet) this._server.flushConnection(message);
|
843
1263
|
|
@@ -845,24 +1265,16 @@ Faye.NodeAdapter = Faye.Class({
|
|
845
1265
|
var body = JSON.stringify(replies);
|
846
1266
|
if (isGet) body = jsonp + '(' + body + ');';
|
847
1267
|
response.sendHeader(200, type);
|
848
|
-
response.
|
849
|
-
response.
|
1268
|
+
response.write(body);
|
1269
|
+
response.close();
|
850
1270
|
});
|
851
1271
|
} catch (e) {
|
852
|
-
response.sendHeader(400,
|
853
|
-
response.
|
854
|
-
response.
|
1272
|
+
response.sendHeader(400, this.TYPE_TEXT);
|
1273
|
+
response.write('Bad request');
|
1274
|
+
response.close();
|
855
1275
|
}
|
856
1276
|
}
|
857
1277
|
});
|
858
1278
|
|
859
|
-
|
860
|
-
|
861
|
-
SCRIPT_PATH: path.dirname(__filename) + '/faye-client-min.js',
|
862
|
-
|
863
|
-
TYPE_JSON: {'Content-Type': 'text/json'},
|
864
|
-
TYPE_SCRIPT: {'Content-Type': 'text/javascript'},
|
865
|
-
TYPE_TEXT: {'Content-Type': 'text/plain'}
|
866
|
-
});
|
867
|
-
|
868
|
-
exports.NodeAdapter = Faye.NodeAdapter;
|
1279
|
+
exports.NodeAdapter = Faye.NodeAdapter;
|
1280
|
+
exports.Client = Faye.Client;
|