firehose 0.2.alpha.5 → 0.2.alpha.6
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/firehose.gemspec +3 -2
- data/lib/assets/javascripts/firehose/consumer.js.coffee +21 -20
- data/lib/assets/javascripts/firehose/long_poll.js.coffee +95 -56
- data/lib/assets/javascripts/firehose/transport.js.coffee +7 -9
- data/lib/assets/javascripts/firehose/web_socket.js.coffee +34 -11
- data/lib/firehose/rack/consumer_app.rb +9 -6
- data/lib/firehose/rack.rb +1 -1
- data/lib/firehose/version.rb +2 -2
- data/spec/integrations/shared_examples.rb +1 -1
- metadata +52 -36
data/firehose.gemspec
CHANGED
@@ -5,8 +5,8 @@ require "firehose/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "firehose"
|
7
7
|
s.version = Firehose::VERSION
|
8
|
-
s.authors = ["Brad Gessler", "Steel Fu", "Paul Cortens"]
|
9
|
-
s.email = ["brad@polleverywhere.com", "steel@polleverywhere.com", "paul@polleverywhere.com"]
|
8
|
+
s.authors = ["Brad Gessler", "Steel Fu", "Paul Cortens", "Zach Zolton"]
|
9
|
+
s.email = ["brad@polleverywhere.com", "steel@polleverywhere.com", "paul@polleverywhere.com", "zach@polleverywhere.com"]
|
10
10
|
s.homepage = "http://firehose.io/"
|
11
11
|
s.summary = %q{Build realtime Ruby web applications}
|
12
12
|
s.description = %q{Firehose is a realtime web application toolkit for building realtime Ruby web applications.}
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_runtime_dependency "faraday"
|
26
26
|
s.add_runtime_dependency "faye-websocket"
|
27
27
|
s.add_runtime_dependency "em-http-request", "~> 1.0.0"
|
28
|
+
s.add_runtime_dependency "json"
|
28
29
|
|
29
30
|
s.add_development_dependency "rspec"
|
30
31
|
s.add_development_dependency "webmock"
|
@@ -5,6 +5,10 @@ class Firehose.Consumer
|
|
5
5
|
constructor: (config = {}) ->
|
6
6
|
# List of transport stragies we have to use.
|
7
7
|
config.transports ||= Firehose.Consumer.transports
|
8
|
+
unless config.transports.length > 0
|
9
|
+
throw 'You must provide at least one tranport for Firehose.Consumer'
|
10
|
+
unless typeof config.uri is 'string'
|
11
|
+
throw 'You must provide a Firehose server URI for Firehose.Consumer'
|
8
12
|
# Empty handler for messages.
|
9
13
|
config.message ||= ->
|
10
14
|
# Empty handler for error handling.
|
@@ -13,41 +17,38 @@ class Firehose.Consumer
|
|
13
17
|
config.connected ||= ->
|
14
18
|
# Empty handler for when we're disconnected.
|
15
19
|
config.disconnected ||= ->
|
16
|
-
# The initial connection failed. This is probably triggered when a
|
17
|
-
# is supported by the browser, but for whatever
|
20
|
+
# The initial connection failed. This is probably triggered when a
|
21
|
+
# transport, like WebSockets is supported by the browser, but for whatever
|
22
|
+
# reason it can't connect (probably a firewall)
|
18
23
|
config.failed ||= ->
|
19
24
|
throw "Could not connect"
|
20
|
-
# URL that we'll connect to.
|
21
|
-
config.uri ||= undefined
|
22
25
|
# Params that we'll tack on to the URL.
|
23
|
-
config.params ||= {
|
26
|
+
config.params ||= {}
|
24
27
|
# Do stuff before we send the message into config.message. The sensible
|
25
28
|
# default on the webs is to parse JSON.
|
26
|
-
config.parse
|
27
|
-
JSON.parse(body)
|
28
|
-
|
29
|
+
config.parse ||= JSON.parse
|
29
30
|
# Hang on to these config for when we connect.
|
30
31
|
@config = config
|
31
32
|
# Make sure we return ourself out of the constructor so we can chain.
|
32
33
|
this
|
33
34
|
|
34
|
-
connect: =>
|
35
|
+
connect: (delay=0) =>
|
35
36
|
# Get a list of transports that the browser supports
|
36
|
-
supportedTransports = (
|
37
|
+
supportedTransports = (t for t in @config.transports when t.supported())
|
37
38
|
# Mmmkay, we've got transports supported by the browser, now lets try connecting
|
38
39
|
# to them and dealing with failed connections that might be caused by firewalls,
|
39
40
|
# or other network connectivity issues.
|
40
41
|
transports = for transport in supportedTransports
|
41
|
-
|
42
|
-
config = @config
|
42
|
+
originalFailFun = @config.failed
|
43
43
|
# Map the next transport into the existing transports connectionError
|
44
44
|
# If the connection fails, try the next transport supported by the browser.
|
45
|
-
config.failed = =>
|
46
|
-
# Map the next transport to connect
|
47
|
-
if
|
48
|
-
new
|
49
|
-
|
50
|
-
|
51
|
-
new transport(config)
|
45
|
+
@config.failed = =>
|
46
|
+
# Map the next transport to connect inside of the current transport failures
|
47
|
+
if nextTransportType = supportedTransports.pop()
|
48
|
+
nextTransport = new nextTransportType @config
|
49
|
+
nextTransport.connect delay
|
50
|
+
else originalFailFun?()
|
51
|
+
new transport(@config)
|
52
52
|
# Fire off the first connection attempt.
|
53
|
-
|
53
|
+
[firstTransport] = transports
|
54
|
+
firstTransport.connect delay
|
@@ -1,32 +1,33 @@
|
|
1
1
|
class Firehose.LongPoll extends Firehose.Transport
|
2
|
-
messageSequenceHeader: '
|
2
|
+
messageSequenceHeader: 'Pragma'
|
3
|
+
name: -> 'LongPoll'
|
3
4
|
|
4
|
-
# CORS is supported in
|
5
|
-
|
6
|
-
|
5
|
+
# CORS is kinda supported in IE8+ except that its implementation cannot
|
6
|
+
# access "simple request" response headers. This means we don't yet have a
|
7
|
+
# plan to support IE<10 (when it gets a real XHR2 implementation). Sucks...
|
8
|
+
@ieSupported: ->
|
9
|
+
$.browser.msie and parseInt($.browser.version) >= 10
|
7
10
|
|
8
|
-
@supported:
|
11
|
+
@supported: ->
|
9
12
|
# IE 8+, FF 3.5+, Chrome 4+, Safari 4+, Opera 12+, iOS 3.2+, Android 2.1+
|
10
13
|
if xhr = $.ajaxSettings.xhr()
|
11
14
|
"withCredentials" of xhr || Firehose.LongPoll.ieSupported()
|
12
15
|
|
13
16
|
constructor: (args) ->
|
14
17
|
super args
|
15
|
-
|
16
18
|
# Configrations specifically for web sockets
|
17
|
-
@config.longPoll
|
19
|
+
@config.longPoll ||= {}
|
18
20
|
# Protocol schema we should use for talking to WS server.
|
19
|
-
@config.longPoll.url
|
21
|
+
@config.longPoll.url ||= "http:#{@config.uri}"
|
20
22
|
# How many ms should we wait before timing out the AJAX connection?
|
21
23
|
@config.longPoll.timeout ||= 25000
|
22
|
-
|
23
24
|
# TODO - What is @_lagTime for? Can't we just use the @_timeout value?
|
24
25
|
# We use the lag time to make the client live longer than the server.
|
25
|
-
@_lagTime
|
26
|
-
@_timeout
|
27
|
-
@_okInterval
|
28
|
-
|
29
|
-
@
|
26
|
+
@_lagTime = 5000
|
27
|
+
@_timeout = @config.longPoll.timeout + @_lagTime
|
28
|
+
@_okInterval = 0
|
29
|
+
@_isConnected = false
|
30
|
+
@_stopRequestLoop = false
|
30
31
|
|
31
32
|
connect: (delay = 0) =>
|
32
33
|
unless @_isConnected
|
@@ -40,53 +41,35 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
40
41
|
# set any HTTP headers for CORS requests.
|
41
42
|
data = @config.params
|
42
43
|
data.last_message_sequence = @_lastMessageSequence
|
43
|
-
# TODO: Some of these options will be deprecated in
|
44
|
+
# TODO: Some of these options will be deprecated in jQuery 1.8
|
44
45
|
# See: http://api.jquery.com/jQuery.ajax/#jqXHR
|
46
|
+
opts =
|
47
|
+
crossDomain: true
|
48
|
+
data: data
|
49
|
+
timeout: @_timeout
|
50
|
+
success: @_success
|
51
|
+
error: @_error
|
52
|
+
complete: @_xhrComplete
|
53
|
+
opts.xhr = hackAroundFirefoxXhrHeadersBug if $.browser.mozilla
|
54
|
+
$.ajax @config.longPoll.url, opts
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
error: @_error
|
52
|
-
xhr: ->
|
53
|
-
# TODO - This while `xrh` attr is a stupid hack to deal with CORS short-comings in jQuery in Firefox.
|
54
|
-
# This ticket can be viewed at http://bugs.jquery.com/ticket/10338. Once jQuery is
|
55
|
-
# upgraded to this version, we can probably remove this, but be sure you test the
|
56
|
-
# crap out of Firefox!
|
57
|
-
#
|
58
|
-
# Its also worth noting that I had to localize this monkey-patch to the Firehose.LongPoll
|
59
|
-
# consumer because a previous global patch on jQuery.ajaxSettings.xhr was breaking regular IE7
|
60
|
-
# loading. I figured its better to localize this anyway to solve that problem and loading order issues.
|
61
|
-
xhr = jQuery.ajaxSettings.xhr()
|
62
|
-
getAllResponseHeaders = xhr.getAllResponseHeaders
|
63
|
-
xhr.getAllResponseHeaders = ->
|
64
|
-
allHeaders = getAllResponseHeaders.call(xhr)
|
65
|
-
return allHeaders if allHeaders
|
66
|
-
allHeaders = ""
|
67
|
-
for headerName in [ "Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma" ]
|
68
|
-
do (headerName) ->
|
69
|
-
allHeaders += headerName + ": " + xhr.getResponseHeader(headerName) + "\n" if xhr.getResponseHeader(headerName)
|
70
|
-
allHeaders
|
71
|
-
xhr
|
56
|
+
_xhrComplete: (jqXhr) =>
|
57
|
+
# Get the last sequence from the server if specified.
|
58
|
+
if jqXhr.status is 200
|
59
|
+
val = jqXhr.getResponseHeader @messageSequenceHeader
|
60
|
+
@_lastMessageSequence = val if val?
|
72
61
|
|
73
|
-
|
74
|
-
|
75
|
-
if jqXhr.status == 200
|
76
|
-
@_lastMessageSequence = jqXhr.getResponseHeader(@messageSequenceHeader)
|
77
|
-
if @_lastMessageSequence == null
|
78
|
-
console.log 'ERROR: Unable to get last message sequnce from header'
|
62
|
+
stop: =>
|
63
|
+
@_stopRequestLoop = true
|
79
64
|
|
80
65
|
_success: (data, status, jqXhr) =>
|
81
|
-
|
82
|
-
|
83
|
-
# Call the 'connected' callback if the connection succeeds.
|
84
|
-
@_open(data) unless @_succeeded
|
66
|
+
@_open data unless @_succeeded
|
67
|
+
return if @_stopRequestLoop
|
85
68
|
if jqXhr.status == 204
|
86
69
|
# If we get a 204 back, that means the server timed-out and sent back a 204 with a
|
87
70
|
# X-Http-Next-Request header
|
88
71
|
#
|
89
|
-
# Why did we use a 204 and not a 408? Because
|
72
|
+
# Why did we use a 204 and not a 408? Because Firefox is really stupid about 400 level error
|
90
73
|
# codes and would claims its a 0 error code, which we use for something else. Firefox is IE
|
91
74
|
# in this case
|
92
75
|
@connect(@_okInterval)
|
@@ -109,9 +92,65 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
109
92
|
_error: (jqXhr, status, error) =>
|
110
93
|
@_isConnected = false
|
111
94
|
@config.disconnected()
|
95
|
+
unless @_stopRequestLoop
|
96
|
+
# Ping the server to make sure this isn't a network connectivity error
|
97
|
+
setTimeout @_ping, @_retryDelay + @_lagTime
|
98
|
+
# Reconnect with delay
|
99
|
+
setTimeout @_request, @_retryDelay
|
100
|
+
|
101
|
+
# NB: This is a stupid hack to deal with CORS short-comings in jQuery in
|
102
|
+
# Firefox. There is a ticket for this: http://bugs.jquery.com/ticket/10338
|
103
|
+
# Once jQuery is upgraded to this version we can probably remove this, but be
|
104
|
+
# sure you test the crap out of Firefox!
|
105
|
+
# Its also worth noting that I had to localize this monkey-patch to the
|
106
|
+
# Firehose.LongPoll consumer because a previous global patch on
|
107
|
+
# jQuery.ajaxSettings.xhr was breaking regular IE7 loading. Better to localize
|
108
|
+
# this anyway to solve that problem and loading order issues.
|
109
|
+
hackAroundFirefoxXhrHeadersBug = ->
|
110
|
+
XHR_HEADERS = [
|
111
|
+
"Cache-Control", "Content-Language", "Content-Type"
|
112
|
+
"Expires", "Last-Modified", "Pragma"
|
113
|
+
]
|
114
|
+
xhr = jQuery.ajaxSettings.xhr()
|
115
|
+
originalFun = xhr.getAllResponseHeaders
|
116
|
+
xhr.getAllResponseHeaders = ->
|
117
|
+
return allHeaders if allHeaders = originalFun.call xhr
|
118
|
+
lines = for name in XHR_HEADERS when xhr.getResponseHeader(name)?
|
119
|
+
"#{name}: #{xhr.getResponseHeader name}"
|
120
|
+
lines.join '\n'
|
121
|
+
xhr
|
112
122
|
|
113
|
-
|
114
|
-
|
123
|
+
# NB: Leaving this here for now. It does work, but won't help us since the XDR
|
124
|
+
# object cannot access any response headers, which Firehose relies on.
|
115
125
|
|
116
|
-
|
117
|
-
|
126
|
+
# # Let's try to hack in support for IE8+ via the XDomainRequest object!
|
127
|
+
# # This was adapted from code shamelessly stolen from:
|
128
|
+
# # https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js
|
129
|
+
# if $.browser.msie and parseInt($.browser.version, 10) in [8, 9]
|
130
|
+
# jQuery.ajaxTransport (s) ->
|
131
|
+
# if s.crossDomain and s.async
|
132
|
+
# if s.timeout
|
133
|
+
# s.xdrTimeout = s.timeout
|
134
|
+
# delete s.timeout
|
135
|
+
# xdr = undefined
|
136
|
+
# return {
|
137
|
+
# send: (_, complete) ->
|
138
|
+
# callback = (status, statusText, responses, responseHeaders) ->
|
139
|
+
# xdr.onload = xdr.onerror = xdr.ontimeout = jQuery.noop
|
140
|
+
# xdr = undefined
|
141
|
+
# complete status, statusText, responses, responseHeaders
|
142
|
+
# xdr = new XDomainRequest()
|
143
|
+
# xdr.open s.type, s.url
|
144
|
+
# xdr.onload = ->
|
145
|
+
# headers = "Content-Type: #{xdr.contentType}"
|
146
|
+
# callback 200, "OK", {text: xdr.responseText}, headers
|
147
|
+
# xdr.onerror = -> callback 404, "Not Found"
|
148
|
+
# if s.xdrTimeout?
|
149
|
+
# xdr.ontimeout = -> callback 0, "timeout"
|
150
|
+
# xdr.timeout = s.xdrTimeout
|
151
|
+
# xdr.send (s.hasContent and s.data) or null
|
152
|
+
# abort: ->
|
153
|
+
# if xdr?
|
154
|
+
# xdr.onerror = jQuery.noop()
|
155
|
+
# xdr.abort()
|
156
|
+
# }
|
@@ -11,23 +11,21 @@ class Firehose.Transport
|
|
11
11
|
|
12
12
|
# Lets rock'n'roll! Connect to the server.
|
13
13
|
connect: (delay = 0) =>
|
14
|
-
setTimeout
|
15
|
-
@_request()
|
16
|
-
, delay
|
14
|
+
setTimeout @_request, delay
|
17
15
|
this
|
18
16
|
|
19
|
-
#
|
20
|
-
|
17
|
+
# Hey subclasses:
|
18
|
+
name: -> throw 'not implemented in base Transport' # implement this to identify transport type
|
19
|
+
stop: -> throw 'not implemented in base Transport' # implement this to stop receiving messages
|
20
|
+
_request: -> throw 'not implemented in base Transport' # implement this to handle requests
|
21
21
|
|
22
22
|
# Default error handler
|
23
23
|
_error: (event) =>
|
24
|
-
|
25
|
-
# Fail peremantly if the error happens on the first connection.
|
26
|
-
@config.failed(this)
|
27
|
-
else
|
24
|
+
if @_succeeded
|
28
25
|
# Lets try to connect again with delay
|
29
26
|
@config.disconnected()
|
30
27
|
@connect(@_retryDelay)
|
28
|
+
else @config.failed @
|
31
29
|
|
32
30
|
# Default connection established handler
|
33
31
|
_open: (event) =>
|
@@ -3,6 +3,8 @@
|
|
3
3
|
window.WEB_SOCKET_SWF_LOCATION = '/assets/firehose/WebSocketMain.swf' if !window.WEB_SOCKET_SWF_LOCATION
|
4
4
|
|
5
5
|
class Firehose.WebSocket extends Firehose.Transport
|
6
|
+
name: -> 'WebSocket'
|
7
|
+
|
6
8
|
@supported: =>
|
7
9
|
# Compatibility reference: http://caniuse.com/websockets
|
8
10
|
# We don't need to explicitly check for Flash web socket or MozWebSocket
|
@@ -18,11 +20,31 @@ class Firehose.WebSocket extends Firehose.Transport
|
|
18
20
|
@config.webSocket.url ||= "ws:#{@config.uri}?#{$.param(@config.params)}"
|
19
21
|
|
20
22
|
_request: =>
|
21
|
-
@socket = new window.WebSocket
|
22
|
-
@socket.onopen
|
23
|
-
@socket.onclose
|
24
|
-
@socket.onerror
|
25
|
-
@socket.onmessage = @
|
23
|
+
@socket = new window.WebSocket @config.webSocket.url
|
24
|
+
@socket.onopen = @_open
|
25
|
+
@socket.onclose = @_close
|
26
|
+
@socket.onerror = @_error
|
27
|
+
@socket.onmessage = @_waitForPong
|
28
|
+
|
29
|
+
stop: =>
|
30
|
+
@cleanUp()
|
31
|
+
|
32
|
+
_open: =>
|
33
|
+
# TODO: include JSON client-side script for less awesome browsers
|
34
|
+
@socket.send JSON.stringify ping: 'PING'
|
35
|
+
# TODO: consider making this timeout configurable somehow...
|
36
|
+
@pingTimeout = setTimeout @_error, 2000
|
37
|
+
|
38
|
+
_waitForPong: (event) =>
|
39
|
+
o = try JSON.parse event.data catch e then {}
|
40
|
+
if o.pong is 'PONG'
|
41
|
+
# Not quite sure why this doesn't work in IE8:
|
42
|
+
# (Throws "TypeError: Array or arguments object expected")
|
43
|
+
# Firehose.Transport::_open.apply @, event
|
44
|
+
@_succeeded = true
|
45
|
+
@config.connected @
|
46
|
+
clearTimeout @pingTimeout
|
47
|
+
@socket.onmessage = @_message
|
26
48
|
|
27
49
|
_message: (event) =>
|
28
50
|
@config.message(@config.parse(event.data))
|
@@ -34,13 +56,14 @@ class Firehose.WebSocket extends Firehose.Transport
|
|
34
56
|
@_error(event)
|
35
57
|
|
36
58
|
_error: (event) =>
|
37
|
-
|
59
|
+
@cleanUp()
|
60
|
+
super
|
61
|
+
|
62
|
+
cleanUp: ->
|
38
63
|
if @socket
|
39
|
-
@socket.onopen
|
40
|
-
@socket.onclose
|
41
|
-
@socket.onerror
|
64
|
+
@socket.onopen = null
|
65
|
+
@socket.onclose = null
|
66
|
+
@socket.onerror = null
|
42
67
|
@socket.onmessage = null
|
43
68
|
@socket.close()
|
44
69
|
delete(@socket)
|
45
|
-
|
46
|
-
super
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'faye/websocket'
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module Firehose
|
4
5
|
module Rack
|
@@ -47,7 +48,8 @@ module Firehose
|
|
47
48
|
env['async.callback'].call response(400, "Header '#{LAST_MESSAGE_SEQUENCE_HEADER}' may not be less than zero", response_headers(env))
|
48
49
|
else
|
49
50
|
Channel.new(path).next_message(last_sequence, :timeout => TIMEOUT).callback do |message, sequence|
|
50
|
-
|
51
|
+
combined_headers = response_headers(env).merge(LAST_MESSAGE_SEQUENCE_HEADER => sequence.to_s)
|
52
|
+
env['async.callback'].call response(200, message, combined_headers)
|
51
53
|
end.errback do |e|
|
52
54
|
if e == :timeout
|
53
55
|
env['async.callback'].call response(204, '', response_headers(env))
|
@@ -84,8 +86,8 @@ module Firehose
|
|
84
86
|
def cors_headers(env)
|
85
87
|
# TODO seperate out CORS logic as an async middleware with a Goliath web server.
|
86
88
|
{
|
87
|
-
'Access-Control-Allow-Origin'
|
88
|
-
'Access-Control-Expose-Headers'
|
89
|
+
'Access-Control-Allow-Origin' => cors_origin(env),
|
90
|
+
'Access-Control-Expose-Headers' => LAST_MESSAGE_SEQUENCE_HEADER
|
89
91
|
}
|
90
92
|
end
|
91
93
|
end
|
@@ -117,9 +119,10 @@ module Firehose
|
|
117
119
|
subscribe.call nil
|
118
120
|
end
|
119
121
|
|
120
|
-
|
121
|
-
|
122
|
-
|
122
|
+
ws.onmessage = lambda do |event|
|
123
|
+
o = JSON.parse(event.data, :symbolize_names => true) rescue {}
|
124
|
+
ws.send(JSON.generate(:pong => 'PONG')) if o[:ping] == 'PING'
|
125
|
+
end
|
123
126
|
|
124
127
|
ws.onclose = lambda do |event|
|
125
128
|
if @deferrable
|
data/lib/firehose/rack.rb
CHANGED
@@ -10,7 +10,7 @@ module Firehose
|
|
10
10
|
# Normally we'd want to use a custom header to reduce the likelihood of some
|
11
11
|
# HTTP middleware clobbering the value. But Safari seems to ignore our CORS
|
12
12
|
# header instructions, so we are using 'pragma' because it is always allowed.
|
13
|
-
LAST_MESSAGE_SEQUENCE_HEADER = '
|
13
|
+
LAST_MESSAGE_SEQUENCE_HEADER = 'Pragma'
|
14
14
|
RACK_LAST_MESSAGE_SEQUENCE_HEADER = "HTTP_#{LAST_MESSAGE_SEQUENCE_HEADER.upcase.gsub('-', '_')}"
|
15
15
|
# Don't cache in development mode
|
16
16
|
CORS_OPTIONS_MAX_AGE = ENV['RACK_ENV'] == 'development' ? '1' : '1728000'
|
data/lib/firehose/version.rb
CHANGED
metadata
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firehose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.alpha.
|
4
|
+
version: 0.2.alpha.6
|
5
5
|
prerelease: 4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Brad Gessler
|
9
9
|
- Steel Fu
|
10
10
|
- Paul Cortens
|
11
|
+
- Zach Zolton
|
11
12
|
autorequire:
|
12
13
|
bindir: bin
|
13
14
|
cert_chain: []
|
14
|
-
date: 2012-08-
|
15
|
+
date: 2012-08-28 00:00:00.000000000 Z
|
15
16
|
dependencies:
|
16
17
|
- !ruby/object:Gem::Dependency
|
17
18
|
name: eventmachine
|
18
|
-
requirement: &
|
19
|
+
requirement: &70256291491020 !ruby/object:Gem::Requirement
|
19
20
|
none: false
|
20
21
|
requirements:
|
21
22
|
- - ! '>='
|
@@ -23,10 +24,10 @@ dependencies:
|
|
23
24
|
version: 1.0.0.rc
|
24
25
|
type: :runtime
|
25
26
|
prerelease: false
|
26
|
-
version_requirements: *
|
27
|
+
version_requirements: *70256291491020
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: em-hiredis
|
29
|
-
requirement: &
|
30
|
+
requirement: &70256291490580 !ruby/object:Gem::Requirement
|
30
31
|
none: false
|
31
32
|
requirements:
|
32
33
|
- - ! '>='
|
@@ -34,10 +35,10 @@ dependencies:
|
|
34
35
|
version: '0'
|
35
36
|
type: :runtime
|
36
37
|
prerelease: false
|
37
|
-
version_requirements: *
|
38
|
+
version_requirements: *70256291490580
|
38
39
|
- !ruby/object:Gem::Dependency
|
39
40
|
name: thor
|
40
|
-
requirement: &
|
41
|
+
requirement: &70256291490080 !ruby/object:Gem::Requirement
|
41
42
|
none: false
|
42
43
|
requirements:
|
43
44
|
- - ! '>='
|
@@ -45,10 +46,10 @@ dependencies:
|
|
45
46
|
version: '0'
|
46
47
|
type: :runtime
|
47
48
|
prerelease: false
|
48
|
-
version_requirements: *
|
49
|
+
version_requirements: *70256291490080
|
49
50
|
- !ruby/object:Gem::Dependency
|
50
51
|
name: faraday
|
51
|
-
requirement: &
|
52
|
+
requirement: &70256291489660 !ruby/object:Gem::Requirement
|
52
53
|
none: false
|
53
54
|
requirements:
|
54
55
|
- - ! '>='
|
@@ -56,10 +57,10 @@ dependencies:
|
|
56
57
|
version: '0'
|
57
58
|
type: :runtime
|
58
59
|
prerelease: false
|
59
|
-
version_requirements: *
|
60
|
+
version_requirements: *70256291489660
|
60
61
|
- !ruby/object:Gem::Dependency
|
61
62
|
name: faye-websocket
|
62
|
-
requirement: &
|
63
|
+
requirement: &70256291489240 !ruby/object:Gem::Requirement
|
63
64
|
none: false
|
64
65
|
requirements:
|
65
66
|
- - ! '>='
|
@@ -67,10 +68,10 @@ dependencies:
|
|
67
68
|
version: '0'
|
68
69
|
type: :runtime
|
69
70
|
prerelease: false
|
70
|
-
version_requirements: *
|
71
|
+
version_requirements: *70256291489240
|
71
72
|
- !ruby/object:Gem::Dependency
|
72
73
|
name: em-http-request
|
73
|
-
requirement: &
|
74
|
+
requirement: &70256291488740 !ruby/object:Gem::Requirement
|
74
75
|
none: false
|
75
76
|
requirements:
|
76
77
|
- - ~>
|
@@ -78,10 +79,21 @@ dependencies:
|
|
78
79
|
version: 1.0.0
|
79
80
|
type: :runtime
|
80
81
|
prerelease: false
|
81
|
-
version_requirements: *
|
82
|
+
version_requirements: *70256291488740
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: &70256291488320 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: *70256291488320
|
82
94
|
- !ruby/object:Gem::Dependency
|
83
95
|
name: rspec
|
84
|
-
requirement: &
|
96
|
+
requirement: &70256291487860 !ruby/object:Gem::Requirement
|
85
97
|
none: false
|
86
98
|
requirements:
|
87
99
|
- - ! '>='
|
@@ -89,10 +101,10 @@ dependencies:
|
|
89
101
|
version: '0'
|
90
102
|
type: :development
|
91
103
|
prerelease: false
|
92
|
-
version_requirements: *
|
104
|
+
version_requirements: *70256291487860
|
93
105
|
- !ruby/object:Gem::Dependency
|
94
106
|
name: webmock
|
95
|
-
requirement: &
|
107
|
+
requirement: &70256291459520 !ruby/object:Gem::Requirement
|
96
108
|
none: false
|
97
109
|
requirements:
|
98
110
|
- - ! '>='
|
@@ -100,10 +112,10 @@ dependencies:
|
|
100
112
|
version: '0'
|
101
113
|
type: :development
|
102
114
|
prerelease: false
|
103
|
-
version_requirements: *
|
115
|
+
version_requirements: *70256291459520
|
104
116
|
- !ruby/object:Gem::Dependency
|
105
117
|
name: guard-rspec
|
106
|
-
requirement: &
|
118
|
+
requirement: &70256291459080 !ruby/object:Gem::Requirement
|
107
119
|
none: false
|
108
120
|
requirements:
|
109
121
|
- - ! '>='
|
@@ -111,10 +123,10 @@ dependencies:
|
|
111
123
|
version: '0'
|
112
124
|
type: :development
|
113
125
|
prerelease: false
|
114
|
-
version_requirements: *
|
126
|
+
version_requirements: *70256291459080
|
115
127
|
- !ruby/object:Gem::Dependency
|
116
128
|
name: guard-bundler
|
117
|
-
requirement: &
|
129
|
+
requirement: &70256291458660 !ruby/object:Gem::Requirement
|
118
130
|
none: false
|
119
131
|
requirements:
|
120
132
|
- - ! '>='
|
@@ -122,10 +134,10 @@ dependencies:
|
|
122
134
|
version: '0'
|
123
135
|
type: :development
|
124
136
|
prerelease: false
|
125
|
-
version_requirements: *
|
137
|
+
version_requirements: *70256291458660
|
126
138
|
- !ruby/object:Gem::Dependency
|
127
139
|
name: guard-coffeescript
|
128
|
-
requirement: &
|
140
|
+
requirement: &70256291458220 !ruby/object:Gem::Requirement
|
129
141
|
none: false
|
130
142
|
requirements:
|
131
143
|
- - ! '>='
|
@@ -133,10 +145,10 @@ dependencies:
|
|
133
145
|
version: '0'
|
134
146
|
type: :development
|
135
147
|
prerelease: false
|
136
|
-
version_requirements: *
|
148
|
+
version_requirements: *70256291458220
|
137
149
|
- !ruby/object:Gem::Dependency
|
138
150
|
name: rainbows
|
139
|
-
requirement: &
|
151
|
+
requirement: &70256291457800 !ruby/object:Gem::Requirement
|
140
152
|
none: false
|
141
153
|
requirements:
|
142
154
|
- - ! '>='
|
@@ -144,10 +156,10 @@ dependencies:
|
|
144
156
|
version: '0'
|
145
157
|
type: :development
|
146
158
|
prerelease: false
|
147
|
-
version_requirements: *
|
159
|
+
version_requirements: *70256291457800
|
148
160
|
- !ruby/object:Gem::Dependency
|
149
161
|
name: thin
|
150
|
-
requirement: &
|
162
|
+
requirement: &70256291457380 !ruby/object:Gem::Requirement
|
151
163
|
none: false
|
152
164
|
requirements:
|
153
165
|
- - ! '>='
|
@@ -155,10 +167,10 @@ dependencies:
|
|
155
167
|
version: '0'
|
156
168
|
type: :development
|
157
169
|
prerelease: false
|
158
|
-
version_requirements: *
|
170
|
+
version_requirements: *70256291457380
|
159
171
|
- !ruby/object:Gem::Dependency
|
160
172
|
name: rack-test
|
161
|
-
requirement: &
|
173
|
+
requirement: &70256291456960 !ruby/object:Gem::Requirement
|
162
174
|
none: false
|
163
175
|
requirements:
|
164
176
|
- - ! '>='
|
@@ -166,10 +178,10 @@ dependencies:
|
|
166
178
|
version: '0'
|
167
179
|
type: :development
|
168
180
|
prerelease: false
|
169
|
-
version_requirements: *
|
181
|
+
version_requirements: *70256291456960
|
170
182
|
- !ruby/object:Gem::Dependency
|
171
183
|
name: async_rack_test
|
172
|
-
requirement: &
|
184
|
+
requirement: &70256291456520 !ruby/object:Gem::Requirement
|
173
185
|
none: false
|
174
186
|
requirements:
|
175
187
|
- - ! '>='
|
@@ -177,10 +189,10 @@ dependencies:
|
|
177
189
|
version: '0'
|
178
190
|
type: :development
|
179
191
|
prerelease: false
|
180
|
-
version_requirements: *
|
192
|
+
version_requirements: *70256291456520
|
181
193
|
- !ruby/object:Gem::Dependency
|
182
194
|
name: foreman
|
183
|
-
requirement: &
|
195
|
+
requirement: &70256291456040 !ruby/object:Gem::Requirement
|
184
196
|
none: false
|
185
197
|
requirements:
|
186
198
|
- - ! '>='
|
@@ -188,10 +200,10 @@ dependencies:
|
|
188
200
|
version: '0'
|
189
201
|
type: :development
|
190
202
|
prerelease: false
|
191
|
-
version_requirements: *
|
203
|
+
version_requirements: *70256291456040
|
192
204
|
- !ruby/object:Gem::Dependency
|
193
205
|
name: sprockets
|
194
|
-
requirement: &
|
206
|
+
requirement: &70256291455540 !ruby/object:Gem::Requirement
|
195
207
|
none: false
|
196
208
|
requirements:
|
197
209
|
- - ! '>='
|
@@ -199,13 +211,14 @@ dependencies:
|
|
199
211
|
version: '0'
|
200
212
|
type: :development
|
201
213
|
prerelease: false
|
202
|
-
version_requirements: *
|
214
|
+
version_requirements: *70256291455540
|
203
215
|
description: Firehose is a realtime web application toolkit for building realtime
|
204
216
|
Ruby web applications.
|
205
217
|
email:
|
206
218
|
- brad@polleverywhere.com
|
207
219
|
- steel@polleverywhere.com
|
208
220
|
- paul@polleverywhere.com
|
221
|
+
- zach@polleverywhere.com
|
209
222
|
executables:
|
210
223
|
- firehose
|
211
224
|
extensions: []
|
@@ -282,6 +295,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
282
295
|
- - ! '>='
|
283
296
|
- !ruby/object:Gem::Version
|
284
297
|
version: '0'
|
298
|
+
segments:
|
299
|
+
- 0
|
300
|
+
hash: 1005777279219714638
|
285
301
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
286
302
|
none: false
|
287
303
|
requirements:
|