faye 0.8.8 → 0.8.9
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 +16 -10
- data/README.rdoc +1 -1
- data/lib/faye-browser-min.js +1 -1
- data/lib/faye-browser-min.js.map +2 -2
- data/lib/faye-browser.js +302 -287
- data/lib/faye.rb +21 -21
- data/lib/faye/adapters/rack_adapter.rb +50 -48
- data/lib/faye/adapters/static_server.rb +22 -22
- data/lib/faye/engines/connection.rb +13 -13
- data/lib/faye/engines/memory.rb +21 -21
- data/lib/faye/engines/proxy.rb +23 -23
- data/lib/faye/error.rb +6 -6
- data/lib/faye/mixins/logging.rb +12 -12
- data/lib/faye/mixins/publisher.rb +6 -6
- data/lib/faye/mixins/timeouts.rb +1 -1
- data/lib/faye/protocol/channel.rb +24 -24
- data/lib/faye/protocol/client.rb +71 -73
- data/lib/faye/protocol/extensible.rb +7 -7
- data/lib/faye/protocol/grammar.rb +13 -13
- data/lib/faye/protocol/server.rb +57 -57
- data/lib/faye/protocol/socket.rb +4 -4
- data/lib/faye/protocol/subscription.rb +4 -4
- data/lib/faye/transport/http.rb +13 -13
- data/lib/faye/transport/local.rb +5 -5
- data/lib/faye/transport/transport.rb +25 -25
- data/lib/faye/transport/web_socket.rb +34 -30
- data/lib/faye/util/namespace.rb +4 -4
- data/spec/browser.html +5 -5
- data/spec/javascript/channel_spec.js +3 -3
- data/spec/javascript/client_spec.js +104 -98
- data/spec/javascript/engine/memory_spec.js +1 -1
- data/spec/javascript/engine_spec.js +70 -70
- data/spec/javascript/faye_spec.js +6 -6
- data/spec/javascript/grammar_spec.js +12 -12
- data/spec/javascript/node_adapter_spec.js +46 -46
- data/spec/javascript/publisher_spec.js +4 -4
- data/spec/javascript/server/connect_spec.js +21 -21
- data/spec/javascript/server/disconnect_spec.js +15 -15
- data/spec/javascript/server/extensions_spec.js +6 -6
- data/spec/javascript/server/handshake_spec.js +18 -18
- data/spec/javascript/server/integration_spec.js +23 -23
- data/spec/javascript/server/publish_spec.js +9 -9
- data/spec/javascript/server/subscribe_spec.js +30 -30
- data/spec/javascript/server/unsubscribe_spec.js +30 -30
- data/spec/javascript/server_spec.js +15 -15
- data/spec/javascript/transport_spec.js +32 -27
- data/spec/node.js +2 -2
- data/spec/ruby/channel_spec.rb +2 -2
- data/spec/ruby/client_spec.rb +100 -92
- data/spec/ruby/engine_examples.rb +51 -51
- data/spec/ruby/faye_spec.rb +5 -5
- data/spec/ruby/grammar_spec.rb +12 -12
- data/spec/ruby/publisher_spec.rb +4 -4
- data/spec/ruby/rack_adapter_spec.rb +34 -34
- data/spec/ruby/server/connect_spec.rb +22 -22
- data/spec/ruby/server/disconnect_spec.rb +16 -16
- data/spec/ruby/server/extensions_spec.rb +8 -8
- data/spec/ruby/server/handshake_spec.rb +20 -20
- data/spec/ruby/server/integration_spec.rb +22 -24
- data/spec/ruby/server/publish_spec.rb +9 -9
- data/spec/ruby/server/subscribe_spec.rb +31 -31
- data/spec/ruby/server/unsubscribe_spec.rb +31 -31
- data/spec/ruby/server_spec.rb +17 -17
- data/spec/ruby/transport_spec.rb +23 -23
- data/spec/testswarm +23 -10
- data/spec/thin_proxy.rb +5 -5
- metadata +90 -59
data/lib/faye/protocol/client.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
module Faye
|
2
2
|
class Client
|
3
|
-
|
3
|
+
|
4
4
|
include EventMachine::Deferrable
|
5
5
|
include Publisher
|
6
6
|
include Logging
|
7
7
|
include Extensible
|
8
|
-
|
8
|
+
|
9
9
|
UNCONNECTED = 1
|
10
10
|
CONNECTING = 2
|
11
11
|
CONNECTED = 3
|
12
12
|
DISCONNECTED = 4
|
13
|
-
|
13
|
+
|
14
14
|
HANDSHAKE = 'handshake'
|
15
15
|
RETRY = 'retry'
|
16
16
|
NONE = 'none'
|
17
|
-
|
17
|
+
|
18
18
|
CONNECTION_TIMEOUT = 60.0
|
19
19
|
DEFAULT_RETRY = 5.0
|
20
|
-
|
20
|
+
|
21
21
|
attr_reader :client_id, :endpoint, :endpoints, :retry, :transports
|
22
|
-
|
22
|
+
|
23
23
|
def initialize(endpoint = nil, options = {})
|
24
24
|
info('New client created for ?', endpoint)
|
25
|
-
|
25
|
+
|
26
26
|
@options = options
|
27
27
|
@endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
|
28
28
|
@endpoints = @options[:endpoints] || {}
|
@@ -32,29 +32,27 @@ module Faye
|
|
32
32
|
@disabled = []
|
33
33
|
@retry = @options[:retry] || DEFAULT_RETRY
|
34
34
|
|
35
|
-
select_transport(MANDATORY_CONNECTION_TYPES)
|
36
|
-
|
37
35
|
@state = UNCONNECTED
|
38
36
|
@channels = Channel::Set.new
|
39
37
|
@message_id = 0
|
40
|
-
|
38
|
+
|
41
39
|
@response_callbacks = {}
|
42
|
-
|
40
|
+
|
43
41
|
@advice = {
|
44
42
|
'reconnect' => RETRY,
|
45
43
|
'interval' => 1000.0 * (@options[:interval] || Engine::INTERVAL),
|
46
44
|
'timeout' => 1000.0 * (@options[:timeout] || CONNECTION_TIMEOUT)
|
47
45
|
}
|
48
46
|
end
|
49
|
-
|
47
|
+
|
50
48
|
def disable(feature)
|
51
49
|
@disabled << feature
|
52
50
|
end
|
53
|
-
|
51
|
+
|
54
52
|
def set_header(name, value)
|
55
53
|
@headers[name.to_s] = value.to_s
|
56
54
|
end
|
57
|
-
|
55
|
+
|
58
56
|
def state
|
59
57
|
case @state
|
60
58
|
when UNCONNECTED then :UNCONNECTED
|
@@ -71,7 +69,7 @@ module Faye
|
|
71
69
|
# MAY include: * minimumVersion
|
72
70
|
# * ext
|
73
71
|
# * id
|
74
|
-
#
|
72
|
+
#
|
75
73
|
# Success Response Failed Response
|
76
74
|
# MUST include: * channel MUST include: * channel
|
77
75
|
# * version * successful
|
@@ -86,30 +84,30 @@ module Faye
|
|
86
84
|
def handshake(&block)
|
87
85
|
return if @advice['reconnect'] == NONE
|
88
86
|
return if @state != UNCONNECTED
|
89
|
-
|
87
|
+
|
90
88
|
@state = CONNECTING
|
91
|
-
|
89
|
+
|
92
90
|
info('Initiating handshake with ?', @endpoint)
|
93
|
-
|
91
|
+
select_transport(MANDATORY_CONNECTION_TYPES)
|
92
|
+
|
94
93
|
send({
|
95
94
|
'channel' => Channel::HANDSHAKE,
|
96
95
|
'version' => BAYEUX_VERSION,
|
97
96
|
'supportedConnectionTypes' => [@transport.connection_type]
|
98
|
-
|
97
|
+
|
99
98
|
}) do |response|
|
100
|
-
|
99
|
+
|
101
100
|
if response['successful']
|
102
101
|
@state = CONNECTED
|
103
102
|
@client_id = response['clientId']
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
|
104
|
+
select_transport(response['supportedConnectionTypes'])
|
105
|
+
|
108
106
|
info('Handshake successful: ?', @client_id)
|
109
|
-
|
107
|
+
|
110
108
|
subscribe(@channels.keys, true)
|
111
109
|
block.call if block_given?
|
112
|
-
|
110
|
+
|
113
111
|
else
|
114
112
|
info('Handshake unsuccessful')
|
115
113
|
EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
|
@@ -117,7 +115,7 @@ module Faye
|
|
117
115
|
end
|
118
116
|
end
|
119
117
|
end
|
120
|
-
|
118
|
+
|
121
119
|
# Request Response
|
122
120
|
# MUST include: * channel MUST include: * channel
|
123
121
|
# * clientId * successful
|
@@ -130,31 +128,31 @@ module Faye
|
|
130
128
|
def connect(&block)
|
131
129
|
return if @advice['reconnect'] == NONE or
|
132
130
|
@state == DISCONNECTED
|
133
|
-
|
131
|
+
|
134
132
|
return handshake { connect(&block) } if @state == UNCONNECTED
|
135
|
-
|
133
|
+
|
136
134
|
callback(&block)
|
137
135
|
return unless @state == CONNECTED
|
138
|
-
|
136
|
+
|
139
137
|
info('Calling deferred actions for ?', @client_id)
|
140
138
|
set_deferred_status(:succeeded)
|
141
139
|
set_deferred_status(:deferred)
|
142
|
-
|
140
|
+
|
143
141
|
return unless @connect_request.nil?
|
144
142
|
@connect_request = true
|
145
|
-
|
143
|
+
|
146
144
|
info('Initiating connection for ?', @client_id)
|
147
|
-
|
145
|
+
|
148
146
|
send({
|
149
147
|
'channel' => Channel::CONNECT,
|
150
148
|
'clientId' => @client_id,
|
151
149
|
'connectionType' => @transport.connection_type
|
152
|
-
|
150
|
+
|
153
151
|
}) do
|
154
152
|
cycle_connection
|
155
153
|
end
|
156
154
|
end
|
157
|
-
|
155
|
+
|
158
156
|
# Request Response
|
159
157
|
# MUST include: * channel MUST include: * channel
|
160
158
|
# * clientId * successful
|
@@ -165,21 +163,21 @@ module Faye
|
|
165
163
|
def disconnect
|
166
164
|
return unless @state == CONNECTED
|
167
165
|
@state = DISCONNECTED
|
168
|
-
|
166
|
+
|
169
167
|
info('Disconnecting ?', @client_id)
|
170
|
-
|
168
|
+
|
171
169
|
send({
|
172
170
|
'channel' => Channel::DISCONNECT,
|
173
171
|
'clientId' => @client_id
|
174
|
-
|
172
|
+
|
175
173
|
}) do |response|
|
176
174
|
@transport.close if response['successful']
|
177
175
|
end
|
178
|
-
|
176
|
+
|
179
177
|
info('Clearing channel listeners for ?', @client_id)
|
180
178
|
@channels = Channel::Set.new
|
181
179
|
end
|
182
|
-
|
180
|
+
|
183
181
|
# Request Response
|
184
182
|
# MUST include: * channel MUST include: * channel
|
185
183
|
# * clientId * successful
|
@@ -194,31 +192,31 @@ module Faye
|
|
194
192
|
if Array === channel
|
195
193
|
return channel.map { |c| subscribe(c, force, &block) }
|
196
194
|
end
|
197
|
-
|
195
|
+
|
198
196
|
subscription = Subscription.new(self, channel, block)
|
199
197
|
has_subscribe = @channels.has_subscription?(channel)
|
200
|
-
|
198
|
+
|
201
199
|
if has_subscribe and not force
|
202
200
|
@channels.subscribe([channel], block)
|
203
201
|
subscription.set_deferred_status(:succeeded)
|
204
202
|
return subscription
|
205
203
|
end
|
206
|
-
|
204
|
+
|
207
205
|
connect {
|
208
206
|
info('Client ? attempting to subscribe to ?', @client_id, channel)
|
209
207
|
@channels.subscribe([channel], block) unless force
|
210
|
-
|
208
|
+
|
211
209
|
send({
|
212
210
|
'channel' => Channel::SUBSCRIBE,
|
213
211
|
'clientId' => @client_id,
|
214
212
|
'subscription' => channel
|
215
|
-
|
213
|
+
|
216
214
|
}) do |response|
|
217
215
|
unless response['successful']
|
218
216
|
subscription.set_deferred_status(:failed, Error.parse(response['error']))
|
219
217
|
next @channels.unsubscribe(channel, block)
|
220
218
|
end
|
221
|
-
|
219
|
+
|
222
220
|
channels = [response['subscription']].flatten
|
223
221
|
info('Subscription acknowledged for ? to ?', @client_id, channels)
|
224
222
|
subscription.set_deferred_status(:succeeded)
|
@@ -226,7 +224,7 @@ module Faye
|
|
226
224
|
}
|
227
225
|
subscription
|
228
226
|
end
|
229
|
-
|
227
|
+
|
230
228
|
# Request Response
|
231
229
|
# MUST include: * channel MUST include: * channel
|
232
230
|
# * clientId * successful
|
@@ -241,27 +239,27 @@ module Faye
|
|
241
239
|
if Array === channel
|
242
240
|
return channel.map { |c| unsubscribe(c, &block) }
|
243
241
|
end
|
244
|
-
|
242
|
+
|
245
243
|
dead = @channels.unsubscribe(channel, block)
|
246
244
|
return unless dead
|
247
|
-
|
245
|
+
|
248
246
|
connect {
|
249
247
|
info('Client ? attempting to unsubscribe from ?', @client_id, channel)
|
250
|
-
|
248
|
+
|
251
249
|
send({
|
252
250
|
'channel' => Channel::UNSUBSCRIBE,
|
253
251
|
'clientId' => @client_id,
|
254
252
|
'subscription' => channel
|
255
|
-
|
253
|
+
|
256
254
|
}) do |response|
|
257
255
|
next unless response['successful']
|
258
|
-
|
256
|
+
|
259
257
|
channels = [response['subscription']].flatten
|
260
258
|
info('Unsubscription acknowledged for ? from ?', @client_id, channels)
|
261
259
|
end
|
262
260
|
}
|
263
261
|
end
|
264
|
-
|
262
|
+
|
265
263
|
# Request Response
|
266
264
|
# MUST include: * channel MUST include: * channel
|
267
265
|
# * data * successful
|
@@ -272,7 +270,7 @@ module Faye
|
|
272
270
|
publication = Publication.new
|
273
271
|
connect {
|
274
272
|
info('Client ? queueing published message to ?: ?', @client_id, channel, data)
|
275
|
-
|
273
|
+
|
276
274
|
send({
|
277
275
|
'channel' => channel,
|
278
276
|
'data' => data,
|
@@ -287,41 +285,41 @@ module Faye
|
|
287
285
|
}
|
288
286
|
publication
|
289
287
|
end
|
290
|
-
|
288
|
+
|
291
289
|
def receive_message(message)
|
292
290
|
pipe_through_extensions(:incoming, message) do |message|
|
293
291
|
next unless message
|
294
|
-
|
292
|
+
|
295
293
|
handle_advice(message['advice']) if message['advice']
|
296
294
|
deliver_message(message)
|
297
|
-
|
295
|
+
|
298
296
|
next unless message.has_key?('successful')
|
299
|
-
|
297
|
+
|
300
298
|
callback = @response_callbacks[message['id']]
|
301
299
|
next unless callback
|
302
|
-
|
300
|
+
|
303
301
|
@response_callbacks.delete(message['id'])
|
304
302
|
callback.call(message)
|
305
303
|
end
|
306
304
|
end
|
307
|
-
|
305
|
+
|
308
306
|
private
|
309
|
-
|
307
|
+
|
310
308
|
def select_transport(transport_types)
|
311
|
-
Transport.get(self, transport_types) do |transport|
|
309
|
+
Transport.get(self, transport_types, @disabled) do |transport|
|
312
310
|
debug('Selected ? transport for ?', transport.connection_type, transport.endpoint)
|
313
|
-
|
311
|
+
|
314
312
|
@transport = transport
|
315
313
|
@transport.cookies = @cookies
|
316
314
|
@transport.headers = @headers
|
317
|
-
|
315
|
+
|
318
316
|
transport.bind :down do
|
319
317
|
if @transport_up.nil? or @transport_up
|
320
318
|
@transport_up = false
|
321
319
|
trigger('transport:down')
|
322
320
|
end
|
323
321
|
end
|
324
|
-
|
322
|
+
|
325
323
|
transport.bind :up do
|
326
324
|
if @transport_up.nil? or not @transport_up
|
327
325
|
@transport_up = true
|
@@ -330,7 +328,7 @@ module Faye
|
|
330
328
|
end
|
331
329
|
end
|
332
330
|
end
|
333
|
-
|
331
|
+
|
334
332
|
def send(message, &callback)
|
335
333
|
message['id'] = generate_message_id
|
336
334
|
@response_callbacks[message['id']] = callback if callback
|
@@ -339,40 +337,40 @@ module Faye
|
|
339
337
|
@transport.send(message, @advice['timeout'] / 1000.0) if message
|
340
338
|
end
|
341
339
|
end
|
342
|
-
|
340
|
+
|
343
341
|
def generate_message_id
|
344
342
|
@message_id += 1
|
345
343
|
@message_id = 0 if @message_id >= 2**32
|
346
344
|
@message_id.to_s(36)
|
347
345
|
end
|
348
|
-
|
346
|
+
|
349
347
|
def handle_advice(advice)
|
350
348
|
@advice.update(advice)
|
351
|
-
|
349
|
+
|
352
350
|
if @advice['reconnect'] == HANDSHAKE and @state != DISCONNECTED
|
353
351
|
@state = UNCONNECTED
|
354
352
|
@client_id = nil
|
355
353
|
cycle_connection
|
356
354
|
end
|
357
355
|
end
|
358
|
-
|
356
|
+
|
359
357
|
def deliver_message(message)
|
360
358
|
return unless message.has_key?('channel') and message.has_key?('data')
|
361
359
|
info('Client ? calling listeners for ? with ?', @client_id, message['channel'], message['data'])
|
362
360
|
@channels.distribute_message(message)
|
363
361
|
end
|
364
|
-
|
362
|
+
|
365
363
|
def teardown_connection
|
366
364
|
return unless @connect_request
|
367
365
|
@connect_request = nil
|
368
366
|
info('Closed connection for ?', @client_id)
|
369
367
|
end
|
370
|
-
|
368
|
+
|
371
369
|
def cycle_connection
|
372
370
|
teardown_connection
|
373
371
|
EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
|
374
372
|
end
|
375
|
-
|
373
|
+
|
376
374
|
end
|
377
375
|
end
|
378
376
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Faye
|
2
2
|
module Extensible
|
3
3
|
include Logging
|
4
|
-
|
4
|
+
|
5
5
|
def add_extension(extension)
|
6
6
|
@extensions ||= []
|
7
7
|
@extensions << extension
|
8
8
|
extension.added(self) if extension.respond_to?(:added)
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def remove_extension(extension)
|
12
12
|
return unless @extensions
|
13
13
|
@extensions.delete_if do |ext|
|
@@ -16,19 +16,19 @@ module Faye
|
|
16
16
|
true
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def pipe_through_extensions(stage, message, &callback)
|
21
21
|
debug 'Passing through ? extensions: ?', stage, message
|
22
22
|
|
23
23
|
return callback.call(message) unless @extensions
|
24
24
|
extensions = @extensions.dup
|
25
|
-
|
25
|
+
|
26
26
|
pipe = lambda do |message|
|
27
27
|
next callback.call(message) unless message
|
28
|
-
|
28
|
+
|
29
29
|
extension = extensions.shift
|
30
30
|
next callback.call(message) unless extension
|
31
|
-
|
31
|
+
|
32
32
|
if extension.respond_to?(stage)
|
33
33
|
extension.__send__(stage, message, pipe)
|
34
34
|
else
|
@@ -37,7 +37,7 @@ module Faye
|
|
37
37
|
end
|
38
38
|
pipe.call(message)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -1,28 +1,28 @@
|
|
1
1
|
module Faye
|
2
2
|
module Grammar
|
3
|
-
|
3
|
+
|
4
4
|
def self.rule(&block)
|
5
5
|
source = instance_eval(&block)
|
6
6
|
%r{^#{string(source)}$}
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def self.choice(*list)
|
10
10
|
'(' + list.map(&method(:string)) * '|' + ')'
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def self.repeat(*pattern)
|
14
14
|
'(' + string(pattern) + ')*'
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def self.oneormore(*pattern)
|
18
18
|
'(' + string(pattern) + ')+'
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def self.string(item)
|
22
22
|
return item.map(&method(:string)) * '' if Array === item
|
23
23
|
String === item ? item : item.source.gsub(/^\^/, '').gsub(/\$$/, '')
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
LOWALPHA = rule {[ '[a-z]' ]}
|
27
27
|
UPALPHA = rule {[ '[A-Z]' ]}
|
28
28
|
ALPHA = rule {[ choice(LOWALPHA, UPALPHA) ]}
|
@@ -32,27 +32,27 @@ module Faye
|
|
32
32
|
STRING = rule {[ repeat(choice(ALPHANUM, MARK, ' ', '\\/', '\\*', '\\.')) ]}
|
33
33
|
TOKEN = rule {[ oneormore(choice(ALPHANUM, MARK)) ]}
|
34
34
|
INTEGER = rule {[ oneormore(DIGIT) ]}
|
35
|
-
|
35
|
+
|
36
36
|
CHANNEL_SEGMENT = rule {[ TOKEN ]}
|
37
37
|
CHANNEL_SEGMENTS = rule {[ CHANNEL_SEGMENT, repeat('\\/', CHANNEL_SEGMENT) ]}
|
38
38
|
CHANNEL_NAME = rule {[ '\\/', CHANNEL_SEGMENTS ]}
|
39
|
-
|
39
|
+
|
40
40
|
WILD_CARD = rule {[ '\\*{1,2}' ]}
|
41
41
|
CHANNEL_PATTERN = rule {[ repeat('\\/', CHANNEL_SEGMENT), '\\/', WILD_CARD ]}
|
42
|
-
|
42
|
+
|
43
43
|
VERSION_ELEMENT = rule {[ ALPHANUM, repeat(choice(ALPHANUM, '\\-', '\\_')) ]}
|
44
44
|
VERSION = rule {[ INTEGER, repeat('\\.', VERSION_ELEMENT) ]}
|
45
|
-
|
45
|
+
|
46
46
|
CLIENT_ID = rule {[ oneormore(ALPHANUM) ]}
|
47
|
-
|
47
|
+
|
48
48
|
ID = rule {[ oneormore(ALPHANUM) ]}
|
49
|
-
|
49
|
+
|
50
50
|
ERROR_MESSAGE = rule {[ STRING ]}
|
51
51
|
ERROR_ARGS = rule {[ STRING, repeat(',', STRING) ]}
|
52
52
|
ERROR_CODE = rule {[ DIGIT, DIGIT, DIGIT ]}
|
53
53
|
ERROR = rule {[ choice(string([ERROR_CODE, ':', ERROR_ARGS, ':', ERROR_MESSAGE]),
|
54
54
|
string([ERROR_CODE, ':', ':', ERROR_MESSAGE])) ]}
|
55
|
-
|
55
|
+
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|