faye 1.0.4 → 1.1.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/lib/faye.rb CHANGED
@@ -14,30 +14,31 @@ require 'time'
14
14
  require 'uri'
15
15
 
16
16
  module Faye
17
- VERSION = '1.0.4'
17
+ VERSION = '1.1.0'
18
18
 
19
19
  ROOT = File.expand_path(File.dirname(__FILE__))
20
20
 
21
- autoload :Publisher, File.join(ROOT, 'faye', 'mixins', 'publisher')
22
21
  autoload :Deferrable, File.join(ROOT, 'faye', 'mixins', 'deferrable')
23
- autoload :Timeouts, File.join(ROOT, 'faye', 'mixins', 'timeouts')
24
22
  autoload :Logging, File.join(ROOT, 'faye', 'mixins', 'logging')
23
+ autoload :Publisher, File.join(ROOT, 'faye', 'mixins', 'publisher')
24
+ autoload :Timeouts, File.join(ROOT, 'faye', 'mixins', 'timeouts')
25
25
 
26
26
  autoload :Namespace, File.join(ROOT, 'faye', 'util', 'namespace')
27
27
 
28
28
  autoload :Engine, File.join(ROOT, 'faye', 'engines', 'proxy')
29
29
 
30
- autoload :Grammar, File.join(ROOT, 'faye', 'protocol', 'grammar')
31
- autoload :Extensible, File.join(ROOT, 'faye', 'protocol', 'extensible')
32
30
  autoload :Channel, File.join(ROOT, 'faye', 'protocol', 'channel')
33
- autoload :Envelope, File.join(ROOT, 'faye', 'protocol', 'envelope')
34
- autoload :Subscription, File.join(ROOT, 'faye', 'protocol', 'subscription')
35
- autoload :Publication, File.join(ROOT, 'faye', 'protocol', 'publication')
36
31
  autoload :Client, File.join(ROOT, 'faye', 'protocol', 'client')
32
+ autoload :Dispatcher, File.join(ROOT, 'faye', 'protocol', 'dispatcher')
33
+ autoload :Scheduler, File.join(ROOT, 'faye', 'protocol', 'scheduler')
34
+ autoload :Extensible, File.join(ROOT, 'faye', 'protocol', 'extensible')
35
+ autoload :Grammar, File.join(ROOT, 'faye', 'protocol', 'grammar')
36
+ autoload :Publication, File.join(ROOT, 'faye', 'protocol', 'publication')
37
37
  autoload :Server, File.join(ROOT, 'faye', 'protocol', 'server')
38
+ autoload :Subscription, File.join(ROOT, 'faye', 'protocol', 'subscription')
38
39
 
39
- autoload :Transport, File.join(ROOT, 'faye', 'transport', 'transport')
40
40
  autoload :Error, File.join(ROOT, 'faye', 'error')
41
+ autoload :Transport, File.join(ROOT, 'faye', 'transport', 'transport')
41
42
 
42
43
  autoload :RackAdapter, File.join(ROOT, 'faye', 'adapters', 'rack_adapter')
43
44
  autoload :StaticServer, File.join(ROOT, 'faye', 'adapters', 'static_server')
@@ -125,4 +126,3 @@ module Faye
125
126
  resume.call
126
127
  end
127
128
  end
128
-
@@ -22,11 +22,14 @@ module Faye
22
22
  # down. Better suggestions welcome.
23
23
  HTTP_X_NO_CONTENT_LENGTH = 'HTTP_X_NO_CONTENT_LENGTH'
24
24
 
25
- def initialize(app = nil, options = nil)
25
+ def initialize(app = nil, options = nil, &block)
26
26
  @app = app if app.respond_to?(:call)
27
27
  @options = [app, options].grep(Hash).first || {}
28
28
 
29
+ ::WebSocket::Driver.validate_options(@options, [:engine, :mount, :ping, :timeout, :extensions, :websocket_extensions])
30
+
29
31
  @endpoint = @options[:mount] || DEFAULT_ENDPOINT
