faye 0.8.11 → 1.0.0

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

Potentially problematic release.


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

Files changed (73) hide show
  1. data/{History.txt → CHANGELOG.md} +126 -105
  2. data/README.md +36 -0
  3. data/lib/faye-browser-min.js +2 -1
  4. data/lib/faye-browser-min.js.map +1 -8
  5. data/lib/faye-browser.js +923 -607
  6. data/lib/faye.rb +11 -5
  7. data/lib/faye/adapters/rack_adapter.rb +80 -85
  8. data/lib/faye/engines/connection.rb +7 -9
  9. data/lib/faye/engines/memory.rb +1 -0
  10. data/lib/faye/engines/proxy.rb +7 -6
  11. data/lib/faye/mixins/deferrable.rb +15 -0
  12. data/lib/faye/mixins/logging.rb +11 -22
  13. data/lib/faye/mixins/publisher.rb +9 -20
  14. data/lib/faye/protocol/channel.rb +2 -1
  15. data/lib/faye/protocol/client.rb +70 -48
  16. data/lib/faye/protocol/envelope.rb +24 -0
  17. data/lib/faye/protocol/extensible.rb +7 -4
  18. data/lib/faye/protocol/publication.rb +1 -1
  19. data/lib/faye/protocol/server.rb +8 -11
  20. data/lib/faye/protocol/socket.rb +6 -4
  21. data/lib/faye/protocol/subscription.rb +1 -1
  22. data/lib/faye/transport/http.rb +20 -27
  23. data/lib/faye/transport/local.rb +5 -5
  24. data/lib/faye/transport/transport.rb +42 -12
  25. data/lib/faye/transport/web_socket.rb +71 -38
  26. metadata +169 -137
  27. checksums.yaml +0 -7
  28. data/README.rdoc +0 -83
  29. data/spec/browser.html +0 -45
  30. data/spec/encoding_helper.rb +0 -7
  31. data/spec/install.sh +0 -78
  32. data/spec/javascript/channel_spec.js +0 -15
  33. data/spec/javascript/client_spec.js +0 -729
  34. data/spec/javascript/dispatcher_spec.js +0 -122
  35. data/spec/javascript/engine/memory_spec.js +0 -7
  36. data/spec/javascript/engine_spec.js +0 -417
  37. data/spec/javascript/faye_spec.js +0 -34
  38. data/spec/javascript/grammar_spec.js +0 -66
  39. data/spec/javascript/node_adapter_spec.js +0 -314
  40. data/spec/javascript/publisher_spec.js +0 -27
  41. data/spec/javascript/server/connect_spec.js +0 -168
  42. data/spec/javascript/server/disconnect_spec.js +0 -121
  43. data/spec/javascript/server/extensions_spec.js +0 -60
  44. data/spec/javascript/server/handshake_spec.js +0 -145
  45. data/spec/javascript/server/integration_spec.js +0 -131
  46. data/spec/javascript/server/publish_spec.js +0 -85
  47. data/spec/javascript/server/subscribe_spec.js +0 -247
  48. data/spec/javascript/server/unsubscribe_spec.js +0 -245
  49. data/spec/javascript/server_spec.js +0 -121
  50. data/spec/javascript/transport_spec.js +0 -135
  51. data/spec/node.js +0 -55
  52. data/spec/phantom.js +0 -17
  53. data/spec/ruby/channel_spec.rb +0 -17
  54. data/spec/ruby/client_spec.rb +0 -741
  55. data/spec/ruby/engine/memory_spec.rb +0 -7
  56. data/spec/ruby/engine_examples.rb +0 -427
  57. data/spec/ruby/faye_spec.rb +0 -30
  58. data/spec/ruby/grammar_spec.rb +0 -68
  59. data/spec/ruby/publisher_spec.rb +0 -27
  60. data/spec/ruby/rack_adapter_spec.rb +0 -241
  61. data/spec/ruby/server/connect_spec.rb +0 -170
  62. data/spec/ruby/server/disconnect_spec.rb +0 -120
  63. data/spec/ruby/server/extensions_spec.rb +0 -68
  64. data/spec/ruby/server/handshake_spec.rb +0 -143
  65. data/spec/ruby/server/integration_spec.rb +0 -133
  66. data/spec/ruby/server/publish_spec.rb +0 -81
  67. data/spec/ruby/server/subscribe_spec.rb +0 -247
  68. data/spec/ruby/server/unsubscribe_spec.rb +0 -247
  69. data/spec/ruby/server_spec.rb +0 -121
  70. data/spec/ruby/transport_spec.rb +0 -136
  71. data/spec/spec_helper.rb +0 -11
  72. data/spec/testswarm +0 -42
  73. data/spec/thin_proxy.rb +0 -37
