Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
a8df1bc3
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a8df1bc3
编写于
6月 02, 2016
作者:
M
Matthew Draper
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Properly support reloading for Action Cable channels
上级
7b75ca10
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
56 addition
and
84 deletion
+56
-84
actioncable/lib/action_cable/connection/subscriptions.rb
actioncable/lib/action_cable/connection/subscriptions.rb
+3
-3
actioncable/lib/action_cable/engine.rb
actioncable/lib/action_cable/engine.rb
+2
-5
actioncable/lib/action_cable/server/base.rb
actioncable/lib/action_cable/server/base.rb
+3
-13
actioncable/lib/action_cable/server/configuration.rb
actioncable/lib/action_cable/server/configuration.rb
+1
-9
actioncable/test/channel/stream_test.rb
actioncable/test/channel/stream_test.rb
+0
-4
actioncable/test/client/echo_channel.rb
actioncable/test/client/echo_channel.rb
+0
-22
actioncable/test/client_test.rb
actioncable/test/client_test.rb
+47
-25
actioncable/test/connection/subscriptions_test.rb
actioncable/test/connection/subscriptions_test.rb
+0
-1
railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb
...s/app/templates/app/channels/application_cable/channel.rb
+0
-1
railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb
...pp/templates/app/channels/application_cable/connection.rb
+0
-1
未找到文件。
actioncable/lib/action_cable/connection/subscriptions.rb
浏览文件 @
a8df1bc3
...
...
@@ -26,12 +26,12 @@ def add(data)
id_key
=
data
[
'identifier'
]
id_options
=
ActiveSupport
::
JSON
.
decode
(
id_key
).
with_indifferent_access
subscription_klass
=
connection
.
server
.
channel_classes
[
id_options
[
:channel
]]
subscription_klass
=
id_options
[
:channel
].
safe_constantize
if
subscription_klass
if
subscription_klass
&&
ActionCable
::
Channel
::
Base
>=
subscription_klass
subscriptions
[
id_key
]
||=
subscription_klass
.
new
(
connection
,
id_key
,
id_options
)
else
logger
.
error
"Subscription class not found
(
#{
data
.
inspect
}
)
"
logger
.
error
"Subscription class not found
:
#{
id_options
[
:channel
].
inspect
}
"
end
end
...
...
actioncable/lib/action_cable/engine.rb
浏览文件 @
a8df1bc3
...
...
@@ -31,11 +31,8 @@ class Engine < Rails::Engine # :nodoc:
self
.
cable
=
Rails
.
application
.
config_for
(
config_path
).
with_indifferent_access
end
if
'ApplicationCable::Connection'
.
safe_constantize
self
.
connection_class
=
ApplicationCable
::
Connection
end
self
.
channel_paths
=
Rails
.
application
.
paths
[
'app/channels'
].
existent
previous_connection_class
=
self
.
connection_class
self
.
connection_class
=
->
{
'ApplicationCable::Connection'
.
safe_constantize
||
previous_connection_class
.
call
}
options
.
each
{
|
k
,
v
|
send
(
"
#{
k
}
="
,
v
)
}
end
...
...
actioncable/lib/action_cable/server/base.rb
浏览文件 @
a8df1bc3
...
...
@@ -19,13 +19,13 @@ def self.logger; config.logger; end
def
initialize
@mutex
=
Monitor
.
new
@remote_connections
=
@event_loop
=
@worker_pool
=
@
channel_classes
=
@
pubsub
=
nil
@remote_connections
=
@event_loop
=
@worker_pool
=
@pubsub
=
nil
end
# Called by Rack to setup the server.
def
call
(
env
)
setup_heartbeat_timer
config
.
connection_class
.
new
(
self
,
env
).
process
config
.
connection_class
.
call
.
new
(
self
,
env
).
process
end
# Disconnect all the connections identified by `identifiers` on this server or any others via RemoteConnections.
...
...
@@ -67,16 +67,6 @@ def worker_pool
@worker_pool
||
@mutex
.
synchronize
{
@worker_pool
||=
ActionCable
::
Server
::
Worker
.
new
(
max_size:
config
.
worker_pool_size
)
}
end
# Requires and returns a hash of all of the channel class constants, which are keyed by name.
def
channel_classes
@channel_classes
||
@mutex
.
synchronize
do
@channel_classes
||=
begin
config
.
channel_paths
.
each
{
|
channel_path
|
require
channel_path
}
config
.
channel_class_names
.
each_with_object
({})
{
|
name
,
hash
|
hash
[
name
]
=
name
.
constantize
}
end
end
end
# Adapter used for all streams/broadcasting.
def
pubsub
@pubsub
||
@mutex
.
synchronize
{
@pubsub
||=
config
.
pubsub_adapter
.
new
(
self
)
}
...
...
@@ -84,7 +74,7 @@ def pubsub
# All of the identifiers applied to the connection class associated with this server.
def
connection_identifiers
config
.
connection_class
.
identifiers
config
.
connection_class
.
call
.
identifiers
end
end
...
...
actioncable/lib/action_cable/server/configuration.rb
浏览文件 @
a8df1bc3
...
...
@@ -8,23 +8,15 @@ class Configuration
attr_accessor
:disable_request_forgery_protection
,
:allowed_request_origins
attr_accessor
:cable
,
:url
,
:mount_path
attr_accessor
:channel_paths
# :nodoc:
def
initialize
@log_tags
=
[]
@connection_class
=
ActionCable
::
Connection
::
Base
@connection_class
=
->
{
ActionCable
::
Connection
::
Base
}
@worker_pool_size
=
4
@disable_request_forgery_protection
=
false
end
def
channel_class_names
@channel_class_names
||=
channel_paths
.
collect
do
|
channel_path
|
Pathname
.
new
(
channel_path
).
basename
.
to_s
.
split
(
'.'
).
first
.
camelize
end
end
# Returns constant of subscription adapter specified in config/cable.yml.
# If the adapter cannot be found, this will default to the Redis adapter.
# Also makes sure proper dependencies are required.
...
...
actioncable/test/channel/stream_test.rb
浏览文件 @
a8df1bc3
...
...
@@ -128,10 +128,6 @@ class StreamEncodingTest < ActionCable::TestCase
setup
do
@server
=
TestServer
.
new
(
subscription_adapter:
ActionCable
::
SubscriptionAdapter
::
Inline
)
@server
.
config
.
allowed_request_origins
=
%w( http://rubyonrails.com )
@server
.
stubs
(
:channel_classes
).
returns
(
ChatChannel
.
name
=>
ChatChannel
,
UserCallbackChannel
.
name
=>
UserCallbackChannel
,
)
end
test
'custom encoder'
do
...
...
actioncable/test/client/echo_channel.rb
已删除
100644 → 0
浏览文件 @
7b75ca10
class
EchoChannel
<
ActionCable
::
Channel
::
Base
def
subscribed
stream_from
"global"
end
def
unsubscribed
'Goodbye from EchoChannel!'
end
def
ding
(
data
)
transmit
(
dong:
data
[
'message'
])
end
def
delay
(
data
)
sleep
1
transmit
(
dong:
data
[
'message'
])
end
def
bulk
(
data
)
ActionCable
.
server
.
broadcast
"global"
,
wide:
data
[
'message'
]
end
end
actioncable/test/client_test.rb
浏览文件 @
a8df1bc3
...
...
@@ -11,6 +11,29 @@ class ClientTest < ActionCable::TestCase
WAIT_WHEN_EXPECTING_EVENT
=
8
WAIT_WHEN_NOT_EXPECTING_EVENT
=
0.5
class
EchoChannel
<
ActionCable
::
Channel
::
Base
def
subscribed
stream_from
"global"
end
def
unsubscribed
'Goodbye from EchoChannel!'
end
def
ding
(
data
)
transmit
(
dong:
data
[
'message'
])
end
def
delay
(
data
)
sleep
1
transmit
(
dong:
data
[
'message'
])
end
def
bulk
(
data
)
ActionCable
.
server
.
broadcast
"global"
,
wide:
data
[
'message'
]
end
end
def
setup
ActionCable
.
instance_variable_set
(
:@server
,
nil
)
server
=
ActionCable
.
server
...
...
@@ -21,7 +44,6 @@ def setup
# and now the "real" setup for our test:
server
.
config
.
disable_request_forgery_protection
=
true
server
.
config
.
channel_paths
=
[
File
.
expand_path
(
'client/echo_channel.rb'
,
__dir__
)
]
Thread
.
new
{
EventMachine
.
run
}
unless
EventMachine
.
reactor_running?
Thread
.
pass
until
EventMachine
.
reactor_running?
...
...
@@ -148,10 +170,10 @@ def test_single_client
with_puma_server
do
|
port
|
c
=
faye_client
(
port
)
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
# pop the first welcome message off the stack
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
close
end
end
...
...
@@ -165,12 +187,12 @@ def test_interacting_clients
clients
.
map
{
|
c
|
Concurrent
::
Future
.
execute
{
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
# pop the first welcome message off the stack
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
'{"channel":"EchoChannel"}'
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
'{"channel":"
ClientTest::
EchoChannel"}'
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"
ClientTest::
EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
barrier_1
.
wait
WAIT_WHEN_EXPECTING_EVENT
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'bulk'
,
message:
'hello'
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'bulk'
,
message:
'hello'
)
barrier_2
.
wait
WAIT_WHEN_EXPECTING_EVENT
assert_equal
clients
.
size
,
c
.
read_messages
(
clients
.
size
).
size
}
}.
each
(
&
:wait!
)
...
...
@@ -185,10 +207,10 @@ def test_many_clients
clients
.
map
{
|
c
|
Concurrent
::
Future
.
execute
{
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
# pop the first welcome message off the stack
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
'{"channel":"EchoChannel"}'
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
'{"channel":"
ClientTest::
EchoChannel"}'
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"
ClientTest::
EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
}
}.
each
(
&
:wait!
)
clients
.
map
{
|
c
|
Concurrent
::
Future
.
execute
{
c
.
close
}
}.
each
(
&
:wait!
)
...
...
@@ -199,17 +221,17 @@ def test_disappearing_client
with_puma_server
do
|
port
|
c
=
faye_client
(
port
)
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
# pop the first welcome message off the stack
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'delay'
,
message:
'hello'
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'delay'
,
message:
'hello'
)
c
.
close
# disappear before write
c
=
faye_client
(
port
)
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
# pop the first welcome message off the stack
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'message'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
),
data:
JSON
.
generate
(
action:
'ding'
,
message:
'hello'
)
assert_equal
({
"identifier"
=>
'{"channel":"
ClientTest::
EchoChannel"}'
,
"message"
=>
{
"dong"
=>
"hello"
}},
c
.
read_message
)
c
.
close
# disappear before read
end
end
...
...
@@ -217,12 +239,12 @@ def test_disappearing_client
def
test_unsubscribe_client
with_puma_server
do
|
port
|
app
=
ActionCable
.
server
identifier
=
JSON
.
generate
(
channel:
'EchoChannel'
)
identifier
=
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
c
=
faye_client
(
port
)
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
identifier
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
assert_equal
(
1
,
app
.
connections
.
count
)
assert
(
app
.
remote_connections
.
where
(
identifier:
identifier
))
...
...
@@ -242,8 +264,8 @@ def test_server_restart
with_puma_server
do
|
port
|
c
=
faye_client
(
port
)
assert_equal
({
"type"
=>
"welcome"
},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
c
.
send_message
command:
'subscribe'
,
identifier:
JSON
.
generate
(
channel:
'
ClientTest::
EchoChannel'
)
assert_equal
({
"identifier"
=>
"{
\"
channel
\"
:
\"
ClientTest::
EchoChannel
\"
}"
,
"type"
=>
"confirm_subscription"
},
c
.
read_message
)
ActionCable
.
server
.
restart
c
.
wait_for_close
...
...
actioncable/test/connection/subscriptions_test.rb
浏览文件 @
a8df1bc3
...
...
@@ -24,7 +24,6 @@ def speak(data)
setup
do
@server
=
TestServer
.
new
@server
.
stubs
(
:channel_classes
).
returns
(
ChatChannel
.
name
=>
ChatChannel
)
@chat_identifier
=
ActiveSupport
::
JSON
.
encode
(
id:
1
,
channel:
'ActionCable::Connection::SubscriptionsTest::ChatChannel'
)
end
...
...
railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb
浏览文件 @
a8df1bc3
# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
module
ApplicationCable
class
Channel
<
ActionCable
::
Channel
::
Base
end
...
...
railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb
浏览文件 @
a8df1bc3
# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
module
ApplicationCable
class
Connection
<
ActionCable
::
Connection
::
Base
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录