32
+ @extensions = []
30
33
  @endpoint_re = Regexp.new('^' + @endpoint.gsub(/\/$/, '') + '(/[^/]*)*(\\.[^\\.]+)?$')
31
34
  @server = Server.new(@options)
32
35
 
@@ -34,8 +37,15 @@ module Faye
34
37
  @static.map(File.basename(@endpoint) + '.js', SCRIPT_PATH)
35
38
  @static.map('client.js', SCRIPT_PATH)
36
39
 
37
- return unless extensions = @options[:extensions]
38
- [*extensions].each { |extension| add_extension(extension) }
40
+ if extensions = @options[:extensions]
41
+ [*extensions].each { |extension| add_extension(extension) }
42
+ end
43
+
44
+ if websocket_extensions = @options[:websocket_extensions]
45
+ [*websocket_extensions].each { |ext| add_websocket_extension(ext) }
46
+ end
47
+
48
+ block.call(self) if block
39
49
  end
40
50
 
41
51
  def listen(*args)
@@ -50,6 +60,10 @@ module Faye
50
60
  @server.remove_extension(extension)
51
61
  end
52
62
 
63
+ def add_websocket_extension(extension)
64
+ @extensions << extension
65
+ end
66
+
53
67
  def close
54
68
  @server.close
55
69
  end
@@ -89,7 +103,12 @@ module Faye
89
103
  return [400, TYPE_TEXT, ['Bad request']]
90
104
  end
91
105
 
92
- debug "Received message via HTTP #{request.request_method}: ?", json_msg
106
+ unless json_msg.force_encoding('UTF-8').valid_encoding?
107
+ error 'Received request with invalid encoding: ?', format_request(request)
108
+ return [400, TYPE_TEXT, ['Bad request']]
109
+ end
110
+
111
+ debug("Received message via HTTP #{request.request_method}: ?", json_msg)
93
112
 
94
113
  message = MultiJson.load(json_msg)
95
114
  jsonp = request.params['jsonp'] || JSONP_CALLBACK
@@ -120,7 +139,7 @@ module Faye
120
139
 
121
140
  headers['Content-Length'] = response.bytesize.to_s unless request.env[HTTP_X_NO_CONTENT_LENGTH]
122
141
  headers['Connection'] = 'close'
123
- debug 'HTTP response: ?', response
142
+ debug('HTTP response: ?', response)
124
143
  send_response([200, headers, [response]], hijack, callback)
125
144
  end
126
145
  end
@@ -169,17 +188,18 @@ module Faye
169
188
  end
170
189
 
171
190
  def handle_websocket(request)
172
- ws = Faye::WebSocket.new(request.env, nil, :ping => @options[:ping])
191
+ options = {:extensions => @extensions, :ping => @options[:ping]}
192
+ ws = Faye::WebSocket.new(request.env, [], options)
173
193
  client_id = nil
174
194
 
175
195
  ws.onmessage = lambda do |event|
176
196
  begin
177
- debug "Received message via WebSocket[#{ws.version}]: ?", event.data
197
+ debug("Received message via WebSocket[#{ws.version}]: ?", event.data)
178
198
 
179
199
  message = MultiJson.load(event.data)
180
200
  cid = Faye.client_id_from_messages(message)
181
201
 
182
- @server.close_socket(client_id) if client_id and cid and cid != client_id
202
+ @server.close_socket(client_id, false) if client_id and cid and cid != client_id
183
203
  @server.open_socket(cid, ws, request)
184
204
  client_id = cid
185
205
 
@@ -203,7 +223,7 @@ module Faye
203
223
  es = Faye::EventSource.new(request.env, :ping => @options[:ping])
204
224
  client_id = es.url.split('/').pop
205
225
 
206
- debug 'Opened EventSource connection for ?', client_id
226
+ debug('Opened EventSource connection for ?', client_id)
207
227
  @server.open_socket(client_id, es, request)
