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.

@@ -0,0 +1,170 @@
1
+ module Faye
2
+ class Dispatcher
3
+
4
+ class Envelope < Struct.new(:message, :scheduler, :request, :timer)
5
+ end
6
+
7
+ MAX_REQUEST_SIZE = 2048
8
+ DEFAULT_RETRY = 5.0
9
+
10
+ UP = 1
11
+ DOWN = 2
12
+
13
+ include Publisher
14
+ include Logging
15
+ extend Forwardable
16
+ def_delegators :@transport, :connection_type
17
+
18
+ attr_accessor :client_id, :timeout
19
+ attr_reader :cookies, :endpoint, :headers, :max_request_size, :proxy, :retry, :transports, :ws_extensions
20
+
21
+ def initialize(client, endpoint, options)
22
+ super()
23
+
24
+ @client = client
25
+ @endpoint = Faye.parse_url(endpoint)
26
+ @alternates = options[:endpoints] || {}
27
+
28
+ @cookies = CookieJar::Jar.new
29
+ @disabled = []
30
+ @envelopes = {}
31
+ @headers = {}
32
+ @retry = options[:retry] || DEFAULT_RETRY
33
+ @scheduler = options[:scheduler] || Faye::Scheduler
34
+ @state = 0
35
+ @transports = {}
36
+ @ws_extensions = []
37
+
38
+ @proxy = options[:proxy] || {}
39
+ @proxy = {:origin => @proxy} if String === @proxy
40
+
41
+ [*options[:websocket_extensions]].each do |extension|
42
+ add_websocket_extension(extension)
43
+ end
44
+
45
+ @alternates.each do |type, url|
46
+ @alternates[type] = Faye.parse_url(url)
47
+ end
48
+
49
+ @max_request_size = MAX_REQUEST_SIZE
50
+ end
51
+
52
+ def endpoint_for(connection_type)
53
+ @alternates[connection_type] || @endpoint
54
+ end
55
+
56
+ def add_websocket_extension(extension)
57
+ @ws_extensions << extension
58
+ end
59
+
60
+ def disable(feature)
61
+ @disabled << feature
62
+ end
63
+
64
+ def set_header(name, value)
65
+ @headers[name.to_s] = value.to_s
66
+ end
67
+
68
+ def close
69
+ transport = @transport
70
+ @transport = nil
71
+ transport.close if transport
72
+ end
73
+
74
+ def connection_types
75
+ Transport.connection_types
76
+ end
77
+
78
+ def select_transport(transport_types)
79
+ Transport.get(self, transport_types, @disabled) do |transport|
80
+ debug('Selected ? transport for ?', transport.connection_type, transport.endpoint)
81
+
82
+ next if transport == @transport
83
+ @transport.close if @transport
84
+
85
+ @transport = transport
86
+ end
87
+ end
88
+
89
+ def send_message(message, timeout, options = {})
90
+ return unless @transport
91
+
92
+ id = message['id']
93
+ attempts = options[:attempts]
94
+ deadline = options[:deadline] && Time.now.to_f + options[:deadline]
95
+ envelope = @envelopes[id]
96
+
97
+ unless envelope
98
+ scheduler = @scheduler.new(message, :timeout => timeout, :interval => @retry, :attempts => attempts, :deadline => deadline)
99
+ envelope = @envelopes[id] = Envelope.new(message, scheduler, nil, nil)
100
+ end
101
+
102
+ send_envelope(envelope)
103
+ end
104
+
105
+ def send_envelope(envelope)
106
+ return if envelope.request or envelope.timer
107
+
108
+ message = envelope.message
109
+ scheduler = envelope.scheduler
110
+
111
+ unless scheduler.deliverable?
112
+ scheduler.abort!
113
+ @envelopes.delete(message['id'])
114
+ return
115
+ end
116
+
117
+ envelope.timer = EventMachine.add_timer(scheduler.timeout) do
118
+ handle_error(message)
119
+ end
120
+
121
+ scheduler.send!
122
+ envelope.request = @transport.send_message(message)
123
+ end
124
+ private :send_envelope
125
+
126
+ def handle_response(reply)
127
+ envelope = @envelopes.delete(reply['id'])
128
+
129
+ if reply.has_key?('successful') and envelope
130
+ envelope.scheduler.succeed!
131
+ EventMachine.cancel_timer(envelope.timer) if envelope.timer
132
+ end
133
+
134
+ trigger(:message, reply)
135
+
136
+ return if @state == UP
137
+ @state = UP
138
+ @client.trigger('transport:up')
139
+ end
140
+
141
+ def handle_error(message, immediate = false)
142
+ return unless envelope = @envelopes[message['id']]
143
+ return unless request = envelope.request
144
+
145
+ request.callback do |req|
146
+ req.close if req.respond_to?(:close)
147
+ end
148
+
149
+ scheduler = envelope.scheduler
150
+ scheduler.fail!
151
+
152
+ EventMachine.cancel_timer(envelope.timer)
153
+ envelope.request = envelope.timer = nil
154
+
155
+ if immediate
156
+ send_envelope(envelope)
157
+ else
158
+ envelope.timer = EventMachine.add_timer(scheduler.interval) do
159
+ envelope.timer = nil
160
+ send_envelope(envelope)
161
+ end
162
+ end
163
+
164
+ return if @state == DOWN
165
+ @state = DOWN
166
+ @client.trigger('transport:down')
167
+ end
168
+
169
+ end
170
+ end
@@ -18,7 +18,7 @@ module Faye
18
18
  end
