firehose 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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()
|