208
228
 
209
229
  es.onclose = lambda do |event|
@@ -238,4 +258,3 @@ module Faye
238
258
 
239
259
  end
240
260
  end
241
-
@@ -15,7 +15,8 @@ module Faye
15
15
  end
16
16
 
17
17
  def deliver(message)
18
- return socket.send(message) if socket
18
+ message.delete('clientId')
19
+ return @socket.send(message) if @socket
19
20
  return unless @inbox.add?(message)
20
21
  begin_delivery_timeout
21
22
  end
@@ -31,28 +32,27 @@ module Faye
31
32
  begin_connection_timeout(timeout)
32
33
  end
33
34
 
34
- def flush!(force = false)
35
- @engine.close_connection(@id) if force or socket.nil?
36
-
35
+ def flush
37
36
  remove_timeout(:connection)
38
37
  remove_timeout(:delivery)
39
38
 
40
39
  set_deferred_status(:succeeded, @inbox.entries)
41
40
  @inbox = []
41
+
42
+ @engine.close_connection(@id) unless @socket
42
43
  end
43
44
 
44
45
  private
45
46
 
46
47
  def begin_delivery_timeout
47
48
  return if @inbox.empty?
48
- add_timeout(:delivery, MAX_DELAY) { flush! }
49
+ add_timeout(:delivery, MAX_DELAY) { flush }
49
50
  end
50
51
 
51
52
  def begin_connection_timeout(timeout)
52
- add_timeout(:connection, timeout) { flush! }
53
+ add_timeout(:connection, timeout) { flush }
53
54
  end
54
55
  end
55
56
 
56
57
  end
57
58
  end
58
-
@@ -28,7 +28,7 @@ module Faye
28
28
 
29
29
  def create_client(&callback)
30
30
  client_id = @namespace.generate
31
- @server.debug 'Created new client ?', client_id
31
+ @server.debug('Created new client ?', client_id)
32
32
  ping(client_id)
33
33
  @server.trigger(:handshake, client_id)
34
34
  callback.call(client_id)
@@ -44,7 +44,7 @@ module Faye
44
44
  remove_timeout(client_id)
45
45
  @namespace.release(client_id)
46
46
  @messages.delete(client_id)
47
- @server.debug 'Destroyed client ?', client_id
47
+ @server.debug('Destroyed client ?', client_id)
48
48
  @server.trigger(:disconnect, client_id)
49
49
  @server.trigger(:close, client_id)
50
50
  callback.call if callback
@@ -57,7 +57,7 @@ module Faye
57
57
  def ping(client_id)
58
58
  timeout = @server.timeout
59
59
  return unless Numeric === timeout
60
- @server.debug 'Ping ?, ?', client_id, timeout
60
+ @server.debug('Ping ?, ?', client_id, timeout)
61
61
  remove_timeout(client_id)
62
62
  add_timeout(client_id, 2 * timeout) { destroy_client(client_id) }
63
63
  end
@@ -69,7 +69,7 @@ module Faye
69
69
  @channels[channel] ||= Set.new
70
70
  @channels[channel].add(client_id)
71
71
 
72
- @server.debug 'Subscribed client ? to channel ?', client_id, channel
72
+ @server.debug('Subscribed client ? to channel ?', client_id, channel)
73
73
  @server.trigger(:subscribe, client_id, channel) if should_trigger
74
74
  callback.call(true) if callback
75
75
  end
@@ -85,13 +85,13 @@ module Faye
85
85
  @channels.delete(channel) if @channels[channel].empty?
86
86
  end
87
87
 
88
- @server.debug 'Unsubscribed client ? from channel ?', client_id, channel
88
+ @server.debug('Unsubscribed client ? from channel ?', client_id, channel)
89
89
  @server.trigger(:unsubscribe, client_id, channel) if should_trigger
90
90
  callback.call(true) if callback
91
91
  end