19
19
 
20
20
  def pipe_through_extensions(stage, message, env, &callback)
21
- debug 'Passing through ? extensions: ?', stage, message
21
+ debug('Passing through ? extensions: ?', stage, message)
22
22
 
23
23
  return callback.call(message) unless @extensions
24
24
  extensions = @extensions.dup
@@ -43,4 +43,3 @@ module Faye
43
43
 
44
44
  end
45
45
  end
46
-
@@ -55,4 +55,3 @@ module Faye
55
55
 
56
56
  end
57
57
  end
58
-
@@ -0,0 +1,43 @@
1
+ module Faye
2
+ class Scheduler
3
+
4
+ def initialize(message, options)
5
+ @message = message
6
+ @options = options
7
+ @attempts = 0
8
+ end
9
+
10
+ def interval
11
+ @options[:interval]
12
+ end
13
+
14
+ def timeout
15
+ @options[:timeout]
16
+ end
17
+
18
+ def deliverable?
19
+ attempts = @options[:attempts]
20
+ deadline = @options[:deadline]
21
+ now = Time.now.to_f
22
+
23
+ return false if attempts and @attempts >= attempts
24
+ return false if deadline and now > deadline
25
+
26
+ true
27
+ end
28
+
29
+ def send!
30
+ @attempts += 1
31
+ end
32
+
33
+ def succeed!
34
+ end
35
+
36
+ def fail!
37
+ end
38
+
39
+ def abort!
40
+ end
41
+
42
+ end
43
+ end
@@ -6,6 +6,8 @@ module Faye
6
6
  include Logging
7
7
  include Extensible
8
8
 
9
+ META_METHODS = %w[handshake connect disconnect subscribe unsubscribe]
10
+
9
11
  attr_reader :engine
10
12
 
11
13
  def initialize(options = {})
@@ -14,7 +16,7 @@ module Faye
14
16
  engine_opts[:timeout] = @options[:timeout]
15
17
  @engine = Faye::Engine.get(engine_opts)
16
18
 
17
- info 'Created new server: ?', @options
19
+ info('Created new server: ?', @options)
18
20
  end
19
21
 
20
22
  def close
@@ -26,14 +28,14 @@ module Faye
26
28
  @engine.open_socket(client_id, Socket.new(self, socket, env))
27
29
  end
28
30
 
29
- def close_socket(client_id)
30
- @engine.flush(client_id)
31
+ def close_socket(client_id, close = true)
32
+ @engine.flush_connection(client_id, close)
31
33
  end
32
34
 
33
35
  def process(messages, env, &callback)
34
36
  local = env.nil?
35
37
  messages = [messages].flatten
36
- info 'Processing messages: ? (local: ?)', messages, local
38
+ info('Processing messages: ? (local: ?)', messages, local)
37
39
 
38
40
  return callback.call([]) if messages.size == 0
39
41
  processed, responses = 0, []
@@ -42,7 +44,7 @@ module Faye
42
44
  responses.concat(replies)
43
45
  processed += 1
44
46
  responses.compact!
45
- info 'Returning replies: ?', responses
47
+ info('Returning replies: ?', responses)
46
48
  callback.call(responses) if processed == messages.size
47
49
  end
48
50
 
@@ -51,7 +53,7 @@ module Faye
51
53
  gather_replies.call(replies) if expected == 0
52
54
 
53
55
  replies.each_with_index do |reply, i|
54
- debug 'Processing reply: ?', reply
56
+ debug('Processing reply: ?', reply)
55
57
  pipe_through_extensions(:outgoing, reply, env) do |message|
56
58
  replies[i] = message
57
59
  extended += 1
@@ -81,7 +83,7 @@ module Faye
81
83
 
82
84
  def handle(message, local = false, &callback)
83
85
  return callback.call([]) if !message
84
- info 'Handling message: ? (local: ?)', message, local
86
+ info('Handling message: ? (local: ?)', message, local)
85
87
 
86
88
  channel_name = message['channel']
87
89
  error = message['error']
@@ -92,7 +94,6 @@ module Faye
92
94
  error = Faye::Error.channel_invalid(channel_name)
93
95
  end
94
96
 
95
- message.delete('clientId')
96
97
  @engine.publish(message) unless error
97
98
 
98
99
  response = make_response(message)
@@ -102,10 +103,9 @@ module Faye
102
103
  end
103
104
 
104
105
  def handle_meta(message, local, &callback)