@@ -1,28 +1,17 @@
1
1
  module Faye
2
2
  module Publisher
3
3
 
4
- def count_listeners(event_type)
5
- return 0 unless @subscribers and @subscribers[event_type]
6
- @subscribers[event_type].size
7
- end
8
-
9
- def bind(event_type, &listener)
10
- @subscribers ||= {}
11
- list = @subscribers[event_type] ||= []
12
- list << listener
13
- end
4
+ include ::WebSocket::Driver::EventEmitter
14
5
 
15
- def unbind(event_type, &listener)
16
- return unless @subscribers and @subscribers[event_type]
17
- return @subscribers.delete(event_type) unless listener
18
-
19
- @subscribers[event_type].delete_if(&listener.method(:==))
20
- end
6
+ alias :bind :add_listener
7
+ alias :trigger :emit
21
8
 
22
- def trigger(event_type, *args)
23
- return unless @subscribers and @subscribers[event_type]
24
- listeners = @subscribers[event_type].dup
25
- listeners.each { |listener| listener.call(*args) }
9
+ def unbind(event, &listener)
10
+ if listener
11
+ remove_listener(event, &listener)
12
+ else
13
+ remove_all_listeners(event)
14
+ end
26
15
  end
27
16
 
28
17
  end
@@ -5,6 +5,7 @@ module Faye
5
5
  attr_reader :name
6
6
 
7
7
  def initialize(name)
8
+ super()
8
9
  @name = name
9
10
  end
10
11
 
@@ -13,7 +14,7 @@ module Faye
13
14
  end
14
15
 
15
16
  def unused?
16
- count_listeners(:message).zero?
17
+ listener_count(:message).zero?
17
18
  end
18
19
 
19
20
  HANDSHAKE = '/meta/handshake'
@@ -1,7 +1,7 @@
1
1
  module Faye
2
2
  class Client
3
3
 
4
- include EventMachine::Deferrable
4
+ include Deferrable
5
5
  include Publisher
6
6
  include Logging
7
7
  include Extensible
@@ -17,14 +17,16 @@ module Faye
17
17
 
18
18
  CONNECTION_TIMEOUT = 60.0
19
19
  DEFAULT_RETRY = 5.0
20
+ MAX_REQUEST_SIZE = 2048
20
21
 
21
- attr_reader :client_id, :endpoint, :endpoints, :retry, :transports
22
+ attr_reader :cookies, :endpoint, :endpoints, :headers, :max_request_size, :retry, :transports
22
23
 
23
24
  def initialize(endpoint = nil, options = {})
25
+ super()
24
26
  info('New client created for ?', endpoint)
25
27
 
26
28
  @options = options
27
- @endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
29
+ @endpoint = Faye.parse_url(endpoint || RackAdapter::DEFAULT_ENDPOINT)
28
30
  @endpoints = @options[:endpoints] || {}
29
31
  @transports = {}
30
32
  @cookies = CookieJar::Jar.new
@@ -32,6 +34,12 @@ module Faye
32
34
  @disabled = []
33
35
  @retry = @options[:retry] || DEFAULT_RETRY
34
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
+
35
43
  @state = UNCONNECTED
36
44
  @channels = Channel::Set.new
37
45
  @message_id = 0
@@ -53,15 +61,6 @@ module Faye
53
61
  @headers[name.to_s] = value.to_s
54
62
  end
55
63
 
56
- def state
57
- case @state
58
- when UNCONNECTED then :UNCONNECTED
59
- when CONNECTING then :CONNECTING
60
- when CONNECTED then :CONNECTED
61
- when DISCONNECTED then :DISCONNECTED
62
- end
63
- end
64
-
65
64
  # Request
66
65
  # MUST include: * channel
67
66
  # * version