92
92
 
93
93
  def publish(message, channels)
94
- @server.debug 'Publishing message ?', message
94
+ @server.debug('Publishing message ?', message)
95
95
 
96
96
  clients = Set.new
97
97
 
@@ -101,7 +101,7 @@ module Faye
101
101
  end
102
102
 
103
103
  clients.each do |client_id|
104
- @server.debug 'Queueing for client ?: ?', client_id, message
104
+ @server.debug('Queueing for client ?: ?', client_id, message)
105
105
  @messages[client_id] ||= []
106
106
  @messages[client_id] << Faye.copy_object(message)
107
107
  empty_queue(client_id)
@@ -119,4 +119,3 @@ module Faye
119
119
 
120
120
  end
121
121
  end
122
-
@@ -21,7 +21,7 @@ module Faye
21
21
 
22
22
  def self.random(bitlength = ID_LENGTH)
23
23
  limit = 2 ** bitlength
24
- max_size = (limit - 1).to_s(36).size
24
+ max_size = (bitlength * Math.log(2) / Math.log(36)).ceil
25
25
  string = SecureRandom.random_number(limit).to_s(36)
26
26
  string = '0' + string while string.size < max_size
27
27
  string
@@ -48,14 +48,14 @@ module Faye
48
48
  @engine = engine_class.create(self, @options)
49
49
 
50
50
  bind :close do |client_id|
51
- EventMachine.next_tick { flush(client_id) }
51
+ EventMachine.next_tick { flush_connection(client_id) }
52
52
  end
53
53
 
54
- debug 'Created new engine: ?', @options
54
+ debug('Created new engine: ?', @options)
55
55
  end
56
56
 
57
57
  def connect(client_id, options = {}, &callback)
58
- debug 'Accepting connection from ?', client_id
58
+ debug('Accepting connection from ?', client_id)
59
59
  @engine.ping(client_id)
60
60
  conn = connection(client_id, true)
61
61
  conn.connect(options, &callback)
@@ -75,9 +75,8 @@ module Faye
75
75
  end
76
76
 
77
77
  def close_connection(client_id)
78
- debug 'Closing connection for ?', client_id
79
- conn = @connections[client_id]
80
- return unless conn
78
+ debug('Closing connection for ?', client_id)
79
+ return unless conn = @connections[client_id]
81
80
  conn.socket.close if conn.socket
82
81
  trigger('connection:close', client_id)
83
82
  @connections.delete(client_id)
@@ -90,8 +89,7 @@ module Faye
90
89
 
91
90
  def deliver(client_id, messages)
92
91
  return if !messages || messages.empty?
93
- conn = connection(client_id, false)
94
- return false unless conn
92
+ return false unless conn = connection(client_id, false)
95
93
  messages.each(&conn.method(:deliver))
96
94
  true
97
95
  end
@@ -100,15 +98,17 @@ module Faye
100
98
  Engine.random
101
99
  end
102
100
 
103
- def flush(client_id)
101
+ def flush_connection(client_id, close = true)
104
102
  return unless client_id
105
- debug 'Flushing connection for ?', client_id
106
- conn = connection(client_id, false)
107
- conn.flush!(true) if conn
103
+ debug('Flushing connection for ?', client_id)
104
+ return unless conn = connection(client_id, false)
105
+ conn.socket = nil unless close
106
+ conn.flush
107
+ close_connection(client_id)
108
108
  end
109
109
 
110
110
  def close
111
- @connections.keys.each { |client_id| flush(client_id) }
111
+ @connections.keys.each { |client_id| flush_connection(client_id) }
112
112
  @engine.disconnect
113
113
  end
114
114
 
@@ -124,4 +124,3 @@ module Faye
124
124
 
125
125
  end
126
126
  end
127
-
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
 
@@ -92,10 +92,9 @@ module Faye
92
92
  end
93
93
 
94
94
  def subscribe(names, callback)
