actioncable 5.0.0.beta1.1 → 5.0.0.beta2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -3
- data/MIT-LICENSE +1 -1
- data/README.md +60 -44
- data/lib/action_cable.rb +2 -1
- data/lib/action_cable/channel/base.rb +2 -2
- data/lib/action_cable/channel/periodic_timers.rb +3 -3
- data/lib/action_cable/channel/streams.rb +4 -4
- data/lib/action_cable/connection.rb +4 -1
- data/lib/action_cable/connection/base.rb +22 -21
- data/lib/action_cable/connection/client_socket.rb +150 -0
- data/lib/action_cable/connection/identification.rb +1 -1
- data/lib/action_cable/connection/internal_channel.rb +6 -6
- data/lib/action_cable/connection/stream.rb +59 -0
- data/lib/action_cable/connection/stream_event_loop.rb +94 -0
- data/lib/action_cable/connection/subscriptions.rb +0 -1
- data/lib/action_cable/connection/web_socket.rb +14 -8
- data/lib/action_cable/engine.rb +3 -3
- data/lib/action_cable/gem_version.rb +1 -1
- data/lib/action_cable/remote_connections.rb +1 -1
- data/lib/action_cable/server.rb +0 -4
- data/lib/action_cable/server/base.rb +19 -22
- data/lib/action_cable/server/broadcasting.rb +1 -8
- data/lib/action_cable/server/configuration.rb +25 -5
- data/lib/action_cable/server/connections.rb +3 -5
- data/lib/action_cable/server/worker.rb +42 -13
- data/lib/action_cable/subscription_adapter.rb +8 -0
- data/lib/action_cable/subscription_adapter/async.rb +22 -0
- data/lib/action_cable/subscription_adapter/base.rb +28 -0
- data/lib/action_cable/subscription_adapter/evented_redis.rb +67 -0
- data/lib/action_cable/subscription_adapter/inline.rb +35 -0
- data/lib/action_cable/subscription_adapter/postgresql.rb +106 -0
- data/lib/action_cable/subscription_adapter/redis.rb +163 -0
- data/lib/action_cable/subscription_adapter/subscriber_map.rb +53 -0
- data/lib/assets/compiled/action_cable.js +473 -0
- data/lib/rails/generators/channel/channel_generator.rb +6 -1
- metadata +21 -99
- data/lib/action_cable/process/logging.rb +0 -10
- data/lib/assets/javascripts/action_cable.coffee.erb +0 -23
- data/lib/assets/javascripts/action_cable/connection.coffee +0 -84
- data/lib/assets/javascripts/action_cable/connection_monitor.coffee +0 -84
- data/lib/assets/javascripts/action_cable/consumer.coffee +0 -31
- data/lib/assets/javascripts/action_cable/subscription.coffee +0 -68
- data/lib/assets/javascripts/action_cable/subscriptions.coffee +0 -78
@@ -5,11 +5,16 @@ module Rails
|
|
5
5
|
|
6
6
|
argument :actions, type: :array, default: [], banner: "method method"
|
7
7
|
|
8
|
+
class_option :assets, type: :boolean
|
9
|
+
|
8
10
|
check_class_collision suffix: "Channel"
|
9
11
|
|
10
12
|
def create_channel_file
|
11
13
|
template "channel.rb", File.join('app/channels', class_path, "#{file_name}_channel.rb")
|
12
|
-
|
14
|
+
|
15
|
+
if options[:assets]
|
16
|
+
template "assets/channel.coffee", File.join('app/assets/javascripts/channels', class_path, "#{file_name}.coffee")
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
20
|
protected
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actioncable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.0.
|
4
|
+
version: 5.0.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pratik Naik
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-01
|
12
|
+
date: 2016-02-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|
@@ -17,42 +17,28 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - '='
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 5.0.0.
|
20
|
+
version: 5.0.0.beta2
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - '='
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 5.0.0.
|
27
|
+
version: 5.0.0.beta2
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: nio4r
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: '1.2'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
42
|
-
- !ruby/object:Gem::Dependency
|
43
|
-
name: faye-websocket
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - "~>"
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: 0.10.0
|
49
|
-
type: :runtime
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - "~>"
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: 0.10.0
|
41
|
+
version: '1.2'
|
56
42
|
- !ruby/object:Gem::Dependency
|
57
43
|
name: websocket-driver
|
58
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,76 +53,6 @@ dependencies:
|
|
67
53
|
- - "~>"
|
68
54
|
- !ruby/object:Gem::Version
|
69
55
|
version: 0.6.1
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: celluloid
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - "~>"
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: 0.17.2
|
77
|
-
type: :runtime
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - "~>"
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: 0.17.2
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: em-hiredis
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
- - "~>"
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: 0.3.0
|
91
|
-
type: :runtime
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - "~>"
|
96
|
-
- !ruby/object:Gem::Version
|
97
|
-
version: 0.3.0
|
98
|
-
- !ruby/object:Gem::Dependency
|
99
|
-
name: redis
|
100
|
-
requirement: !ruby/object:Gem::Requirement
|
101
|
-
requirements:
|
102
|
-
- - "~>"
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version: '3.0'
|
105
|
-
type: :runtime
|
106
|
-
prerelease: false
|
107
|
-
version_requirements: !ruby/object:Gem::Requirement
|
108
|
-
requirements:
|
109
|
-
- - "~>"
|
110
|
-
- !ruby/object:Gem::Version
|
111
|
-
version: '3.0'
|
112
|
-
- !ruby/object:Gem::Dependency
|
113
|
-
name: puma
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
-
requirements:
|
116
|
-
- - ">="
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: '0'
|
119
|
-
type: :development
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
requirements:
|
123
|
-
- - ">="
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: mocha
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
requirements:
|
130
|
-
- - ">="
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: '0'
|
133
|
-
type: :development
|
134
|
-
prerelease: false
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
136
|
-
requirements:
|
137
|
-
- - ">="
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
version: '0'
|
140
56
|
description: Structure many real-time application concerns into channels over a single
|
141
57
|
WebSocket connection.
|
142
58
|
email:
|
@@ -160,16 +76,18 @@ files:
|
|
160
76
|
- lib/action_cable/connection.rb
|
161
77
|
- lib/action_cable/connection/authorization.rb
|
162
78
|
- lib/action_cable/connection/base.rb
|
79
|
+
- lib/action_cable/connection/client_socket.rb
|
163
80
|
- lib/action_cable/connection/identification.rb
|
164
81
|
- lib/action_cable/connection/internal_channel.rb
|
165
82
|
- lib/action_cable/connection/message_buffer.rb
|
83
|
+
- lib/action_cable/connection/stream.rb
|
84
|
+
- lib/action_cable/connection/stream_event_loop.rb
|
166
85
|
- lib/action_cable/connection/subscriptions.rb
|
167
86
|
- lib/action_cable/connection/tagged_logger_proxy.rb
|
168
87
|
- lib/action_cable/connection/web_socket.rb
|
169
88
|
- lib/action_cable/engine.rb
|
170
89
|
- lib/action_cable/gem_version.rb
|
171
90
|
- lib/action_cable/helpers/action_cable_helper.rb
|
172
|
-
- lib/action_cable/process/logging.rb
|
173
91
|
- lib/action_cable/remote_connections.rb
|
174
92
|
- lib/action_cable/server.rb
|
175
93
|
- lib/action_cable/server/base.rb
|
@@ -178,13 +96,16 @@ files:
|
|
178
96
|
- lib/action_cable/server/connections.rb
|
179
97
|
- lib/action_cable/server/worker.rb
|
180
98
|
- lib/action_cable/server/worker/active_record_connection_management.rb
|
99
|
+
- lib/action_cable/subscription_adapter.rb
|
100
|
+
- lib/action_cable/subscription_adapter/async.rb
|
101
|
+
- lib/action_cable/subscription_adapter/base.rb
|
102
|
+
- lib/action_cable/subscription_adapter/evented_redis.rb
|
103
|
+
- lib/action_cable/subscription_adapter/inline.rb
|
104
|
+
- lib/action_cable/subscription_adapter/postgresql.rb
|
105
|
+
- lib/action_cable/subscription_adapter/redis.rb
|
106
|
+
- lib/action_cable/subscription_adapter/subscriber_map.rb
|
181
107
|
- lib/action_cable/version.rb
|
182
|
-
- lib/assets/
|
183
|
-
- lib/assets/javascripts/action_cable/connection.coffee
|
184
|
-
- lib/assets/javascripts/action_cable/connection_monitor.coffee
|
185
|
-
- lib/assets/javascripts/action_cable/consumer.coffee
|
186
|
-
- lib/assets/javascripts/action_cable/subscription.coffee
|
187
|
-
- lib/assets/javascripts/action_cable/subscriptions.coffee
|
108
|
+
- lib/assets/compiled/action_cable.js
|
188
109
|
- lib/rails/generators/channel/USAGE
|
189
110
|
- lib/rails/generators/channel/channel_generator.rb
|
190
111
|
- lib/rails/generators/channel/templates/assets/channel.coffee
|
@@ -209,8 +130,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
130
|
version: 1.3.1
|
210
131
|
requirements: []
|
211
132
|
rubyforge_project:
|
212
|
-
rubygems_version: 2.5.
|
133
|
+
rubygems_version: 2.5.2
|
213
134
|
signing_key:
|
214
135
|
specification_version: 4
|
215
136
|
summary: WebSocket framework for Rails.
|
216
137
|
test_files: []
|
138
|
+
has_rdoc:
|
@@ -1,23 +0,0 @@
|
|
1
|
-
#= require_self
|
2
|
-
#= require action_cable/consumer
|
3
|
-
|
4
|
-
@ActionCable =
|
5
|
-
INTERNAL: <%= ActionCable::INTERNAL.to_json %>
|
6
|
-
|
7
|
-
createConsumer: (url = @getConfig("url")) ->
|
8
|
-
new ActionCable.Consumer @createWebSocketURL(url)
|
9
|
-
|
10
|
-
getConfig: (name) ->
|
11
|
-
element = document.head.querySelector("meta[name='action-cable-#{name}']")
|
12
|
-
element?.getAttribute("content")
|
13
|
-
|
14
|
-
createWebSocketURL: (url) ->
|
15
|
-
if url and not /^wss?:/i.test(url)
|
16
|
-
a = document.createElement("a")
|
17
|
-
a.href = url
|
18
|
-
# Fix populating Location properties in IE. Otherwise, protocol will be blank.
|
19
|
-
a.href = a.href
|
20
|
-
a.protocol = a.protocol.replace("http", "ws")
|
21
|
-
a.href
|
22
|
-
else
|
23
|
-
url
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.
|
2
|
-
|
3
|
-
{message_types} = ActionCable.INTERNAL
|
4
|
-
|
5
|
-
class ActionCable.Connection
|
6
|
-
@reopenDelay: 500
|
7
|
-
|
8
|
-
constructor: (@consumer) ->
|
9
|
-
@open()
|
10
|
-
|
11
|
-
send: (data) ->
|
12
|
-
if @isOpen()
|
13
|
-
@webSocket.send(JSON.stringify(data))
|
14
|
-
true
|
15
|
-
else
|
16
|
-
false
|
17
|
-
|
18
|
-
open: =>
|
19
|
-
if @webSocket and not @isState("closed")
|
20
|
-
throw new Error("Existing connection must be closed before opening")
|
21
|
-
else
|
22
|
-
@webSocket = new WebSocket(@consumer.url)
|
23
|
-
@installEventHandlers()
|
24
|
-
true
|
25
|
-
|
26
|
-
close: ->
|
27
|
-
@webSocket?.close()
|
28
|
-
|
29
|
-
reopen: ->
|
30
|
-
if @isState("closed")
|
31
|
-
@open()
|
32
|
-
else
|
33
|
-
try
|
34
|
-
@close()
|
35
|
-
finally
|
36
|
-
setTimeout(@open, @constructor.reopenDelay)
|
37
|
-
|
38
|
-
isOpen: ->
|
39
|
-
@isState("open")
|
40
|
-
|
41
|
-
# Private
|
42
|
-
|
43
|
-
isState: (states...) ->
|
44
|
-
@getState() in states
|
45
|
-
|
46
|
-
getState: ->
|
47
|
-
return state.toLowerCase() for state, value of WebSocket when value is @webSocket?.readyState
|
48
|
-
null
|
49
|
-
|
50
|
-
installEventHandlers: ->
|
51
|
-
for eventName of @events
|
52
|
-
handler = @events[eventName].bind(this)
|
53
|
-
@webSocket["on#{eventName}"] = handler
|
54
|
-
return
|
55
|
-
|
56
|
-
events:
|
57
|
-
message: (event) ->
|
58
|
-
{identifier, message, type} = JSON.parse(event.data)
|
59
|
-
|
60
|
-
switch type
|
61
|
-
when message_types.confirmation
|
62
|
-
@consumer.subscriptions.notify(identifier, "connected")
|
63
|
-
when message_types.rejection
|
64
|
-
@consumer.subscriptions.reject(identifier)
|
65
|
-
else
|
66
|
-
@consumer.subscriptions.notify(identifier, "received", message)
|
67
|
-
|
68
|
-
open: ->
|
69
|
-
@disconnected = false
|
70
|
-
@consumer.subscriptions.reload()
|
71
|
-
|
72
|
-
close: ->
|
73
|
-
@disconnect()
|
74
|
-
|
75
|
-
error: ->
|
76
|
-
@disconnect()
|
77
|
-
|
78
|
-
disconnect: ->
|
79
|
-
return if @disconnected
|
80
|
-
@disconnected = true
|
81
|
-
@consumer.subscriptions.notifyAll("disconnected")
|
82
|
-
|
83
|
-
toJSON: ->
|
84
|
-
state: @getState()
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting
|
2
|
-
# revival reconnections if things go astray. Internal class, not intended for direct user manipulation.
|
3
|
-
class ActionCable.ConnectionMonitor
|
4
|
-
@pollInterval:
|
5
|
-
min: 3
|
6
|
-
max: 30
|
7
|
-
|
8
|
-
@staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
|
9
|
-
|
10
|
-
identifier: ActionCable.INTERNAL.identifiers.ping
|
11
|
-
|
12
|
-
constructor: (@consumer) ->
|
13
|
-
@consumer.subscriptions.add(this)
|
14
|
-
@start()
|
15
|
-
|
16
|
-
connected: ->
|
17
|
-
@reset()
|
18
|
-
@pingedAt = now()
|
19
|
-
delete @disconnectedAt
|
20
|
-
|
21
|
-
disconnected: ->
|
22
|
-
@disconnectedAt = now()
|
23
|
-
|
24
|
-
received: ->
|
25
|
-
@pingedAt = now()
|
26
|
-
|
27
|
-
reset: ->
|
28
|
-
@reconnectAttempts = 0
|
29
|
-
|
30
|
-
start: ->
|
31
|
-
@reset()
|
32
|
-
delete @stoppedAt
|
33
|
-
@startedAt = now()
|
34
|
-
@poll()
|
35
|
-
document.addEventListener("visibilitychange", @visibilityDidChange)
|
36
|
-
|
37
|
-
stop: ->
|
38
|
-
@stoppedAt = now()
|
39
|
-
document.removeEventListener("visibilitychange", @visibilityDidChange)
|
40
|
-
|
41
|
-
poll: ->
|
42
|
-
setTimeout =>
|
43
|
-
unless @stoppedAt
|
44
|
-
@reconnectIfStale()
|
45
|
-
@poll()
|
46
|
-
, @getInterval()
|
47
|
-
|
48
|
-
getInterval: ->
|
49
|
-
{min, max} = @constructor.pollInterval
|
50
|
-
interval = 5 * Math.log(@reconnectAttempts + 1)
|
51
|
-
clamp(interval, min, max) * 1000
|
52
|
-
|
53
|
-
reconnectIfStale: ->
|
54
|
-
if @connectionIsStale()
|
55
|
-
@reconnectAttempts++
|
56
|
-
unless @disconnectedRecently()
|
57
|
-
@consumer.connection.reopen()
|
58
|
-
|
59
|
-
connectionIsStale: ->
|
60
|
-
secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold
|
61
|
-
|
62
|
-
disconnectedRecently: ->
|
63
|
-
@disconnectedAt and secondsSince(@disconnectedAt) < @constructor.staleThreshold
|
64
|
-
|
65
|
-
visibilityDidChange: =>
|
66
|
-
if document.visibilityState is "visible"
|
67
|
-
setTimeout =>
|
68
|
-
if @connectionIsStale() or not @consumer.connection.isOpen()
|
69
|
-
@consumer.connection.reopen()
|
70
|
-
, 200
|
71
|
-
|
72
|
-
toJSON: ->
|
73
|
-
interval = @getInterval()
|
74
|
-
connectionIsStale = @connectionIsStale()
|
75
|
-
{@startedAt, @stoppedAt, @pingedAt, @reconnectAttempts, connectionIsStale, interval}
|
76
|
-
|
77
|
-
now = ->
|
78
|
-
new Date().getTime()
|
79
|
-
|
80
|
-
secondsSince = (time) ->
|
81
|
-
(now() - time) / 1000
|
82
|
-
|
83
|
-
clamp = (number, min, max) ->
|
84
|
-
Math.max(min, Math.min(max, number))
|
@@ -1,31 +0,0 @@
|
|
1
|
-
#= require action_cable/connection
|
2
|
-
#= require action_cable/connection_monitor
|
3
|
-
#= require action_cable/subscriptions
|
4
|
-
#= require action_cable/subscription
|
5
|
-
|
6
|
-
# The ActionCable.Consumer establishes the connection to a server-side Ruby Connection object. Once established,
|
7
|
-
# the ActionCable.ConnectionMonitor will ensure that its properly maintained through heartbeats and checking for stale updates.
|
8
|
-
# The Consumer instance is also the gateway to establishing subscriptions to desired channels through the #createSubscription
|
9
|
-
# method.
|
10
|
-
#
|
11
|
-
# The following example shows how this can be setup:
|
12
|
-
#
|
13
|
-
# @App = {}
|
14
|
-
# App.cable = ActionCable.createConsumer "ws://example.com/accounts/1"
|
15
|
-
# App.appearance = App.cable.subscriptions.create "AppearanceChannel"
|
16
|
-
#
|
17
|
-
# For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.
|
18
|
-
class ActionCable.Consumer
|
19
|
-
constructor: (@url) ->
|
20
|
-
@subscriptions = new ActionCable.Subscriptions this
|
21
|
-
@connection = new ActionCable.Connection this
|
22
|
-
@connectionMonitor = new ActionCable.ConnectionMonitor this
|
23
|
-
|
24
|
-
send: (data) ->
|
25
|
-
@connection.send(data)
|
26
|
-
|
27
|
-
inspect: ->
|
28
|
-
JSON.stringify(this, null, 2)
|
29
|
-
|
30
|
-
toJSON: ->
|
31
|
-
{@url, @subscriptions, @connection, @connectionMonitor}
|