faye 1.0.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/faye/error.rb CHANGED
@@ -46,4 +46,3 @@ module Faye
46
46
 
47
47
  end
48
48
  end
49
-
@@ -12,4 +12,3 @@ module Faye
12
12
 
13
13
  end
14
14
  end
15
-
@@ -33,4 +33,3 @@ module Faye
33
33
 
34
34
  end
35
35
  end
36
-
@@ -16,4 +16,3 @@ module Faye
16
16
 
17
17
  end
18
18
  end
19
-
@@ -24,4 +24,3 @@ module Faye
24
24
  end
25
25
  end
26
26
  end
27
-
@@ -75,7 +75,7 @@ module Faye
75
75
  end
76
76
 
77
77
  class Set
78
- def initialize(parent = nil, value = nil)
78
+ def initialize
79
79
  @channels = {}
80
80
  end
81
81
 
@@ -91,18 +91,17 @@ module Faye
91
91
  @channels.has_key?(name)
92
92
  end
93
93
 
94
- def subscribe(names, callback)
95
- return unless callback
94
+ def subscribe(names, subscription)
96
95
  names.each do |name|
97
96
  channel = @channels[name] ||= Channel.new(name)
98
- channel.bind(:message, &callback)
97
+ channel.bind(:message, &subscription)
99
98
  end
100
99
  end
101
100
 
102
- def unsubscribe(name, callback)
101
+ def unsubscribe(name, subscription)
103
102
  channel = @channels[name]
104
103
  return false unless channel
105
- channel.unbind(:message, &callback)
104
+ channel.unbind(:message, &subscription)
106
105
  if channel.unused?
107
106
  remove(name)
108
107
  true
@@ -115,11 +114,10 @@ module Faye
115
114
  channels = Channel.expand(message['channel'])
116
115
  channels.each do |name|
117
116
  channel = @channels[name]
118
- channel.trigger(:message, message['data']) if channel
117
+ channel.trigger(:message, message) if channel
119
118
  end
120
119
  end
121
120
  end
122
121
 
123
122
  end
124
123
  end
125
-
@@ -6,59 +6,41 @@ module Faye
6
6
  include Logging
7
7
  include Extensible
8
8
 
9
- UNCONNECTED = 1
10
- CONNECTING = 2
11
- CONNECTED = 3
12
- DISCONNECTED = 4
9
+ UNCONNECTED = 1
10
+ CONNECTING = 2
11
+ CONNECTED = 3
12
+ DISCONNECTED = 4
13
13
 
14
- HANDSHAKE = 'handshake'
15
- RETRY = 'retry'
16
- NONE = 'none'
14
+ HANDSHAKE = 'handshake'
15
+ RETRY = 'retry'
16
+ NONE = 'none'
17
17
 
18
- CONNECTION_TIMEOUT = 60.0
19
- DEFAULT_RETRY = 5.0
20
- MAX_REQUEST_SIZE = 2048
18
+ CONNECTION_TIMEOUT = 60.0
21
19
 
22
- attr_reader :cookies, :endpoint, :endpoints, :headers, :max_request_size, :retry, :transports
20
+ extend Forwardable
21
+ def_delegators :@dispatcher, :add_websocket_extension, :disable, :set_header
23
22
 
24
23
  def initialize(endpoint = nil, options = {})
24
+ ::WebSocket::Driver.validate_options(options, [:interval, :timeout, :endpoints, :proxy, :retry, :scheduler, :websocket_extensions, :tls])
25
25
  super()
26
26
  info('New client created for ?', endpoint)
27
27
 
28
- @options = options
29
- @endpoint = Faye.parse_url(endpoint || RackAdapter::DEFAULT_ENDPOINT)
30
- @endpoints = @options[:endpoints] || {}
31
- @transports = {}
32
- @cookies = CookieJar::Jar.new
33
- @headers = {}
34
- @disabled = []
35
- @retry = @options[:retry] || DEFAULT_RETRY
36
-
37
- @endpoints.each do |key, value|
38
- @endpoints[key] = Faye.parse_url(value)
39
- end
40
-
41
- @max_request_size = MAX_REQUEST_SIZE
42
-
43
- @state = UNCONNECTED
44
28
  @channels = Channel::Set.new
29
+ @dispatcher = Dispatcher.new(self, endpoint || RackAdapter::DEFAULT_ENDPOINT, options)
30
+
45
31
  @message_id = 0
32
+ @state = UNCONNECTED
46
33
 
47
34
  @response_callbacks = {}
48
35
 