95
- return unless callback
96
95
  names.each do |name|
97
96
  channel = @channels[name] ||= Channel.new(name)
98
- channel.bind(:message, &callback)
97
+ channel.bind(:message, &callback) if callback
99
98
  end
100
99
  end
101
100
 
@@ -122,4 +121,3 @@ module Faye
122
121
 
123
122
  end
124
123
  end
125
-
@@ -6,59 +6,42 @@ 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])
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
28
+ @endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
44
29
  @channels = Channel::Set.new
30
+ @dispatcher = Dispatcher.new(self, @endpoint, options)
31
+
45
32
  @message_id = 0
33
+ @state = UNCONNECTED
46
34
 
47
35
  @response_callbacks = {}
48
36
 
49
37
  @advice = {
50
38
  'reconnect' => RETRY,
51
- 'interval' => 1000.0 * (@options[:interval] || Engine::INTERVAL),
52
- 'timeout' => 1000.0 * (@options[:timeout] || CONNECTION_TIMEOUT)
39
+ 'interval' => 1000.0 * (options[:interval] || Engine::INTERVAL),
40
+ 'timeout' => 1000.0 * (options[:timeout] || CONNECTION_TIMEOUT)
53
41
  }
54
- end
55
-
56
- def disable(feature)
57
- @disabled << feature
58
- end
42
+ @dispatcher.timeout = @advice['timeout'] / 1000.0
59
43
 
60
- def set_header(name, value)
61
- @headers[name.to_s] = value.to_s
44
+ @dispatcher.bind(:message, &method(:receive_message))
62
45
  end
63
46
 
64
47
  # Request
@@ -87,29 +70,29 @@ module Faye
87
70
  @state = CONNECTING
88
71
 
89
72
  info('Initiating handshake with ?', @endpoint)
90
- select_transport(MANDATORY_CONNECTION_TYPES)
73
+ @dispatcher.select_transport(MANDATORY_CONNECTION_TYPES)
91
74
 
92
- send({
93
- 'channel' => Channel::HANDSHAKE,
94
- 'version' => BAYEUX_VERSION,
95
- 'supportedConnectionTypes' => [@transport.connection_type]
75
+ send_message({
76
+ 'channel' => Channel::HANDSHAKE,
77
+ 'version' => BAYEUX_VERSION,
78
+ 'supportedConnectionTypes' => @dispatcher.connection_types
96
79
 
97
- }) do |response|
80
+ }, {}) do |response|
98
81
 
99
82
  if response['successful']
100
- @state = CONNECTED
101
- @client_id = response['clientId']
83
+ @state = CONNECTED
84
+ @dispatcher.client_id = response['clientId']
102
85
 
103
- select_transport(response['supportedConnectionTypes'])
86
+ @dispatcher.select_transport(response['supportedConnectionTypes'])
104
87
 
105
- info('Handshake successful: ?', @client_id)
88
+ info('Handshake successful: ?', @dispatcher.client_id)
106
89
 
107
90
  subscribe(@channels.keys, true)
108
91
  block.call if block_given?
109
92
 
110
93
  else
111
94
  info('Handshake unsuccessful')
112
- EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
95
+ EventMachine.add_timer(@dispatcher.retry) { handshake(&block) }
113
96
  @state = UNCONNECTED
114
97
  end
115
98
  end
@@ -133,21 +116,21 @@ module Faye
133
116
  callback(&block)
134
117
  return unless @state == CONNECTED
135
118
 
136
- info('Calling deferred actions for ?', @client_id)
119
+ info('Calling deferred actions for ?', @dispatcher.client_id)
137
120
  set_deferred_status(:succeeded)
138
121
  set_deferred_status(:unknown)
139
122
 
140
123
  return unless @connect_request.nil?
141
124
  @connect_request = true
142
125
 
143
- info('Initiating connection for ?', @client_id)
126
+ info('Initiating connection for ?', @dispatcher.client_id)
144
127
 