105
- method = method_for(message)
106
- client_id = message['clientId']
106
+ method = Channel.parse(message['channel'])[1]
107
107
 
108
- unless method
108
+ unless META_METHODS.include?(method)
109
109
  response = make_response(message)
110
110
  response['error'] = Faye::Error.channel_forbidden(message['channel'])
111
111
  response['successful'] = false
@@ -119,16 +119,6 @@ module Faye
119
119
  end
120
120
  end
121
121
 
122
- def method_for(message)
123
- case message['channel']
124
- when Channel::HANDSHAKE then :handshake
125
- when Channel::CONNECT then :connect
126
- when Channel::SUBSCRIBE then :subscribe
127
- when Channel::UNSUBSCRIBE then :unsubscribe
128
- when Channel::DISCONNECT then :disconnect
129
- end
130
- end
131
-
132
122
  def advize(response, connection_type)
133
123
  return unless [Channel::HANDSHAKE, Channel::CONNECT].include?(response['channel'])
134
124
 
@@ -299,4 +289,3 @@ module Faye
299
289
 
300
290
  end
301
291
  end
302
-
@@ -22,4 +22,3 @@ module Faye
22
22
 
23
23
  end
24
24
  end
25
-
@@ -21,4 +21,3 @@ module Faye
21
21
 
22
22
  end
23
23
  end
24
-
@@ -1,65 +1,78 @@
1
1
  module Faye
2
2
 
3
3
  class Transport::Http < Transport
4
- def self.usable?(client, endpoint, &callback)
4
+ def self.usable?(dispatcher, endpoint, &callback)
5
5
  callback.call(URI === endpoint)
6
6
  end
7
7
 
8
- def encode(envelopes)
9
- Faye.to_json(envelopes.map { |e| e.message })
8
+ def encode(messages)
9
+ Faye.to_json(messages)
10
10
  end
11
11
 
12
- def request(envelopes)
13
- content = encode(envelopes)
14
- params = build_params(@endpoint, content)
12
+ def request(messages)
13
+ content = encode(messages)
14
+ params = build_params(content)
15
15
  request = create_request(params)
16
16
 
17
17
  request.callback do
18
- handle_response(request.response, envelopes)
18
+ handle_response(messages, request.response)
19
19
  store_cookies(request.response_header['SET_COOKIE'])
20
20
  end
21
21
 
22
22
  request.errback do
23
- handle_error(envelopes)
23
+ handle_error(messages)
24
24
  end
25
+
26
+ request
25
27
  end
26
28
 
27
29
  private
28
30
 
29
- def build_params(uri, content)
30
- {
31
+ def build_params(content)
32
+ params = {
31
33
  :head => {
32
- 'Content-Length' => content.bytesize,
33
- 'Content-Type' => 'application/json',
34
- 'Cookie' => get_cookies,
35
- 'Host' => uri.host
36
- }.merge(@client.headers),
34
+ 'Content-Length' => content.bytesize,
35
+ 'Content-Type' => 'application/json',
36
+ 'Host' => @endpoint.host + (@endpoint.port ? ":#{@endpoint.port}" : '')
37
+ }.merge(@dispatcher.headers),
37
38
 
38
39
  :body => content,
39
40
  :timeout => -1 # for em-http-request < 1.0
40
41
  }
42
+
43
+ cookie = get_cookies
44
+ params[:head]['Cookie'] = cookie unless cookie == ''
45
+
46
+ params
41
47
  end
42
48
 
43
49
  def create_request(params)
44
50
  version = EventMachine::HttpRequest::VERSION.split('.')[0].to_i
45
- client = if version >= 1
46
- options = { # for em-http-request >= 1.0
47
- :inactivity_timeout => 0 # connection inactivity (post-setup) timeout (0 = disable timeout)
48
- }
49
- EventMachine::HttpRequest.new(@endpoint.to_s, options)
50
- else
51
- EventMachine::HttpRequest.new(@endpoint.to_s)
52
- end
51
+ options = {:inactivity_timeout => 0}
52
+
53
+ if @proxy[:origin]
54
+ uri = URI.parse(@proxy[:origin])
55
+ options[:proxy] = {:host => uri.host, :port => uri.port}
56
+ if uri.user
57
+ options[:proxy][:authorization] = [uri.user, uri.password]
58
+ end
59
+ end
60
+
61
+ if version >= 1
62
+ client = EventMachine::HttpRequest.new(@endpoint.to_s, options)
63
+ else
64
+ client = EventMachine::HttpRequest.new(@endpoint.to_s)
65
+ end
53
66
 
54
67
  client.post(params)
55
68
  end
56
69
 
57
- def handle_response(response, envelopes)
58
- message = MultiJson.load(response) rescue nil
59
- if message
60
- receive(envelopes, message)
70
+ def handle_response(messages, response)
71
+ replies = MultiJson.load(response) rescue nil
72
+ if replies
73
+ receive(replies)
61
74
  else
62
- handle_error(envelopes)
75
+ handle_error(messages)
63
76
  end
64
77
  end
65
78
  end