49
36
  @advice = {
50
37
  'reconnect' => RETRY,
51
- 'interval' => 1000.0 * (@options[:interval] || Engine::INTERVAL),
52
- 'timeout' => 1000.0 * (@options[:timeout] || CONNECTION_TIMEOUT)
38
+ 'interval' => 1000.0 * (options[:interval] || Engine::INTERVAL),
39
+ 'timeout' => 1000.0 * (options[:timeout] || CONNECTION_TIMEOUT)
53
40
  }
54
- end
41
+ @dispatcher.timeout = @advice['timeout'] / 1000.0
55
42
 
56
- def disable(feature)
57
- @disabled << feature
58
- end
59
-
60
- def set_header(name, value)
61
- @headers[name.to_s] = value.to_s
43
+ @dispatcher.bind(:message, &method(:receive_message))
62
44
  end
63
45
 
64
46
  # Request
@@ -86,30 +68,30 @@ module Faye
86
68
 
87
69
  @state = CONNECTING
88
70
 
89
- info('Initiating handshake with ?', @endpoint)
90
- select_transport(MANDATORY_CONNECTION_TYPES)
71
+ info('Initiating handshake with ?', @dispatcher.endpoint.to_s)
72
+ @dispatcher.select_transport(MANDATORY_CONNECTION_TYPES)
91
73
 
92
- send({
93
- 'channel' => Channel::HANDSHAKE,
94
- 'version' => BAYEUX_VERSION,
95
- 'supportedConnectionTypes' => [@transport.connection_type]
74
+ send_message({
75
+ 'channel' => Channel::HANDSHAKE,
76
+ 'version' => BAYEUX_VERSION,
77
+ 'supportedConnectionTypes' => @dispatcher.connection_types
96
78
 
97
- }) do |response|
79
+ }, {}) do |response|
98
80
 
99
81
  if response['successful']
100
- @state = CONNECTED
101
- @client_id = response['clientId']
82
+ @state = CONNECTED
83
+ @dispatcher.client_id = response['clientId']
102
84
 
103
- select_transport(response['supportedConnectionTypes'])
85
+ @dispatcher.select_transport(response['supportedConnectionTypes'])
104
86
 
105
- info('Handshake successful: ?', @client_id)
87
+ info('Handshake successful: ?', @dispatcher.client_id)
106
88
 
107
89
  subscribe(@channels.keys, true)
108
90
  block.call if block_given?
109
91
 
110
92
  else
111
93
  info('Handshake unsuccessful')
112
- EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
94
+ EventMachine.add_timer(@dispatcher.retry) { handshake(&block) }
113
95
  @state = UNCONNECTED
114
96
  end
115
97
  end
@@ -133,21 +115,21 @@ module Faye
133
115
  callback(&block)
134
116
  return unless @state == CONNECTED
135
117
 
136
- info('Calling deferred actions for ?', @client_id)
118
+ info('Calling deferred actions for ?', @dispatcher.client_id)
137
119
  set_deferred_status(:succeeded)
138
120
  set_deferred_status(:unknown)
139
121
 
140
122
  return unless @connect_request.nil?
141
123
  @connect_request = true
142
124
 
143
- info('Initiating connection for ?', @client_id)
125
+ info('Initiating connection for ?', @dispatcher.client_id)
144
126
 
145
- send({
146
- 'channel' => Channel::CONNECT,
147
- 'clientId' => @client_id,
148
- 'connectionType' => @transport.connection_type
127
+ send_message({
128
+ 'channel' => Channel::CONNECT,
129
+ 'clientId' => @dispatcher.client_id,
130
+ 'connectionType' => @dispatcher.connection_type
149
131
 
150
- }) do
132
+ }, {}) do
151
133
  cycle_connection
152
134
  end
153
135
  end
@@ -163,18 +145,26 @@ module Faye
163
145
  return unless @state == CONNECTED
164
146
  @state = DISCONNECTED
165
147
 
166
- info('Disconnecting ?', @client_id)
148
+ info('Disconnecting ?', @dispatcher.client_id)
149
+ promise = Publication.new
167
150
 
168
- send({
169
- 'channel' => Channel::DISCONNECT,
170
- 'clientId' => @client_id
151
+ send_message({
152
+ 'channel' => Channel::DISCONNECT,
153
+ 'clientId' => @dispatcher.client_id
171
154
 
172
- }) do |response|
173
- @transport.close if response['successful']
155
+ }, {}) do |response|
156
+ if response['successful']
157
+ @dispatcher.close
158
+ promise.set_deferred_status(:succeeded)
159
+ else
160
+ promise.set_deferred_status(:failed, Error.parse(response['error']))
161
+ end
174
162
  end