145
- send({
146
- 'channel' => Channel::CONNECT,
147
- 'clientId' => @client_id,
148
- 'connectionType' => @transport.connection_type
128
+ send_message({
129
+ 'channel' => Channel::CONNECT,
130
+ 'clientId' => @dispatcher.client_id,
131
+ 'connectionType' => @dispatcher.connection_type
149
132
 
150
- }) do
133
+ }, {}) do
151
134
  cycle_connection
152
135
  end
153
136
  end
@@ -163,18 +146,26 @@ module Faye
163
146
  return unless @state == CONNECTED
164
147
  @state = DISCONNECTED
165
148
 
166
- info('Disconnecting ?', @client_id)
149
+ info('Disconnecting ?', @dispatcher.client_id)
150
+ promise = Publication.new
167
151
 
168
- send({
169
- 'channel' => Channel::DISCONNECT,
170
- 'clientId' => @client_id
152
+ send_message({
153
+ 'channel' => Channel::DISCONNECT,
154
+ 'clientId' => @dispatcher.client_id
171
155
 
172
- }) do |response|
173
- @transport.close if response['successful']
156
+ }, {}) do |response|
157
+ if response['successful']
158
+ @dispatcher.close
159
+ promise.set_deferred_status(:succeeded)
160
+ else
161
+ promise.set_deferred_status(:failed, Error.parse(response['error']))
162
+ end
174
163
  end
175
164
 
176
- info('Clearing channel listeners for ?', @client_id)
165
+ info('Clearing channel listeners for ?', @dispatcher.client_id)
177
166
  @channels = Channel::Set.new
167
+
168
+ promise
178
169
  end
179
170
 
180
171
  # Request Response
@@ -202,22 +193,22 @@ module Faye
202
193
  end
203
194
 
204
195
  connect {
205
- info('Client ? attempting to subscribe to ?', @client_id, channel)
196
+ info('Client ? attempting to subscribe to ?', @dispatcher.client_id, channel)
206
197
  @channels.subscribe([channel], block) unless force
207
198
 
208
- send({
209
- 'channel' => Channel::SUBSCRIBE,
210
- 'clientId' => @client_id,
211
- 'subscription' => channel
199
+ send_message({
200
+ 'channel' => Channel::SUBSCRIBE,
201
+ 'clientId' => @dispatcher.client_id,
202
+ 'subscription' => channel
212
203
 
213
- }) do |response|
204
+ }, {}) do |response|
214
205
  unless response['successful']
215
206
  subscription.set_deferred_status(:failed, Error.parse(response['error']))
216
207
  next @channels.unsubscribe(channel, block)
217
208
  end
218
209
 
219
210
  channels = [response['subscription']].flatten
220
- info('Subscription acknowledged for ? to ?', @client_id, channels)
211
+ info('Subscription acknowledged for ? to ?', @dispatcher.client_id, channels)
221
212
  subscription.set_deferred_status(:succeeded)
222
213
  end
223
214
  }
@@ -243,18 +234,18 @@ module Faye
243
234
  return unless dead
244
235
 
245
236
  connect {
246
- info('Client ? attempting to unsubscribe from ?', @client_id, channel)
237
+ info('Client ? attempting to unsubscribe from ?', @dispatcher.client_id, channel)
247
238
 
248
- send({
249
- 'channel' => Channel::UNSUBSCRIBE,
250
- 'clientId' => @client_id,
251
- 'subscription' => channel
239
+ send_message({
240
+ 'channel' => Channel::UNSUBSCRIBE,
241
+ 'clientId' => @dispatcher.client_id,
242
+ 'subscription' => channel
252
243
 
253
- }) do |response|
244
+ }, {}) do |response|
254
245
  next unless response['successful']
255
246
 
256
247
  channels = [response['subscription']].flatten
257
- info('Unsubscription acknowledged for ? from ?', @client_id, channels)
248
+ info('Unsubscription acknowledged for ? from ?', @dispatcher.client_id, channels)
258
249
  end
259
250
  }