@@ -91,9 +90,9 @@ module Faye
91
90
  select_transport(MANDATORY_CONNECTION_TYPES)
92
91
 
93
92
  send({
94
- 'channel' => Channel::HANDSHAKE,
95
- 'version' => BAYEUX_VERSION,
96
- 'supportedConnectionTypes' => [@transport.connection_type]
93
+ 'channel' => Channel::HANDSHAKE,
94
+ 'version' => BAYEUX_VERSION,
95
+ 'supportedConnectionTypes' => [@transport.connection_type]
97
96
 
98
97
  }) do |response|
99
98
 
@@ -136,7 +135,7 @@ module Faye
136
135
 
137
136
  info('Calling deferred actions for ?', @client_id)
138
137
  set_deferred_status(:succeeded)
139
- set_deferred_status(:deferred)
138
+ set_deferred_status(:unknown)
140
139
 
141
140
  return unless @connect_request.nil?
142
141
  @connect_request = true
@@ -275,6 +274,7 @@ module Faye
275
274
  'channel' => channel,
276
275
  'data' => data,
277
276
  'clientId' => @client_id
277
+
278
278
  }) do |response|
279
279
  if response['successful']
280
280
  publication.set_deferred_status(:succeeded)
@@ -287,20 +287,40 @@ module Faye
287
287
  end
288
288
 
289
289
  def receive_message(message)
290
- pipe_through_extensions(:incoming, message) do |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|
291
297
  next unless message
292
298
 
293
299
  handle_advice(message['advice']) if message['advice']
294
300
  deliver_message(message)
295
301
 
296
- next unless message.has_key?('successful')
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
297
309
 
298
- callback = @response_callbacks[message['id']]
299
- next unless callback
310
+ def message_error(messages, immediate = false)
311
+ messages.each do |message|
312
+ id = message['id']
300
313
 
301
- @response_callbacks.delete(message['id'])
302
- callback.call(message)
314
+ if immediate
315
+ transport_send(message)
316
+ else
317
+ EventMachine.add_timer(@retry) { transport_send(message) }
318
+ end
303
319
  end
320
+
321
+ return if immediate or @transport_up == false
322
+ @transport_up = false
323
+ trigger('transport:down')
304
324
  end
305
325
 
306
326
  private
@@ -309,35 +329,40 @@ module Faye
309
329
  Transport.get(self, transport_types, @disabled) do |transport|
310
330
  debug('Selected ? transport for ?', transport.connection_type, transport.endpoint)
311
331
 
312
- @transport = transport
313
- @transport.cookies = @cookies
314
- @transport.headers = @headers
315
-
316
- transport.bind :down do
317
- if @transport_up.nil? or @transport_up
318
- @transport_up = false
319
- trigger('transport:down')
320
- end
321
- end
332
+ next if transport == @transport
333
+ @transport.close if @transport
322
334
 
323
- transport.bind :up do
324
- if @transport_up.nil? or not @transport_up
325
- @transport_up = true
326
- trigger('transport:up')
327
- end
328
- end
335
+ @transport = transport
329
336
  end
330
337
  end
331
338
 
332
339
  def send(message, &callback)
340
+ return unless @transport
333
341
  message['id'] = generate_message_id
334
- @response_callbacks[message['id']] = callback if callback
335
342
 
336
- pipe_through_extensions(:outgoing, message) do |message|
337
- @transport.send(message, @advice['timeout'] / 1000.0) if message
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)
338
347
  end
339
348
  end
340
349
 
350
+ def transport_send(message)
351
+ return unless @transport
352
+
353
+ timeout = [nil, 0].include?(@advice['timeout']) ?
354
+ 1.2 * @retry :
355
+ 1.2 * @advice['timeout'] / 1000.0
356
+
357
+ envelope = Envelope.new(message, timeout)
358
+
359
+ envelope.errback do |immediate|
360
+ message_error([message], immediate)
361
+ end
362
+
363
+ @transport.send(envelope)
364
+ end
365
+
341
366
  def generate_message_id
342
367
  @message_id += 1
343
368
  @message_id = 0 if @message_id >= 2**32
@@ -360,14 +385,11 @@ module Faye
360
385
  @channels.distribute_message(message)
361
386
  end
362
387
 