175
163
 
176
- info('Clearing channel listeners for ?', @client_id)
164
+ info('Clearing channel listeners for ?', @dispatcher.client_id)
177
165
  @channels = Channel::Set.new
166
+
167
+ promise
178
168
  end
179
169
 
180
170
  # Request Response
@@ -196,28 +186,28 @@ module Faye
196
186
  has_subscribe = @channels.has_subscription?(channel)
197
187
 
198
188
  if has_subscribe and not force
199
- @channels.subscribe([channel], block)
189
+ @channels.subscribe([channel], subscription)
200
190
  subscription.set_deferred_status(:succeeded)
201
191
  return subscription
202
192
  end
203
193
 
204
194
  connect {
205
- info('Client ? attempting to subscribe to ?', @client_id, channel)
206
- @channels.subscribe([channel], block) unless force
195
+ info('Client ? attempting to subscribe to ?', @dispatcher.client_id, channel)
196
+ @channels.subscribe([channel], subscription) unless force
207
197
 
208
- send({
209
- 'channel' => Channel::SUBSCRIBE,
210
- 'clientId' => @client_id,
211
- 'subscription' => channel
198
+ send_message({
199
+ 'channel' => Channel::SUBSCRIBE,
200
+ 'clientId' => @dispatcher.client_id,
201
+ 'subscription' => channel
212
202
 
213
- }) do |response|
203
+ }, {}) do |response|
214
204
  unless response['successful']
215
205
  subscription.set_deferred_status(:failed, Error.parse(response['error']))
216
- next @channels.unsubscribe(channel, block)
206
+ next @channels.unsubscribe(channel, subscription)
217
207
  end
218
208
 
219
209
  channels = [response['subscription']].flatten
220
- info('Subscription acknowledged for ? to ?', @client_id, channels)
210
+ info('Subscription acknowledged for ? to ?', @dispatcher.client_id, channels)
221
211
  subscription.set_deferred_status(:succeeded)
222
212
  end
223
213
  }
@@ -234,27 +224,29 @@ module Faye
234
224
  # * ext
235
225
  # * id
236
226
  # * timestamp
237
- def unsubscribe(channel, &block)
227
+ def unsubscribe(channel, subscription = nil, &block)
228
+ subscription ||= block
229
+
238
230
  if Array === channel
239
- return channel.map { |c| unsubscribe(c, &block) }
231
+ return channel.map { |c| unsubscribe(c, subscription) }
240
232
  end
241
233
 
242
- dead = @channels.unsubscribe(channel, block)
234
+ dead = @channels.unsubscribe(channel, subscription)
243
235
  return unless dead
244
236
 
245
237
  connect {
246
- info('Client ? attempting to unsubscribe from ?', @client_id, channel)
238
+ info('Client ? attempting to unsubscribe from ?', @dispatcher.client_id, channel)
247
239
 
248
- send({
249
- 'channel' => Channel::UNSUBSCRIBE,
250
- 'clientId' => @client_id,
251
- 'subscription' => channel
240
+ send_message({
241
+ 'channel' => Channel::UNSUBSCRIBE,
242
+ 'clientId' => @dispatcher.client_id,
243
+ 'subscription' => channel
252
244
 
253
- }) do |response|
245
+ }, {}) do |response|
254
246
  next unless response['successful']
255
247
 
256
248
  channels = [response['subscription']].flatten
257
- info('Unsubscription acknowledged for ? from ?', @client_id, channels)
249
+ info('Unsubscription acknowledged for ? from ?', @dispatcher.client_id, channels)
258
250
  end
259
251
  }
260
252
  end
@@ -265,17 +257,19 @@ module Faye
265
257
  # MAY include: * clientId MAY include: * id
266
258
  # * id * error
267
259
  # * ext * ext
268
- def publish(channel, data)
260
+ def publish(channel, data, options = {})
261
+ ::WebSocket::Driver.validate_options(options, [:attempts, :deadline])
262
+
269
263
  publication = Publication.new