260
251
  end
@@ -265,17 +256,19 @@ module Faye
265
256
  # MAY include: * clientId MAY include: * id
266
257
  # * id * error
267
258
  # * ext * ext
268
- def publish(channel, data)
259
+ def publish(channel, data, options = {})
260
+ ::WebSocket::Driver.validate_options(options, [:attempts, :deadline])
261
+
269
262
  publication = Publication.new
270
263
  connect {
271
- info('Client ? queueing published message to ?: ?', @client_id, channel, data)
264
+ info('Client ? queueing published message to ?: ?', @dispatcher.client_id, channel, data)
272
265
 
273
- send({
274
- 'channel' => channel,
275
- 'data' => data,
276
- 'clientId' => @client_id
266
+ send_message({
267
+ 'channel' => channel,
268
+ 'data' => data,
269
+ 'clientId' => @dispatcher.client_id
277
270
 
278
- }) do |response|
271
+ }, options) do |response|
279
272
  if response['successful']
280
273
  publication.set_deferred_status(:succeeded)
281
274
  else
@@ -286,81 +279,20 @@ module Faye
286
279
  publication
287
280
  end
288
281
 
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
282
  private
327
283
 
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
284
+ def send_message(message, options, &callback)
341
285
  message['id'] = generate_message_id
342
286
 
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
287
  timeout = [nil, 0].include?(@advice['timeout']) ?
354
- 1.2 * @retry :
288
+ 1.2 * @dispatcher.retry :
355
289
  1.2 * @advice['timeout'] / 1000.0
356
290
 
357
- envelope = Envelope.new(message, timeout)
358
-
359
- envelope.errback do |immediate|
360
- message_error([message], immediate)
291
+ pipe_through_extensions(:outgoing, message, nil) do |message|
292
+ next unless message
293
+ @response_callbacks[message['id']] = callback if callback
294
+ @dispatcher.send_message(message, timeout, options)
361
295
  end
362
-
363
- @transport.send(envelope)
364
296
  end
365
297
 
366
298
  def generate_message_id
@@ -369,30 +301,45 @@ module Faye
369
301
  @message_id.to_s(36)
370
302
  end
371
303
 
304
+ def receive_message(message)
305
+ id = message['id']
306
+
307
+ if message.has_key?('successful')
308
+ callback = @response_callbacks.delete(id)
309
+ end
310
+
311
+ pipe_through_extensions(:incoming, message, nil) do |message|
312
+ next unless message
313
+ handle_advice(message['advice']) if message['advice']
314
+ deliver_message(message)
315
+ callback.call(message) if callback
316
+ end
317
+ end
318
+
372
319
  def handle_advice(advice)
373
320
  @advice.update(advice)
321
+ @dispatcher.timeout = @advice['timeout'] / 1000.0
374
322
 
375
323
  if @advice['reconnect'] == HANDSHAKE and @state != DISCONNECTED
376
- @state = UNCONNECTED
377
- @client_id = nil
324
+ @state = UNCONNECTED
325
+ @dispatcher.client_id = nil
378
326
  cycle_connection
379
327
  end
380
328
  end
381
329
 
382
330
  def deliver_message(message)
383
331
  return unless message.has_key?('channel') and message.has_key?('data')
384
- info('Client ? calling listeners for ? with ?', @client_id, message['channel'], message['data'])
332
+ info('Client ? calling listeners for ? with ?', @dispatcher.client_id, message['channel'], message['data'])
385
333
  @channels.distribute_message(message)
386
334
  end
387
335
 
388
336
  def cycle_connection
389
337
  if @connect_request
390
338
  @connect_request = nil
391
- info('Closed connection for ?', @client_id)
339
+ info('Closed connection for ?', @dispatcher.client_id)
392
340
  end
393
341
  EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
394
342
  end
395
343
 
396
344
  end
397
345
  end
398
-