firehose 0.1.1 → 0.2.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.env.sample +10 -0
- data/.gitignore +2 -0
- data/Procfile +1 -1
- data/README.md +117 -11
- data/config/rainbows.rb +20 -0
- data/firehose.gemspec +9 -6
- data/lib/assets/flash/firehose/WebSocketMain.swf +0 -0
- data/lib/assets/javascripts/firehose.js.coffee +4 -1
- data/lib/assets/javascripts/firehose/consumer.js.coffee +3 -11
- data/lib/assets/javascripts/firehose/lib/jquery.cors.headers.js.coffee +16 -0
- data/lib/assets/javascripts/firehose/lib/swfobject.js +4 -0
- data/lib/assets/javascripts/firehose/lib/web_socket.js +389 -0
- data/lib/assets/javascripts/firehose/long_poll.js.coffee +42 -39
- data/lib/assets/javascripts/firehose/transport.js.coffee +1 -1
- data/lib/assets/javascripts/firehose/web_socket.js.coffee +8 -14
- data/lib/firehose.rb +12 -17
- data/lib/firehose/channel.rb +84 -0
- data/lib/firehose/cli.rb +57 -13
- data/lib/firehose/client.rb +92 -0
- data/lib/firehose/default.rb +2 -2
- data/lib/firehose/logging.rb +35 -0
- data/lib/firehose/producer.rb +1 -0
- data/lib/firehose/publisher.rb +56 -4
- data/lib/firehose/rack.rb +37 -120
- data/lib/firehose/rack/consumer_app.rb +143 -0
- data/lib/firehose/rack/ping_app.rb +84 -0
- data/lib/firehose/rack/publisher_app.rb +40 -0
- data/lib/firehose/server.rb +48 -0
- data/lib/firehose/subscriber.rb +54 -0
- data/lib/firehose/swf_policy_request.rb +23 -0
- data/lib/firehose/version.rb +2 -2
- data/lib/rainbows_em_swf_policy.rb +33 -0
- data/lib/thin_em_swf_policy.rb +26 -0
- data/spec/integrations/integration_test_helper.rb +16 -0
- data/spec/integrations/rainbows_spec.rb +7 -0
- data/spec/integrations/shared_examples.rb +111 -0
- data/spec/integrations/thin_spec.rb +5 -79
- data/spec/lib/channel_spec.rb +164 -0
- data/spec/lib/client_spec.rb +9 -0
- data/spec/lib/default_spec.rb +2 -2
- data/spec/lib/publisher_spec.rb +82 -0
- data/spec/lib/rack/consumer_app_spec.rb +11 -0
- data/spec/lib/rack/ping_app_spec.rb +28 -0
- data/spec/lib/rack/publisher_app_spec.rb +26 -0
- data/spec/lib/subscriber_spec.rb +69 -0
- data/spec/spec_helper.rb +49 -8
- metadata +114 -45
- data/config.ru +0 -6
- data/lib/firehose/subscription.rb +0 -77
@@ -1,4 +1,6 @@
|
|
1
1
|
class Firehose.LongPoll extends Firehose.Transport
|
2
|
+
messageSequenceHeader: 'pragma'
|
3
|
+
|
2
4
|
# CORS is supported in IE 8+
|
3
5
|
@ieSupported: =>
|
4
6
|
$.browser.msie and parseInt($.browser.version) > 7 and window.XDomainRequest
|
@@ -15,56 +17,43 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
15
17
|
# Protocol schema we should use for talking to WS server.
|
16
18
|
@config.longPoll.url ||= "http:#{@config.uri}"
|
17
19
|
# How many ms should we wait before timing out the AJAX connection?
|
18
|
-
@config.longPoll.timeout ||=
|
20
|
+
@config.longPoll.timeout ||= 25000
|
19
21
|
|
20
22
|
# TODO - What is @_lagTime for? Can't we just use the @_timeout value?
|
21
23
|
# We use the lag time to make the client live longer than the server.
|
22
24
|
@_lagTime = 5000
|
23
25
|
@_timeout = @config.longPoll.timeout + @_lagTime
|
24
|
-
@_offlineTimer
|
25
26
|
@_okInterval = 0
|
26
27
|
|
27
|
-
@
|
28
|
-
|
29
|
-
registerIETransport: =>
|
30
|
-
if Firehose.LongPoll.ieSupported()
|
31
|
-
# TODO - Ask Steel what this is for. Looks like some kind of polygot fill, but I want
|
32
|
-
# to take the 'json' transport out and do that myself.
|
33
|
-
$.ajaxTransport 'json', (options, orignalOptions, jqXhr) ->
|
34
|
-
xdr = null
|
35
|
-
send: (_, callback) ->
|
36
|
-
xdr = new XDomainRequest()
|
37
|
-
xdr.onload = ->
|
38
|
-
statusCode = if xdr.responseText.length > 0 then 200 else 204
|
39
|
-
callback(statusCode, 'success', text: xdr.responseText)
|
40
|
-
|
41
|
-
xdr.onerror = xdr.ontimeout = ->
|
42
|
-
callback(400, 'failed', text: xdr.responseText)
|
43
|
-
|
44
|
-
xdr.open(options.type, options.url)
|
45
|
-
xdr.send(options.data)
|
46
|
-
|
47
|
-
abort: ->
|
48
|
-
if xdr
|
49
|
-
xdr.onerror = $.noop()
|
50
|
-
xdr.abort()
|
51
|
-
|
52
|
-
# also, override the support check
|
53
|
-
$.support.cors = true;
|
54
|
-
|
28
|
+
@_isConnected = false
|
29
|
+
|
55
30
|
connect: (delay = 0) =>
|
56
|
-
@
|
31
|
+
unless @_isConnected
|
32
|
+
@_isConnected = true
|
33
|
+
@config.connected()
|
57
34
|
super(delay)
|
58
35
|
|
59
36
|
_request: =>
|
37
|
+
# Set the Last Message Sequence in a query string.
|
38
|
+
# Ideally we'd use an HTTP header, but android devices don't let us
|
39
|
+
# set any HTTP headers for CORS requests.
|
40
|
+
data = @config.params
|
41
|
+
data.last_message_sequence = @_lastMessageSequence
|
42
|
+
# TODO: Some of these options will be deprecated in jQurey 1.8
|
43
|
+
# See: http://api.jquery.com/jQuery.ajax/#jqXHR
|
60
44
|
$.ajax @config.longPoll.url,
|
61
45
|
crossDomain: true
|
62
|
-
|
63
|
-
data: @config.params
|
46
|
+
data: data
|
64
47
|
timeout: @_timeout
|
65
48
|
success: @_success
|
66
49
|
error: @_error
|
67
|
-
|
50
|
+
complete: (jqXhr) =>
|
51
|
+
# Get the last sequence from the server if specified.
|
52
|
+
if jqXhr.status == 200
|
53
|
+
@_lastMessageSequence = jqXhr.getResponseHeader(@messageSequenceHeader)
|
54
|
+
if @_lastMessageSequence == null
|
55
|
+
console.log 'ERROR: Unable to get last message sequnce from header'
|
56
|
+
|
68
57
|
_success: (data, status, jqXhr) =>
|
69
58
|
# TODO we actually want to do this when the thing calls out... mmm right now it takes
|
70
59
|
# up to 30s before we can call this thing.
|
@@ -76,16 +65,30 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
76
65
|
#
|
77
66
|
# Why did we use a 204 and not a 408? Because FireFox is really stupid about 400 level error
|
78
67
|
# codes and would claims its a 0 error code, which we use for something else. Firefox is IE
|
79
|
-
# in
|
68
|
+
# in this case
|
80
69
|
@connect(@_okInterval)
|
81
70
|
else
|
82
|
-
@config.message(@config.parse(
|
71
|
+
@config.message(@config.parse(jqXhr.responseText))
|
83
72
|
@connect(@_okInterval)
|
84
73
|
|
74
|
+
_ping: =>
|
75
|
+
# Ping long poll server to verify internet connectivity
|
76
|
+
# jQuery CORS doesn't support timeouts and there is no way to access xhr2 object
|
77
|
+
# directly so we can't manually set a timeout.
|
78
|
+
$.ajax @config.longPoll.url,
|
79
|
+
method: 'HEAD'
|
80
|
+
crossDomain: true
|
81
|
+
data: @config.params
|
82
|
+
success: @config.connected
|
83
|
+
|
85
84
|
# We need this custom handler to have the connection status
|
86
85
|
# properly displayed
|
87
86
|
_error: (jqXhr, status, error) =>
|
88
|
-
|
87
|
+
@_isConnected = false
|
89
88
|
@config.disconnected()
|
90
|
-
|
91
|
-
|
89
|
+
|
90
|
+
# Ping the server to make sure this isn't a network connectivity error
|
91
|
+
setTimeout @_ping, @_retryDelay + @_lagTime
|
92
|
+
|
93
|
+
# Reconnect with delay
|
94
|
+
setTimeout @_request, @_retryDelay
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Unfortunately this needs to a global variable. The only other option is to
|
2
|
+
# hack into the internals of the web_socket.js plugin we are using.
|
3
|
+
window.WEB_SOCKET_SWF_LOCATION = '/assets/firehose/WebSocketMain.swf' if !window.WEB_SOCKET_SWF_LOCATION
|
4
4
|
|
5
|
+
class Firehose.WebSocket extends Firehose.Transport
|
5
6
|
@supported: =>
|
6
7
|
# Compatibility reference: http://caniuse.com/websockets
|
7
|
-
#
|
8
|
-
|
8
|
+
# We don't need to explicitly check for Flash web socket or MozWebSocket
|
9
|
+
# because web_socket.js has already handled that.
|
10
|
+
!!(window.WebSocket)
|
9
11
|
|
10
12
|
constructor: (args) ->
|
11
13
|
super args
|
@@ -14,14 +16,6 @@ class Firehose.WebSocket extends Firehose.Transport
|
|
14
16
|
@config.webSocket ||= {}
|
15
17
|
# Protocol schema we should use for talking to WS server.
|
16
18
|
@config.webSocket.url ||= "ws:#{@config.uri}?#{$.param(@config.params)}"
|
17
|
-
# Path of the swf WebSocket that we use in non-WS flash browsers.
|
18
|
-
@config.webSocket.swf_path ||= "/flash/firehose/WebSocketMain.swf"
|
19
|
-
|
20
|
-
# Set flash socket path for the WS SWF polyfill.
|
21
|
-
WebSocket.__swfLocation = @config.webSocket.swf_path
|
22
|
-
|
23
|
-
# Mozilla decided to have their own implementation of Web Sockets so detect for that.
|
24
|
-
window.WebSocket = window.MozWebSocket if window["MozWebSocket"] and window.MozWebSocket
|
25
19
|
|
26
20
|
_request: =>
|
27
21
|
@socket = new window.WebSocket(@config.webSocket.url)
|
@@ -49,4 +43,4 @@ class Firehose.WebSocket extends Firehose.Transport
|
|
49
43
|
@socket.close()
|
50
44
|
delete(@socket)
|
51
45
|
|
52
|
-
super
|
46
|
+
super
|
data/lib/firehose.rb
CHANGED
@@ -1,24 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'em-hiredis'
|
4
|
-
require 'logger'
|
1
|
+
ENV['RACK_ENV'] ||= 'development'
|
5
2
|
|
6
|
-
require 'firehose/
|
3
|
+
require 'firehose/version'
|
4
|
+
require 'em-hiredis' # TODO Move this into a Redis module so that we can auto-load it. Lots of the CLI tools don't need this.
|
5
|
+
require 'firehose/logging'
|
6
|
+
require 'firehose/rails' if defined?(::Rails::Engine) # TODO Detect Sprockets instead of the jankin Rails::Engine test.
|
7
7
|
|
8
8
|
module Firehose
|
9
|
-
autoload :
|
9
|
+
autoload :Subscriber, 'firehose/subscriber'
|
10
10
|
autoload :Publisher, 'firehose/publisher'
|
11
|
-
autoload :Producer, 'firehose/producer'
|
11
|
+
autoload :Producer, 'firehose/producer' # TODO Move this into the Firehose::Client namespace.
|
12
12
|
autoload :Default, 'firehose/default'
|
13
13
|
autoload :Rack, 'firehose/rack'
|
14
14
|
autoload :CLI, 'firehose/cli'
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def self.logger=(logger)
|
22
|
-
@logger = logger
|
23
|
-
end
|
24
|
-
end
|
15
|
+
autoload :Client, 'firehose/client'
|
16
|
+
autoload :Server, 'firehose/server'
|
17
|
+
autoload :Channel, 'firehose/channel'
|
18
|
+
autoload :SwfPolicyRequest, 'firehose/swf_policy_request'
|
19
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Firehose
|
2
|
+
class Channel
|
3
|
+
attr_reader :channel_key, :redis, :subscriber, :list_key, :sequence_key
|
4
|
+
|
5
|
+
def self.redis
|
6
|
+
@redis ||= EM::Hiredis.connect
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.subscriber
|
10
|
+
@subscriber ||= Subscriber.new(EM::Hiredis.connect)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def initialize(channel_key, redis=self.class.redis, subscriber=self.class.subscriber)
|
15
|
+
@channel_key, @redis, @subscriber = channel_key, redis, subscriber
|
16
|
+
|
17
|
+
@list_key, @sequence_key = key(channel_key, :list), key(channel_key, :sequence)
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_message(last_sequence=nil, options={})
|
21
|
+
last_sequence = last_sequence.to_i
|
22
|
+
|
23
|
+
deferrable = EM::DefaultDeferrable.new
|
24
|
+
# TODO - Think this through a little harder... maybe some tests ol buddy!
|
25
|
+
deferrable.errback {|e| EM.next_tick { raise e } unless [:timeout, :disconnect].include?(e) }
|
26
|
+
|
27
|
+
|
28
|
+
# TODO: Use HSET so we don't have to pull 100 messages back every time.
|
29
|
+
redis.multi
|
30
|
+
redis.get(sequence_key).
|
31
|
+
errback {|e| deferrable.fail e }
|
32
|
+
redis.lrange(list_key, 0, Firehose::Publisher::MAX_MESSAGES).
|
33
|
+
errback {|e| deferrable.fail e }
|
34
|
+
redis.exec.callback do |(sequence, message_list)|
|
35
|
+
Firehose.logger.debug "exec returened: `#{sequence}` and `#{message_list.inspect}`"
|
36
|
+
sequence = sequence.to_i
|
37
|
+
|
38
|
+
if sequence.nil? || (diff = sequence - last_sequence) <= 0
|
39
|
+
Firehose.logger.debug "No message available yet, subscribing. sequence: `#{sequence}`"
|
40
|
+
# Either this resource has never been seen before or we are all caught up.
|
41
|
+
# Subscribe and hope something gets published to this end-point.
|
42
|
+
subscribe(deferrable, options[:timeout])
|
43
|
+
elsif last_sequence > 0 && diff < Firehose::Publisher::MAX_MESSAGES
|
44
|
+
# The client is kinda-sorta running behind, but has a chance to catch
|
45
|
+
# up. Catch them up FTW.
|
46
|
+
# But we won't "catch them up" if last_sequence was zero/nil because
|
47
|
+
# that implies the client is connecting for the 1st time.
|
48
|
+
message = message_list[diff-1]
|
49
|
+
Firehose.logger.debug "Sending old message `#{message}` and sequence `#{sequence}` to client directly. Client is `#{diff}` behind, at `#{last_sequence}`."
|
50
|
+
deferrable.succeed message, last_sequence + 1
|
51
|
+
else
|
52
|
+
# The client is hopelessly behind and underwater. Just reset
|
53
|
+
# their whole world with the lastest message.
|
54
|
+
message = message_list[0]
|
55
|
+
Firehose.logger.debug "Sending latest message `#{message}` and sequence `#{sequence}` to client directly."
|
56
|
+
deferrable.succeed message, sequence
|
57
|
+
end
|
58
|
+
end.errback {|e| deferrable.fail e }
|
59
|
+
|
60
|
+
deferrable
|
61
|
+
end
|
62
|
+
|
63
|
+
def unsubscribe(deferrable)
|
64
|
+
subscriber.unsubscribe channel_key, deferrable
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def key(*segments)
|
69
|
+
segments.unshift(:firehose).join(':')
|
70
|
+
end
|
71
|
+
|
72
|
+
def subscribe(deferrable, timeout=nil)
|
73
|
+
subscriber.subscribe(channel_key, deferrable)
|
74
|
+
if timeout
|
75
|
+
timer = EventMachine::Timer.new(timeout) do
|
76
|
+
deferrable.fail :timeout
|
77
|
+
unsubscribe deferrable
|
78
|
+
end
|
79
|
+
# Cancel the timer if when the deferrable succeeds
|
80
|
+
deferrable.callback { timer.cancel }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/firehose/cli.rb
CHANGED
@@ -1,28 +1,72 @@
|
|
1
1
|
require 'thor'
|
2
|
-
require '
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
# Enable native
|
6
|
+
EM.kqueue if EM.kqueue?
|
7
|
+
EM.epoll if EM.epoll?
|
3
8
|
|
4
9
|
module Firehose
|
5
10
|
class CLI < Thor
|
6
|
-
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
# Disable buffering to $stdio for Firehose.logger
|
14
|
+
$stdout.sync = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "version", "Display the current version."
|
7
18
|
def version
|
8
19
|
puts %[Firehose #{Firehose::VERSION} "#{Firehose::CODENAME}"]
|
9
20
|
end
|
10
21
|
|
11
|
-
desc "server", "
|
12
|
-
method_option :port,
|
13
|
-
method_option :host,
|
14
|
-
|
22
|
+
desc "server", "Start an instance of a server."
|
23
|
+
method_option :port, :type => :numeric, :default => ENV['PORT'] || Firehose::Default::URI.port, :required => false, :aliases => '-p'
|
24
|
+
method_option :host, :type => :string, :default => ENV['HOST'] || Firehose::Default::URI.host, :required => false, :aliases => '-h'
|
25
|
+
method_option :server, :type => :string, :default => ENV['SERVER'] ||'rainbows', :required => false, :aliases => '-s'
|
15
26
|
def server
|
16
|
-
server = Thin::Server.new(options[:host], options[:port]) do
|
17
|
-
run Firehose::Rack::App.new
|
18
|
-
end
|
19
|
-
|
20
27
|
begin
|
21
|
-
|
22
|
-
rescue
|
28
|
+
Firehose::Server.new(options).start
|
29
|
+
rescue => e
|
23
30
|
Firehose.logger.error "#{e.message}: #{e.backtrace}"
|
24
|
-
raise
|
31
|
+
raise e
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "consume URI", "Consume messages from a resource."
|
36
|
+
method_option :concurrency, :type => :numeric, :default => 1, :aliases => '-c'
|
37
|
+
def consume(uri)
|
38
|
+
EM.run do
|
39
|
+
options[:concurrency].times { Firehose::Client::Consumer.parse(uri).request }
|
25
40
|
end
|
26
41
|
end
|
42
|
+
|
43
|
+
desc "publish URI [PAYLOAD]", "Publish messages to a resource."
|
44
|
+
method_option :interval, :type => :numeric, :aliases => '-i'
|
45
|
+
method_option :times, :type => :numeric, :aliases => '-n'
|
46
|
+
def publish(uri, payload=nil)
|
47
|
+
payload ||= $stdin.read
|
48
|
+
client = Firehose::Producer.new(uri)
|
49
|
+
path = URI.parse(uri).path
|
50
|
+
times = options[:times]
|
51
|
+
|
52
|
+
EM.run do
|
53
|
+
# TODO I think this can be cleaned up so the top-level if/else can be ditched.
|
54
|
+
if interval = options[:interval]
|
55
|
+
# Publish messages at a forced interval.
|
56
|
+
EM.add_periodic_timer interval do
|
57
|
+
client.publish(payload).to(path)
|
58
|
+
EM.stop if times && (times-=1).zero?
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# Publish messages as soon as the last message was published.
|
62
|
+
worker = Proc.new do
|
63
|
+
client.publish(payload).to(path)
|
64
|
+
times && (times-=1).zero? ? EM.stop : worker.call
|
65
|
+
end
|
66
|
+
worker.call
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
27
71
|
end
|
28
72
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'em-http'
|
2
|
+
require 'faye/websocket'
|
3
|
+
|
4
|
+
module Firehose
|
5
|
+
# Ruby clients that connect to Firehose to either publish or consume messages.
|
6
|
+
module Client
|
7
|
+
# TODO - Move the Firehose producer.rb file/class in here and rename to Firehose::Client::Producer::Http.new() ..
|
8
|
+
module Producer
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO - Test this libs. I had to throw these quickly into our app so that we could get
|
12
|
+
# some stress testing out of the way.
|
13
|
+
# TODO - Replace the integration test clients with these guys. You'll want to refactor each
|
14
|
+
# transport to use on(:message), on(:conncect), and on(:disconnect) callbacks.
|
15
|
+
module Consumer
|
16
|
+
TransportNotSupportedError = Class.new(RuntimeError)
|
17
|
+
|
18
|
+
# Build up a benchmark client based on a given URI. Accepts ws:// and http:// for now.
|
19
|
+
def self.parse(uri)
|
20
|
+
case transport = URI.parse(uri).scheme
|
21
|
+
when 'ws'
|
22
|
+
Consumer::WebSocket.new(uri)
|
23
|
+
when 'http'
|
24
|
+
Consumer::HttpLongPoll.new(uri)
|
25
|
+
else
|
26
|
+
raise TransportNotSupportedError.new("Transport #{transport.inspect} not supported.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Connect to Firehose via WebSockets and consume messages.
|
31
|
+
class WebSocket
|
32
|
+
attr_reader :url, :logger
|
33
|
+
|
34
|
+
def initialize(url, logger = Firehose.logger)
|
35
|
+
@url, @logger = url, logger
|
36
|
+
end
|
37
|
+
|
38
|
+
def request
|
39
|
+
ws = Faye::WebSocket::Client.new(url)
|
40
|
+
ws.onmessage = lambda do |event|
|
41
|
+
logger.info "WS | #{event.data[0...40].inspect}"
|
42
|
+
end
|
43
|
+
ws.onclose = lambda do |event|
|
44
|
+
logger.info "WS | Closed"
|
45
|
+
end
|
46
|
+
ws.onerror do
|
47
|
+
logger.error "WS | Failed"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Connect to Firehose via HTTP Long Polling and consume messages.
|
53
|
+
class HttpLongPoll
|
54
|
+
JITTER = 0.003
|
55
|
+
|
56
|
+
attr_reader :url, :logger
|
57
|
+
|
58
|
+
def initialize(url, logger = Firehose.logger)
|
59
|
+
@url, @logger = url, logger
|
60
|
+
end
|
61
|
+
|
62
|
+
def request(last_sequence=0)
|
63
|
+
http = EM::HttpRequest.new(url, :inactivity_timeout => 0).get(:query => {'last_message_sequence' => last_sequence})
|
64
|
+
http.callback do
|
65
|
+
case status = http.response_header.status
|
66
|
+
when 200
|
67
|
+
next_sequence = http.response_header['Pragma'].to_i
|
68
|
+
logger.info "HTTP 200 | Next Sequence: #{next_sequence} - #{http.response[0...40].inspect}"
|
69
|
+
EM::add_timer(jitter) { request next_sequence }
|
70
|
+
when 204
|
71
|
+
logger.info "HTTP 204 | Last Sequence #{last_sequence}"
|
72
|
+
EM::add_timer(jitter) { request last_sequence }
|
73
|
+
else
|
74
|
+
logger.error "HTTP #{status} | Failed"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
http.errback do
|
78
|
+
logger.error "Connection Failed"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
# Random jitter between long poll requests.
|
85
|
+
def jitter
|
86
|
+
rand*JITTER
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|