363
- def teardown_connection
364
- return unless @connect_request
365
- @connect_request = nil
366
- info('Closed connection for ?', @client_id)
367
- end
368
-
369
388
  def cycle_connection
370
- teardown_connection
389
+ if @connect_request
390
+ @connect_request = nil
391
+ info('Closed connection for ?', @client_id)
392
+ end
371
393
  EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
372
394
  end
373
395
 
@@ -0,0 +1,24 @@
1
+ module Faye
2
+ class Envelope
3
+
4
+ include Deferrable
5
+ attr_reader :id, :message
6
+
7
+ def initialize(message, timeout = nil)
8
+ @id = message['id']
9
+ @message = message
10
+
11
+ self.timeout(timeout, false) if timeout
12
+ end
13
+
14
+ def eql?(other)
15
+ Envelope === other and @id == other.id
16
+ end
17
+
18
+ def hash
19
+ @id.hash
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -17,7 +17,7 @@ module Faye
17
17
  end
18
18
  end
19
19
 
20
- def pipe_through_extensions(stage, message, &callback)
20
+ def pipe_through_extensions(stage, message, env, &callback)
21
21
  debug 'Passing through ? extensions: ?', stage, message
22
22
 
23
23
  return callback.call(message) unless @extensions
@@ -29,10 +29,13 @@ module Faye
29
29
  extension = extensions.shift
30
30
  next callback.call(message) unless extension
31
31
 
32
- if extension.respond_to?(stage)
33
- extension.__send__(stage, message, pipe)
32
+ next pipe.call(message) unless extension.respond_to?(stage)
33
+
34
+ arity = extension.method(stage).arity
35
+ if arity >= 3
36
+ extension.__send__(stage, message, env, pipe)
34
37
  else
35
- pipe.call(message)
38
+ extension.__send__(stage, message, pipe)
36
39
  end
37
40
  end
38
41
  pipe.call(message)
@@ -1,5 +1,5 @@
1
1
  module Faye
2
2
  class Publication
3
- include EventMachine::Deferrable
3
+ include Deferrable
4
4
  end
5
5
  end
@@ -19,21 +19,17 @@ module Faye
19
19
  info 'Created new server: ?', @options
20
20
  end
21
21
 
22
- def flush_connection(messages)
23
- client_id = Faye.client_id_from_messages(messages)
24
- info 'Flushing connection for ?', client_id
25
- @engine.flush(client_id) if client_id
26
- end
27
-
28
- def open_socket(client_id, socket)
29
- @engine.open_socket(client_id, Socket.new(self, socket))
22
+ def open_socket(client_id, socket, env)
23
+ return unless client_id and socket
24
+ @engine.open_socket(client_id, Socket.new(self, socket, env))
30
25
  end
31
26
 
32
27
  def close_socket(client_id)
33
28
  @engine.flush(client_id)
34
29
  end
35
30
 
36
- def process(messages, local = false, &callback)
31
+ def process(messages, env, &callback)
32
+ local = env.nil?
37
33
  messages = [messages].flatten
38
34
  info 'Processing messages: ? (local: ?)', messages, local
39
35
 
@@ -54,7 +50,7 @@ module Faye
54
50
 
55
51
  replies.each_with_index do |reply, i|
56
52
  debug 'Processing reply: ?', reply
57
- pipe_through_extensions(:outgoing, reply) do |message|
53
+ pipe_through_extensions(:outgoing, reply, env) do |message|
58
54
  replies[i] = message
59
55
  extended += 1
60
56
  gather_replies.call(replies) if extended == expected
@@ -63,7 +59,7 @@ module Faye
63
59
  end
64
60
 
65
61
  messages.each do |message|
66
- pipe_through_extensions(:incoming, message) do |piped_message|
62
+ pipe_through_extensions(:incoming, message, env) do |piped_message|
67
63
  handle(piped_message, local, &handle_reply)
68
64
  end
69
65
  end
@@ -94,6 +90,7 @@ module Faye
94
90
  error = Faye::Error.channel_invalid(channel_name)
95
91
  end
96
92
 
93
+ message.delete('clientId')
97
94
  @engine.publish(message) unless error
98
95
 
99
96
  response = make_response(message)
@@ -2,19 +2,21 @@ module Faye
2
2
  class Server
