firehose 0.0.9 → 0.0.10
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/.rspec +1 -1
- data/README.md +2 -2
- data/firehose.gemspec +2 -1
- data/lib/assets/javascripts/firehose.js.coffee +1 -1
- data/lib/assets/javascripts/firehose/consumer.js.coffee +61 -0
- data/lib/assets/javascripts/firehose/long_poll.js.coffee +9 -1
- data/lib/assets/javascripts/firehose/transport.js.coffee +8 -3
- data/lib/assets/javascripts/firehose/web_socket.js.coffee +1 -1
- data/lib/firehose/rack.rb +9 -1
- data/lib/firehose/version.rb +1 -1
- metadata +37 -26
- data/lib/assets/javascripts/firehose/client.js.coffee +0 -45
data/.rspec
CHANGED
@@ -1 +1 @@
|
|
1
|
-
--colour
|
1
|
+
--colour
|
data/README.md
CHANGED
@@ -65,14 +65,14 @@ You have a dirt simple HTTP pub-sub feed. You could setup an `after_commit` hook
|
|
65
65
|
|
66
66
|
Holy mackerel! Its a nice, clean, RESTful way to build real-time web applications.
|
67
67
|
|
68
|
-
# The JavaScript
|
68
|
+
# The JavaScript Consumer
|
69
69
|
|
70
70
|
Firehose doesn't just stop at curl; it has a full-featured JavaScript client that lets you subscribe to channels for live updates.
|
71
71
|
|
72
72
|
Still have the server running? Copy and paste the code below into Firebug or the WebKit console.
|
73
73
|
|
74
74
|
```javascript
|
75
|
-
new Firehose.
|
75
|
+
new Firehose.Consumer({
|
76
76
|
message: function(msg){
|
77
77
|
console.log(msg);
|
78
78
|
},
|
data/firehose.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = Firehose::VERSION
|
8
8
|
s.authors = ["Brad Gessler", "Steel Fu"]
|
9
9
|
s.email = ["brad@polleverywhere.com", "steel@polleverywhere.com"]
|
10
|
-
s.homepage = "http://
|
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.}
|
13
13
|
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_runtime_dependency "thin"
|
25
25
|
s.add_runtime_dependency "thor"
|
26
26
|
s.add_runtime_dependency "websocket-rack"
|
27
|
+
s.add_runtime_dependency "faraday"
|
27
28
|
|
28
29
|
s.add_development_dependency "rspec"
|
29
30
|
s.add_development_dependency "rack-test"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Firehose.Consumer
|
2
|
+
# Transports that are available to Firehose.
|
3
|
+
@transports: [Firehose.WebSocket, Firehose.LongPoll]
|
4
|
+
|
5
|
+
# Generate a random consumer id.
|
6
|
+
@nextConsumerId: ->
|
7
|
+
Math.floor((Math.random()*99999999999)+1)
|
8
|
+
|
9
|
+
constructor: (config = {}) ->
|
10
|
+
# The consumerId is used by the server to remember messages between requests. In a production environment,
|
11
|
+
# this should probably be some combination of "user_id-rand". Why the rand? Because a user may have multiple
|
12
|
+
# tabs open to the application, and each tab needs a different channel on the server.
|
13
|
+
config.consumerId ||= Firehose.Consumer.nextConsumerId()
|
14
|
+
# List of transport stragies we have to use.
|
15
|
+
config.transports ||= Firehose.Consumer.transports
|
16
|
+
# Empty handler for messages.
|
17
|
+
config.message ||= ->
|
18
|
+
# Empty handler for error handling.
|
19
|
+
config.error ||= ->
|
20
|
+
# Empty handler for when we establish a connection.
|
21
|
+
config.connected ||= ->
|
22
|
+
# Empty handler for when we're disconnected.
|
23
|
+
config.disconnected ||= ->
|
24
|
+
# The initial connection failed. This is probably triggered when a transport, like WebSockets
|
25
|
+
# is supported by the browser, but for whatever reason it can't connect (probably a firewall)
|
26
|
+
config.failed ||= ->
|
27
|
+
throw "Could not connect"
|
28
|
+
# URL that we'll connect to.
|
29
|
+
config.uri ||= undefined
|
30
|
+
# Params that we'll tack on to the URL. We include a consumerId in here for kicks.
|
31
|
+
config.params ||= { cid: config.consumerId }
|
32
|
+
# Do stuff before we send the message into config.message. The sensible
|
33
|
+
# default on the webs is to parse JSON.
|
34
|
+
config.parse ||= (body) ->
|
35
|
+
$.parseJSON(body)
|
36
|
+
|
37
|
+
# Hang on to these config for when we connect.
|
38
|
+
@config = config
|
39
|
+
# Make sure we return ourself out of the constructor so we can chain.
|
40
|
+
this
|
41
|
+
|
42
|
+
connect: =>
|
43
|
+
# Get a list of transports that the browser supports
|
44
|
+
supportedTransports = (transport for transport in @config.transports when transport.supported())
|
45
|
+
# Mmmkay, we've got transports supported by the browser, now lets try connecting
|
46
|
+
# to them and dealing with failed connections that might be caused by firewalls,
|
47
|
+
# or other network connectivity issues.
|
48
|
+
transports = for transport in supportedTransports
|
49
|
+
# Copy the config so we can modify it with a failed callback.
|
50
|
+
config = @config
|
51
|
+
# Map the next transport into the existing transports connectionError
|
52
|
+
# If the connection fails, try the next transport supported by the browser.
|
53
|
+
config.failed = =>
|
54
|
+
# Map the next transport to connect insie of the current transport failures
|
55
|
+
if nextTransport = supportedTransports.pop()
|
56
|
+
new nextTransport(config).connect()
|
57
|
+
else
|
58
|
+
@config.failed() # Call the original fail method passed into the Firehose.Consumer
|
59
|
+
new transport(config)
|
60
|
+
# Fire off the first connection attempt.
|
61
|
+
transports[0].connect()
|
@@ -14,10 +14,14 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
14
14
|
@config.longPoll ||= {}
|
15
15
|
# Protocol schema we should use for talking to WS server.
|
16
16
|
@config.longPoll.url ||= "http:#{@config.uri}"
|
17
|
+
# How many ms should we wait before timing out the AJAX connection?
|
18
|
+
# TODO why was this set at 0s?
|
19
|
+
@config.longPoll.timeout ||= 0
|
17
20
|
|
21
|
+
# TODO - What is @_lagTime for? Can't we just use the @_timeout value?
|
18
22
|
# We use the lag time to make the client live longer than the server.
|
19
23
|
@_lagTime = 5000
|
20
|
-
@_timeout = @config.
|
24
|
+
@_timeout = @config.longPoll.timeout + @_lagTime
|
21
25
|
@_offlineTimer
|
22
26
|
@_okInterval = 0
|
23
27
|
|
@@ -63,6 +67,10 @@ class Firehose.LongPoll extends Firehose.Transport
|
|
63
67
|
error: @_error
|
64
68
|
|
65
69
|
_success: (data, status, jqXhr) =>
|
70
|
+
# TODO we actually want to do this when the thing calls out... mmm right now it takes
|
71
|
+
# up to 30s before we can call this thing.
|
72
|
+
# Call the 'connected' callback if the connection succeeds.
|
73
|
+
@_open(data) unless @_succeeded
|
66
74
|
if jqXhr.status == 204
|
67
75
|
# If we get a 204 back, that means the server timed-out and sent back a 204 with a
|
68
76
|
# X-Http-Next-Request header
|
@@ -21,12 +21,17 @@ class Firehose.Transport
|
|
21
21
|
|
22
22
|
# Default error handler
|
23
23
|
_error: (event) =>
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
unless @_succeeded
|
25
|
+
# Fail peremantly if the error happens on the first connection.
|
26
|
+
@config.failed(this)
|
27
|
+
else
|
28
|
+
# Lets try to connect again with delay
|
29
|
+
@config.disconnected()
|
30
|
+
@connect(@_retryDelay)
|
27
31
|
|
28
32
|
# Default connection established handler
|
29
33
|
_open: (event) =>
|
34
|
+
@_succeeded = true
|
30
35
|
@config.connected()
|
31
36
|
|
32
37
|
# Default connection closed handler
|
@@ -5,7 +5,7 @@ class Firehose.WebSocket extends Firehose.Transport
|
|
5
5
|
@supported: =>
|
6
6
|
# Compatibility reference: http://caniuse.com/websockets
|
7
7
|
# Native websocket support + Flash web socket
|
8
|
-
window.WebSocket || (window["MozWebSocket"] and window.MozWebSocket) || WebSocket.flashSupported()
|
8
|
+
!!(window.WebSocket || (window["MozWebSocket"] and window.MozWebSocket) || WebSocket.flashSupported())
|
9
9
|
|
10
10
|
constructor: (args) ->
|
11
11
|
super args
|
data/lib/firehose/rack.rb
CHANGED
@@ -95,10 +95,18 @@ module Firehose
|
|
95
95
|
|
96
96
|
class App
|
97
97
|
def call(env)
|
98
|
-
websocket_request?(env) ?
|
98
|
+
websocket_request?(env) ? websocket.call(env) : http_long_poll.call(env)
|
99
99
|
end
|
100
100
|
|
101
101
|
private
|
102
|
+
def websocket
|
103
|
+
@websocket ||= WebSocket.new
|
104
|
+
end
|
105
|
+
|
106
|
+
def http_long_poll
|
107
|
+
@http_long_poll ||= HttpLongPoll.new
|
108
|
+
end
|
109
|
+
|
102
110
|
def websocket_request?(env)
|
103
111
|
env['HTTP_UPGRADE'] =~ /websocket/i
|
104
112
|
end
|
data/lib/firehose/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firehose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-04-
|
13
|
+
date: 2012-04-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: eventmachine
|
17
|
-
requirement: &
|
17
|
+
requirement: &70248892020200 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 1.0.0.beta
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70248892020200
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: amqp
|
28
|
-
requirement: &
|
28
|
+
requirement: &70248892017640 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 0.9.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70248892017640
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: thin
|
39
|
-
requirement: &
|
39
|
+
requirement: &70248892031220 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70248892031220
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: thor
|
50
|
-
requirement: &
|
50
|
+
requirement: &70248892024520 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70248892024520
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: websocket-rack
|
61
|
-
requirement: &
|
61
|
+
requirement: &70248892039500 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,21 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :runtime
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70248892039500
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: faraday
|
72
|
+
requirement: &70248892037240 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :runtime
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *70248892037240
|
70
81
|
- !ruby/object:Gem::Dependency
|
71
82
|
name: rspec
|
72
|
-
requirement: &
|
83
|
+
requirement: &70248892032840 !ruby/object:Gem::Requirement
|
73
84
|
none: false
|
74
85
|
requirements:
|
75
86
|
- - ! '>='
|
@@ -77,10 +88,10 @@ dependencies:
|
|
77
88
|
version: '0'
|
78
89
|
type: :development
|
79
90
|
prerelease: false
|
80
|
-
version_requirements: *
|
91
|
+
version_requirements: *70248892032840
|
81
92
|
- !ruby/object:Gem::Dependency
|
82
93
|
name: rack-test
|
83
|
-
requirement: &
|
94
|
+
requirement: &70248892042160 !ruby/object:Gem::Requirement
|
84
95
|
none: false
|
85
96
|
requirements:
|
86
97
|
- - ! '>='
|
@@ -88,10 +99,10 @@ dependencies:
|
|
88
99
|
version: '0'
|
89
100
|
type: :development
|
90
101
|
prerelease: false
|
91
|
-
version_requirements: *
|
102
|
+
version_requirements: *70248892042160
|
92
103
|
- !ruby/object:Gem::Dependency
|
93
104
|
name: guard-rspec
|
94
|
-
requirement: &
|
105
|
+
requirement: &70248892053200 !ruby/object:Gem::Requirement
|
95
106
|
none: false
|
96
107
|
requirements:
|
97
108
|
- - ! '>='
|
@@ -99,10 +110,10 @@ dependencies:
|
|
99
110
|
version: '0'
|
100
111
|
type: :development
|
101
112
|
prerelease: false
|
102
|
-
version_requirements: *
|
113
|
+
version_requirements: *70248892053200
|
103
114
|
- !ruby/object:Gem::Dependency
|
104
115
|
name: guard-bundler
|
105
|
-
requirement: &
|
116
|
+
requirement: &70248892049780 !ruby/object:Gem::Requirement
|
106
117
|
none: false
|
107
118
|
requirements:
|
108
119
|
- - ! '>='
|
@@ -110,10 +121,10 @@ dependencies:
|
|
110
121
|
version: '0'
|
111
122
|
type: :development
|
112
123
|
prerelease: false
|
113
|
-
version_requirements: *
|
124
|
+
version_requirements: *70248892049780
|
114
125
|
- !ruby/object:Gem::Dependency
|
115
126
|
name: em-http-request
|
116
|
-
requirement: &
|
127
|
+
requirement: &70248892059480 !ruby/object:Gem::Requirement
|
117
128
|
none: false
|
118
129
|
requirements:
|
119
130
|
- - ~>
|
@@ -121,10 +132,10 @@ dependencies:
|
|
121
132
|
version: 0.3.0
|
122
133
|
type: :development
|
123
134
|
prerelease: false
|
124
|
-
version_requirements: *
|
135
|
+
version_requirements: *70248892059480
|
125
136
|
- !ruby/object:Gem::Dependency
|
126
137
|
name: guard-coffeescript
|
127
|
-
requirement: &
|
138
|
+
requirement: &70248892071480 !ruby/object:Gem::Requirement
|
128
139
|
none: false
|
129
140
|
requirements:
|
130
141
|
- - ! '>='
|
@@ -132,7 +143,7 @@ dependencies:
|
|
132
143
|
version: '0'
|
133
144
|
type: :development
|
134
145
|
prerelease: false
|
135
|
-
version_requirements: *
|
146
|
+
version_requirements: *70248892071480
|
136
147
|
description: Firehose is a realtime web application toolkit for building realtime
|
137
148
|
Ruby web applications.
|
138
149
|
email:
|
@@ -156,7 +167,7 @@ files:
|
|
156
167
|
- lib/assets/flash/firehose/WebSocketMain.swf
|
157
168
|
- lib/assets/javascripts/firehose.js.coffee
|
158
169
|
- lib/assets/javascripts/firehose/base.js.coffee
|
159
|
-
- lib/assets/javascripts/firehose/
|
170
|
+
- lib/assets/javascripts/firehose/consumer.js.coffee
|
160
171
|
- lib/assets/javascripts/firehose/long_poll.js.coffee
|
161
172
|
- lib/assets/javascripts/firehose/transport.js.coffee
|
162
173
|
- lib/assets/javascripts/firehose/web_socket.js.coffee
|
@@ -170,7 +181,7 @@ files:
|
|
170
181
|
- spec/integrations/amqp_resources_spec.rb
|
171
182
|
- spec/integrations/thin_spec.rb
|
172
183
|
- spec/spec_helper.rb
|
173
|
-
homepage: http://
|
184
|
+
homepage: http://firehose.io/
|
174
185
|
licenses: []
|
175
186
|
post_install_message:
|
176
187
|
rdoc_options: []
|
@@ -1,45 +0,0 @@
|
|
1
|
-
class Firehose.Client
|
2
|
-
# Transports that are available to Firehose.
|
3
|
-
@transports: ['WebSocket', 'LongPoll']
|
4
|
-
|
5
|
-
# Generate a random client_id.
|
6
|
-
@nextClientId: ->
|
7
|
-
Math.floor((Math.random()*99999999999)+1)
|
8
|
-
|
9
|
-
constructor: (config={}) ->
|
10
|
-
# The clientId is used by the server to remember messages between requests. In a production environment,
|
11
|
-
# this should probably be some combination of "user_id-rand". Why the rand? Because a user may have multiple
|
12
|
-
# tabs open to the application, and each tab needs a different channel on the server.
|
13
|
-
config.clientId ||= Firehose.Client.nextClientId()
|
14
|
-
# List of transport stragies we have to use.
|
15
|
-
config.transports ||= Firehose.Client.transports
|
16
|
-
# Empty handler for messages.
|
17
|
-
config.message ||= ->
|
18
|
-
# Empty handler for error handling.
|
19
|
-
config.error ||= ->
|
20
|
-
# Empty handler for when we establish a connection.
|
21
|
-
config.connected ||= ->
|
22
|
-
# Empty handler for when we're disconnected.
|
23
|
-
config.disconnected ||= ->
|
24
|
-
# Additional options.
|
25
|
-
config.options ||= {}
|
26
|
-
# URL that we'll connect to.
|
27
|
-
config.uri ||= undefined
|
28
|
-
# Params that we'll tack on to the URL. We include a clientId in here for kicks.
|
29
|
-
config.params ||= { cid: config.clientId }
|
30
|
-
# Do stuff before we send the message into config.message. The sensible
|
31
|
-
# default on the webs is to parse JSON.
|
32
|
-
config.parse ||= (body) ->
|
33
|
-
$.parseJSON(body)
|
34
|
-
|
35
|
-
# Hang on to these config for when we connect.
|
36
|
-
@config = config
|
37
|
-
# Make sure we return ourself out of the constructor so we can chain.
|
38
|
-
this
|
39
|
-
|
40
|
-
connect: =>
|
41
|
-
# Figure out what transport is supported and return it.
|
42
|
-
# TODO if the initial connection fails, try the next transport mmmkay?
|
43
|
-
for transport in @config.transports
|
44
|
-
if transport = Firehose[transport]
|
45
|
-
return new transport(@config).connect() if transport.supported()
|