270
264
  connect {
271
- info('Client ? queueing published message to ?: ?', @client_id, channel, data)
265
+ info('Client ? queueing published message to ?: ?', @dispatcher.client_id, channel, data)
272
266
 
273
- send({
274
- 'channel' => channel,
275
- 'data' => data,
276
- 'clientId' => @client_id
267
+ send_message({
268
+ 'channel' => channel,
269
+ 'data' => data,
270
+ 'clientId' => @dispatcher.client_id
277
271
 
278
- }) do |response|
272
+ }, options) do |response|
279
273
  if response['successful']
280
274
  publication.set_deferred_status(:succeeded)
281
275
  else
@@ -286,81 +280,20 @@ module Faye
286
280
  publication
287
281
  end
288
282
 
289
- def receive_message(message)
290
- id = message['id']
291
-
292
- if message.has_key?('successful')
293
- callback = @response_callbacks.delete(id)
294
- end
295
-
296
- pipe_through_extensions(:incoming, message, nil) do |message|
297
- next unless message
298
-
299
- handle_advice(message['advice']) if message['advice']
300
- deliver_message(message)
301
-
302
- callback.call(message) if callback
303
- end
304
-
305
- return if @transport_up == true
306
- @transport_up = true
307
- trigger('transport:up')
308
- end
309
-
310
- def message_error(messages, immediate = false)
311
- messages.each do |message|
312
- id = message['id']
313
-
314
- if immediate
315
- transport_send(message)
316
- else
317
- EventMachine.add_timer(@retry) { transport_send(message) }
318
- end
319
- end
320
-
321
- return if immediate or @transport_up == false
322
- @transport_up = false
323
- trigger('transport:down')
324
- end
325
-
326
283
  private
327
284
 
328
- def select_transport(transport_types)
329
- Transport.get(self, transport_types, @disabled) do |transport|
330
- debug('Selected ? transport for ?', transport.connection_type, transport.endpoint)
331
-
332
- next if transport == @transport
333
- @transport.close if @transport
334
-
335
- @transport = transport
336
- end
337
- end
338
-
339
- def send(message, &callback)
340
- return unless @transport
285
+ def send_message(message, options, &callback)
341
286
  message['id'] = generate_message_id
342
287
 
343
- pipe_through_extensions(:outgoing, message, nil) do |message|
344
- next unless message
345
- @response_callbacks[message['id']] = callback if callback
346
- transport_send(message)
347
- end
348
- end
349
-
350
- def transport_send(message)
351
- return unless @transport
352
-
353
288
  timeout = [nil, 0].include?(@advice['timeout']) ?
354
- 1.2 * @retry :
289
+ 1.2 * @dispatcher.retry :
355
290
  1.2 * @advice['timeout'] / 1000.0
356
291
 
357
- envelope = Envelope.new(message, timeout)
358
-
359
- envelope.errback do |immediate|
360
- message_error([message], immediate)
292
+ pipe_through_extensions(:outgoing, message, nil) do |message|
293
+ next unless message
294
+ @response_callbacks[message['id']] = callback if callback
295
+ @dispatcher.send_message(message, timeout, options)
361
296
  end
362
-
363
- @transport.send(envelope)
364
297
  end
365
298
 
366
299
  def generate_message_id
@@ -369,30 +302,45 @@ module Faye
369
302
  @message_id.to_s(36)
370
303
  end
371
304
 
305
+ def receive_message(message)
306
+ id = message['id']
307
+
308
+ if message.has_key?('successful')
309
+ callback = @response_callbacks.delete(id)
310
+ end
311
+
312
+ pipe_through_extensions(:incoming, message, nil) do |message|
313
+ next unless message
314
+ handle_advice(message['advice']) if message['advice']
315
+ deliver_message(message)
316
+ callback.call(message) if callback
317
+ end
318
+ end
319
+
372
320
  def handle_advice(advice)
373
321
  @advice.update(advice)
322
+ @dispatcher.timeout = @advice['timeout'] / 1000.0
374
323
 
375
324
  if @advice['reconnect'] == HANDSHAKE and @state != DISCONNECTED
376
- @state = UNCONNECTED
377
- @client_id = nil
325
+ @state = UNCONNECTED
326
+ @dispatcher.client_id = nil
378
327
  cycle_connection
379
328
  end
380
329
  end
381
330
 
382
331
  def deliver_message(message)
383
332
  return unless message.has_key?('channel') and message.has_key?('data')
384
- info('Client ? calling listeners for ? with ?', @client_id, message['channel'], message['data'])
333
+ info('Client ? calling listeners for ? with ?', @dispatcher.client_id, message['channel'], message['data'])
385
334
  @channels.distribute_message(message)
386
335
  end
387
336
 
388
337
  def cycle_connection
389
338
  if @connect_request
390
339
  @connect_request = nil
391
- info('Closed connection for ?', @client_id)
340
+ info('Closed connection for ?', @dispatcher.client_id)
392
341
  end
393
342
  EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
394
343
  end
395
344
 
396
345
  end
397
346
  end
398
-