3
3
 
4
4
  class Socket
5
- def initialize(server, socket)
5
+ def initialize(server, socket, env)
6
6
  @server = server
7
7
  @socket = socket
8
+ @env = env
8
9
  end
9
10
 
10
11
  def send(message)
11
- @server.pipe_through_extensions(:outgoing, message) do |piped_message|
12
- @socket.send(Faye.to_json([piped_message]))
12
+ @server.pipe_through_extensions(:outgoing, message, @env) do |piped_message|
13
+ @socket.send(Faye.to_json([piped_message])) if @socket
13
14
  end
14
15
  end
15
16
 
16
17
  def close
17
- @socket.close
18
+ @socket.close if @socket
19
+ @socket = nil
18
20
  end
19
21
  end
20
22
 
@@ -1,6 +1,6 @@
1
1
  module Faye
2
2
  class Subscription
3
- include EventMachine::Deferrable
3
+ include Deferrable
4
4
 
5
5
  def initialize(client, channels, callback)
6
6
  @client = client
@@ -2,37 +2,38 @@ module Faye
2
2
 
3
3
  class Transport::Http < Transport
4
4
  def self.usable?(client, endpoint, &callback)
5
- callback.call(endpoint.is_a?(String))
5
+ callback.call(URI === endpoint)
6
6
  end
7
7
 
8
- def request(message, timeout)
9
- retry_block = retry_block(message, timeout)
8
+ def encode(envelopes)
9
+ Faye.to_json(envelopes.map { |e| e.message })
10
+ end
10
11
 
11
- content = Faye.to_json(message)
12
- cookies = @cookies.get_cookies(@endpoint)
13
- params = build_params(URI.parse(@endpoint), content, cookies)
12
+ def request(envelopes)
13
+ content = encode(envelopes)
14
+ params = build_params(@endpoint, content)
14
15
  request = create_request(params)
15
16
 
16
17
  request.callback do
17
- handle_response(request.response, retry_block)
18
- store_cookies([*request.response_header['SET_COOKIE']].compact)
18
+ handle_response(request.response, envelopes)
19
+ store_cookies(request.response_header['SET_COOKIE'])
19
20
  end
21
+
20
22
  request.errback do
21
- retry_block.call
22
- trigger(:down)
23
+ handle_error(envelopes)
23
24
  end
24
25
  end
25
26
 
26
27
  private
27
28
 
28
- def build_params(uri, content, cookies)
29
+ def build_params(uri, content)
29
30
  {
30
31
  :head => {
31
32
  'Content-Length' => content.bytesize,
32
33
  'Content-Type' => 'application/json',
33
- 'Cookie' => cookies * '; ',
34
+ 'Cookie' => get_cookies,
34
35
  'Host' => uri.host
35
- }.merge(@headers),
36
+ }.merge(@client.headers),
36
37
 
37
38
  :body => content,
38
39
  :timeout => -1 # for em-http-request < 1.0
@@ -45,28 +46,20 @@ module Faye
45
46
  options = { # for em-http-request >= 1.0
46
47
  :inactivity_timeout => 0 # connection inactivity (post-setup) timeout (0 = disable timeout)
47
48
  }
48
- EventMachine::HttpRequest.new(@endpoint, options)
49
+ EventMachine::HttpRequest.new(@endpoint.to_s, options)
49
50
  else
50
- EventMachine::HttpRequest.new(@endpoint)
51
+ EventMachine::HttpRequest.new(@endpoint.to_s)
51
52
  end
52
53
 
53
54
  client.post(params)
54
55
  end
55
56
 
56
- def handle_response(response, retry_block)
57
- message = Yajl::Parser.parse(response) rescue nil
57
+ def handle_response(response, envelopes)
58
+ message = MultiJson.load(response) rescue nil
58
59
  if message
59
- receive(message)
60
- trigger(:up)
60
+ receive(envelopes, message)
61
61
  else
62
- retry_block.call
63
- trigger(:down)
64
- end
65
- end
66
-
67
- def store_cookies(cookies)
68
- cookies.each do |cookie|
69
- @cookies.set_cookie(@endpoint, cookie)
62
+ handle_error(messages)
70
63
  end
71
64
  end
72
65
  end