cable_room 0.1.2 → 0.2.0
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/lib/cable_room/channel_base.rb +18 -5
- data/lib/cable_room/channel_tracker.rb +2 -2
- data/lib/cable_room/room/base.rb +6 -2
- data/lib/cable_room/room/broadcasting.rb +13 -0
- data/lib/cable_room/room/input_handling.rb +51 -5
- data/lib/cable_room/room/port_management.rb +136 -0
- data/lib/cable_room/room/port_scoping.rb +40 -0
- data/lib/cable_room/room/user_management.rb +60 -29
- data/lib/cable_room/room.rb +5 -3
- data/lib/cable_room/room_member.rb +29 -13
- data/lib/cable_room/version.rb +1 -1
- data/spec/internal/log/test.log +3056 -0
- metadata +4 -2
- data/lib/cable_room/room/member_management.rb +0 -67
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 020faa2e6a7e8cd1027b4d5c7303d57ef1282ab4f298800df26d6336587082dc
|
|
4
|
+
data.tar.gz: fae6de782ad1a15d7e065fbef53e71665ebb4606ecd75748fa7e574bd63ae393
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24de44e3b78d19d72af29783069bf8ddd6ed87d03bb185c4e2fae9b79e159f6c2da7701f2a575cf54cb2a6baaf0a66ea4e4d65c7e84048694f33c8d6c19e2dd4
|
|
7
|
+
data.tar.gz: 178caf0566a1420f7cb705d9076ae39a5cd664cd42da23619f9312f1feccc34b8afb55563aeb5acf8af700fe4046b6cad5f901b34c6d9bf2947d8c2f6ff08529
|
|
@@ -67,8 +67,11 @@ module CableRoom
|
|
|
67
67
|
@mutex.synchronize do
|
|
68
68
|
@current_state = :shutting_down
|
|
69
69
|
stop_all_streams
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
begin
|
|
71
|
+
@room.send(:_shutdown)
|
|
72
|
+
ensure
|
|
73
|
+
terminate!
|
|
74
|
+
end
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
|
|
@@ -80,7 +83,9 @@ module CableRoom
|
|
|
80
83
|
end
|
|
81
84
|
|
|
82
85
|
def check_room_watchdog
|
|
83
|
-
|
|
86
|
+
@mutex.synchronize do
|
|
87
|
+
return if state == :dead || state == :shutting_down
|
|
88
|
+
end
|
|
84
89
|
|
|
85
90
|
relock = CableRoom.lock_manager.lock(@lock_info[:resource], @lock_duration.in_milliseconds, extend: @lock_info)
|
|
86
91
|
unless relock
|
|
@@ -121,7 +126,7 @@ module CableRoom
|
|
|
121
126
|
end
|
|
122
127
|
end
|
|
123
128
|
|
|
124
|
-
def
|
|
129
|
+
def _post_wrapped_work(async: false, silent: false, &blk)
|
|
125
130
|
if async
|
|
126
131
|
# Async stuff is mostly untracked - we just post it to the worker pool and forget about it
|
|
127
132
|
worker_pool.executor.post(&blk)
|
|
@@ -137,6 +142,14 @@ module CableRoom
|
|
|
137
142
|
end
|
|
138
143
|
end
|
|
139
144
|
|
|
145
|
+
def post_work(**kwargs, &blk)
|
|
146
|
+
_post_wrapped_work(**kwargs) do
|
|
147
|
+
worker_pool.invoke(self, :instance_exec, connection: self, &blk)
|
|
148
|
+
rescue => e
|
|
149
|
+
logger.error "Error during work execution: #{e.class.name}: #{e.message}"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
140
153
|
def beat
|
|
141
154
|
post_work(async: true) do
|
|
142
155
|
check_room_watchdog
|
|
@@ -184,7 +197,7 @@ module CableRoom
|
|
|
184
197
|
|
|
185
198
|
class DummyConnection
|
|
186
199
|
attr_reader :channel
|
|
187
|
-
delegate :server, :logger, :tenant, :transmit, :post_work, to: :channel
|
|
200
|
+
delegate :server, :logger, :tenant, :transmit, :post_work, :_post_wrapped_work, to: :channel
|
|
188
201
|
delegate :event_loop, :pubsub, :worker_pool, to: :server
|
|
189
202
|
|
|
190
203
|
attr_reader :identifiers
|
|
@@ -96,7 +96,7 @@ module CableRoom
|
|
|
96
96
|
ActionCable::Server::Worker.connection = pconn
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
def async_invoke(receiver, method, *args, connection: receiver,
|
|
99
|
+
def async_invoke(receiver, method, *args, connection: receiver, &block)
|
|
100
100
|
# Instead of posting directly to the global pool, post to a dedicated queue for the room/"connection".
|
|
101
101
|
# This makes each rooms so that they can be processed by at-most-one thread at a time, while still
|
|
102
102
|
# allowing multiple rooms to be processed by the same thread-pool.
|
|
@@ -105,7 +105,7 @@ module CableRoom
|
|
|
105
105
|
|
|
106
106
|
# "connection" here really references the Channel, since "Connections" in this context don't really exist
|
|
107
107
|
|
|
108
|
-
connection.
|
|
108
|
+
connection._post_wrapped_work(async: false) do
|
|
109
109
|
invoke(receiver, method, *args, connection: connection, &block)
|
|
110
110
|
end
|
|
111
111
|
end
|
data/lib/cable_room/room/base.rb
CHANGED
|
@@ -50,15 +50,19 @@ module CableRoom
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
include Ports
|
|
53
|
+
|
|
53
54
|
include Callbacks
|
|
54
55
|
include Threading
|
|
55
56
|
include ChannelAdapter
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
include Lifecycle
|
|
58
59
|
include Reaping
|
|
60
|
+
include InputHandling
|
|
59
61
|
|
|
60
|
-
include
|
|
62
|
+
include PortScoping
|
|
63
|
+
include PortManagement
|
|
61
64
|
include UserManagement
|
|
65
|
+
include Broadcasting
|
|
62
66
|
|
|
63
67
|
attr_reader :key
|
|
64
68
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module CableRoom
|
|
2
|
+
module Room
|
|
3
|
+
module Broadcasting
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def broadcast(message, **kwargs)
|
|
7
|
+
with_port_scope!(**kwargs) do |client_port: nil|
|
|
8
|
+
ports[client_port || self.class::ROOM_OUT_CHANNEL] << message
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
module CableRoom
|
|
2
2
|
module Room
|
|
3
|
+
thread_mattr_accessor :current_message
|
|
4
|
+
|
|
3
5
|
module InputHandling
|
|
4
6
|
extend ActiveSupport::Concern
|
|
7
|
+
include ActiveSupport::Callbacks
|
|
8
|
+
|
|
9
|
+
class_methods do
|
|
10
|
+
def authorize_inbound(symbol_or_proc = nil, only: nil, except: nil, &blk)
|
|
11
|
+
raise ArgumentError, "Must provide either a symbol, proc, or block" unless symbol_or_proc ^ blk
|
|
12
|
+
|
|
13
|
+
only = Set.new(Array(only).map(&:to_sym)) if only
|
|
14
|
+
except = Set.new(Array(except).map(&:to_sym)) if except
|
|
15
|
+
|
|
16
|
+
blk = symbol_or_proc if symbol_or_proc.is_a?(Proc)
|
|
17
|
+
blk = -> { send(symbol_or_proc) } if symbol_or_proc.is_a?(Symbol)
|
|
18
|
+
|
|
19
|
+
set_callback(:receive_message, :before) do
|
|
20
|
+
type = message['type'].to_s.underscore.to_sym
|
|
21
|
+
if (only && !only.include?(type)) || (except && except.include?(type))
|
|
22
|
+
next
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
unless instance_exec(message, &blk)
|
|
26
|
+
logger.warn "Dropping unauthorized message: #{message.inspect}"
|
|
27
|
+
throw :abort
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
5
32
|
|
|
6
33
|
included do
|
|
34
|
+
define_callbacks :receive_message
|
|
35
|
+
|
|
36
|
+
set_callback(:receive_message, :before) do
|
|
37
|
+
logger.debug "Received message: #{message.inspect}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
set_callback(:receive_message, :before) do
|
|
41
|
+
if message == "KILL"
|
|
42
|
+
shutdown!
|
|
43
|
+
throw :abort
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
7
47
|
before_startup do
|
|
8
48
|
ports[self.class::ROOM_IN_CHANNEL].stream do |message|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
49
|
+
begin
|
|
50
|
+
Room.current_message = message
|
|
51
|
+
run_callbacks :receive_message do
|
|
52
|
+
handle_received_message(message)
|
|
53
|
+
end
|
|
54
|
+
ensure
|
|
55
|
+
Room.current_message = nil
|
|
14
56
|
end
|
|
15
57
|
end
|
|
16
58
|
end
|
|
@@ -18,6 +60,10 @@ module CableRoom
|
|
|
18
60
|
|
|
19
61
|
protected
|
|
20
62
|
|
|
63
|
+
def message
|
|
64
|
+
Room.current_message
|
|
65
|
+
end
|
|
66
|
+
|
|
21
67
|
def handle_received_message(message)
|
|
22
68
|
sym = :"on_#{message['type'].underscore.to_s.downcase}"
|
|
23
69
|
if respond_to?(sym, true)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
module CableRoom
|
|
2
|
+
module Room
|
|
3
|
+
module PortManagement
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
PORT_TIMEOUT = 30.seconds
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def inbound_require_tag(tag, **kwargs)
|
|
10
|
+
tag_array = Array(tag).map(&:to_sym)
|
|
11
|
+
authorize_inbound(**kwargs) do |message|
|
|
12
|
+
(tag_array - origin_tags).empty?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def on_port_connected(...)
|
|
17
|
+
set_callback(:port_connected, :before, ...)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def on_port_disconnected(...)
|
|
21
|
+
set_callback(:port_disconnected, :after, ...)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
included do
|
|
26
|
+
periodically :check_port_inactivity, every: PORT_TIMEOUT
|
|
27
|
+
|
|
28
|
+
define_callbacks :port_connected, :port_disconnected
|
|
29
|
+
|
|
30
|
+
set_callback(:receive_message, :around) do |_, blk|
|
|
31
|
+
previous_mtok = @current_message_origin
|
|
32
|
+
begin
|
|
33
|
+
mtok = message['mtok']
|
|
34
|
+
@current_message_origin = mtok
|
|
35
|
+
blk.call
|
|
36
|
+
ensure
|
|
37
|
+
@current_message_origin = previous_mtok
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(...)
|
|
43
|
+
super
|
|
44
|
+
@port_data = {}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def _apply_port_scope(client_port: nil, tag: nil, **kwargs)
|
|
48
|
+
if client_port && tag
|
|
49
|
+
throw :abort unless port_data(client_port)[:tags]&.include?(tag)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
{ client_port: client_port || tag, **kwargs }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def reply(message = nil, **kwargs)
|
|
56
|
+
raise ArgumentError, "Can only use reply when handling a message" unless origin_port
|
|
57
|
+
raise ArgumentError, "Must provide message or block" unless message || block_given?
|
|
58
|
+
raise ArgumentError, "Cannot specify client_port: when using reply" if kwargs.key?(:client_port)
|
|
59
|
+
|
|
60
|
+
if block_given?
|
|
61
|
+
with_port_scope(client_port: origin_port) do
|
|
62
|
+
yield
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
broadcast(message, **kwargs, client_port: origin_port)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
protected
|
|
70
|
+
|
|
71
|
+
def on_port_disconnected(); end
|
|
72
|
+
|
|
73
|
+
def on_port_connected(); end
|
|
74
|
+
|
|
75
|
+
def touch_port_activity(mtok = nil)
|
|
76
|
+
port_data(mtok)[:last_seen_at] = Time.now
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def port_data(mtok = nil)
|
|
80
|
+
mtok ||= @current_message_origin
|
|
81
|
+
@port_data[mtok] ||= HashWithIndifferentAccess.new
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def origin_port
|
|
85
|
+
@current_message_origin
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def origin_tags
|
|
89
|
+
port_data[:tags] || []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def origin_tagged?(tag)
|
|
93
|
+
origin_tags.include?(tag)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def handle_received_message(message)
|
|
97
|
+
case message['type']
|
|
98
|
+
when 'port_connected'
|
|
99
|
+
mdata = port_data
|
|
100
|
+
mdata[:last_seen_at] = Time.now
|
|
101
|
+
touch_port_activity
|
|
102
|
+
|
|
103
|
+
mdata.merge! ::ActiveJob::Arguments.deserialize(message['extra'])[0] if message['extra'].present?
|
|
104
|
+
mdata[:tags] = Array(message['tags']).map(&:to_sym) if message['tags'].present?
|
|
105
|
+
|
|
106
|
+
run_callbacks :port_connected do
|
|
107
|
+
on_port_connected
|
|
108
|
+
end
|
|
109
|
+
when 'port_disconnected'
|
|
110
|
+
run_callbacks :port_disconnected do
|
|
111
|
+
on_port_disconnected
|
|
112
|
+
end
|
|
113
|
+
@port_data.delete(origin_port)
|
|
114
|
+
when 'port_ping'
|
|
115
|
+
touch_port_activity
|
|
116
|
+
else
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def check_port_inactivity
|
|
122
|
+
return unless @port_data
|
|
123
|
+
|
|
124
|
+
threshold = PORT_TIMEOUT.ago
|
|
125
|
+
@port_data.each do |mtok, data|
|
|
126
|
+
next unless data[:last_seen_at] && data[:last_seen_at] < threshold
|
|
127
|
+
|
|
128
|
+
run_callbacks :port_disconnected do
|
|
129
|
+
on_port_disconnected
|
|
130
|
+
end
|
|
131
|
+
@port_data.delete(mtok)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module CableRoom
|
|
2
|
+
module Room
|
|
3
|
+
thread_mattr_accessor :current_port_scope
|
|
4
|
+
|
|
5
|
+
module PortScoping
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def without_port_scope(&blk)
|
|
9
|
+
prev = Room.current_port_scope
|
|
10
|
+
Room.current_port_scope = nil
|
|
11
|
+
yield
|
|
12
|
+
ensure
|
|
13
|
+
Room.current_port_scope = prev
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Wrap the passed block with a specific messaging scope
|
|
17
|
+
def with_port_scope(**kwargs, &blk)
|
|
18
|
+
prev = Room.current_port_scope
|
|
19
|
+
Room.current_port_scope = prev ? prev.merge(kwargs) : kwargs
|
|
20
|
+
yield
|
|
21
|
+
ensure
|
|
22
|
+
Room.current_port_scope = prev
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Similar to with_port_scope, but won't call the block if no ports match
|
|
26
|
+
def with_port_scope!(**kwargs, &blk)
|
|
27
|
+
if kwargs.empty?
|
|
28
|
+
catch :abort do
|
|
29
|
+
remaining = _apply_port_scope(**Room.current_port_scope || {})
|
|
30
|
+
blk.call(**remaining)
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
with_port_scope(**kwargs) do
|
|
34
|
+
with_port_scope!(&blk)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -3,64 +3,95 @@ module CableRoom
|
|
|
3
3
|
module UserManagement
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
class_methods do
|
|
7
|
+
def on_user_joined(...)
|
|
8
|
+
set_callback(:user_joined, :before, ...)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def on_user_left(...)
|
|
12
|
+
set_callback(:user_left, :after, ...)
|
|
13
|
+
end
|
|
10
14
|
end
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
included do
|
|
17
|
+
set_callback(:port_connected, :before, :_handle_user_setup_during_connection)
|
|
18
|
+
set_callback(:port_disconnected, :after, :_handle_user_cleanup_after_disconnection)
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
next unless usm.present?
|
|
17
|
-
usm[:member_tokens].delete(mtok)
|
|
18
|
-
if usm[:member_tokens].empty?
|
|
19
|
-
@_user_state_map.delete(u)
|
|
20
|
-
on_user_left(u)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
20
|
+
define_callbacks :user_joined, :user_left
|
|
21
|
+
end
|
|
23
22
|
|
|
23
|
+
def initialize(...)
|
|
24
|
+
@_user_state_map = {}c
|
|
25
|
+
@_user_map_mutex = Monitor.new
|
|
24
26
|
super
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
def
|
|
29
|
+
def on_user_left; end
|
|
28
30
|
|
|
29
|
-
def
|
|
31
|
+
def on_user_joined; end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def _handle_user_setup_during_connection
|
|
30
36
|
_user_state_transaction do |usm, u|
|
|
31
37
|
if usm.nil?
|
|
32
38
|
usm = @_user_state_map[u] = {
|
|
33
|
-
|
|
39
|
+
port_tokens: Set.new,
|
|
34
40
|
}
|
|
35
41
|
is_new = true
|
|
36
42
|
end
|
|
37
|
-
usm[:
|
|
38
|
-
|
|
43
|
+
usm[:port_tokens] << origin_port
|
|
44
|
+
if is_new
|
|
45
|
+
run_callbacks :user_joined do
|
|
46
|
+
on_user_joined
|
|
47
|
+
end
|
|
48
|
+
end
|
|
39
49
|
end
|
|
50
|
+
end
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
def _handle_user_cleanup_after_disconnection
|
|
53
|
+
_user_state_transaction do |usm, u|
|
|
54
|
+
next unless usm.present?
|
|
55
|
+
usm[:port_tokens].delete(origin_port)
|
|
56
|
+
if usm[:port_tokens].empty?
|
|
57
|
+
run_callbacks :user_left do
|
|
58
|
+
on_user_left
|
|
59
|
+
end
|
|
60
|
+
@_user_state_map.delete(u)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
42
63
|
end
|
|
43
64
|
|
|
44
65
|
def connected_users
|
|
45
|
-
_user_state_map.keys
|
|
66
|
+
@_user_state_map.keys
|
|
46
67
|
end
|
|
47
68
|
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
|
|
69
|
+
def origin_user
|
|
70
|
+
port_data[:as]
|
|
71
|
+
end
|
|
51
72
|
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
def all_user_tags(user = nil)
|
|
74
|
+
user ||= origin_user
|
|
75
|
+
raw_ports = @_user_state_map[user]&.[](:port_tokens) || []
|
|
76
|
+
tags = Set.new
|
|
77
|
+
raw_ports.each do |ptok|
|
|
78
|
+
tags.merge(port_data(ptok)&.[](:tags) || [])
|
|
54
79
|
end
|
|
80
|
+
tags
|
|
55
81
|
end
|
|
56
82
|
|
|
57
|
-
def
|
|
58
|
-
|
|
83
|
+
def _apply_port_scope(user: nil, tag: nil, **kwargs)
|
|
84
|
+
if user && tag
|
|
85
|
+
user_tags = all_user_tags(user) || []
|
|
86
|
+
throw :abort unless user_tags.include?(tag)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
super(tag: user || tag, **kwargs)
|
|
59
90
|
end
|
|
60
91
|
|
|
61
92
|
private
|
|
62
93
|
|
|
63
|
-
def _user_state_transaction(user =
|
|
94
|
+
def _user_state_transaction(user = origin_user)
|
|
64
95
|
return unless user.present?
|
|
65
96
|
@_user_map_mutex.synchronize do
|
|
66
97
|
usm = @_user_state_map[user]
|
data/lib/cable_room/room.rb
CHANGED
|
@@ -5,16 +5,18 @@ module CableRoom
|
|
|
5
5
|
eager_autoload do
|
|
6
6
|
autoload :Base
|
|
7
7
|
|
|
8
|
-
# autoload :Ports
|
|
9
8
|
autoload :Callbacks
|
|
10
9
|
autoload :Threading
|
|
11
10
|
autoload :ChannelAdapter
|
|
12
|
-
|
|
11
|
+
|
|
13
12
|
autoload :Lifecycle
|
|
14
13
|
autoload :Reaping
|
|
14
|
+
autoload :InputHandling
|
|
15
15
|
|
|
16
|
-
autoload :
|
|
16
|
+
autoload :PortScoping
|
|
17
|
+
autoload :PortManagement
|
|
17
18
|
autoload :UserManagement
|
|
19
|
+
autoload :Broadcasting
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
end
|
|
@@ -28,11 +28,6 @@ module CableRoom
|
|
|
28
28
|
}
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
if blk
|
|
32
|
-
raise ArgumentError, "Cannot specify both a block and `on_opened:`" if kwargs[:on_opened]
|
|
33
|
-
kwargs[:on_opened] = blk
|
|
34
|
-
end
|
|
35
|
-
|
|
36
31
|
as = respond_to?(:current_user) ? current_user : nil if as == :not_given
|
|
37
32
|
|
|
38
33
|
if as
|
|
@@ -40,7 +35,7 @@ module CableRoom
|
|
|
40
35
|
kwargs[:extra][:as] = as
|
|
41
36
|
end
|
|
42
37
|
|
|
43
|
-
RoomMembership.new(self, room_class, room_key, **kwargs)
|
|
38
|
+
RoomMembership.new(self, room_class, room_key, **kwargs, &blk)
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
def ping_room_memberships
|
|
@@ -61,7 +56,9 @@ module CableRoom
|
|
|
61
56
|
on_closed: nil,
|
|
62
57
|
on_opened: nil,
|
|
63
58
|
on_message: nil,
|
|
64
|
-
|
|
59
|
+
tags: [],
|
|
60
|
+
extra: nil,
|
|
61
|
+
&preconfigure
|
|
65
62
|
)
|
|
66
63
|
@token = SecureRandom.hex(16)
|
|
67
64
|
@has_left = false
|
|
@@ -75,6 +72,7 @@ module CableRoom
|
|
|
75
72
|
@on_closed = on_closed
|
|
76
73
|
@on_message = on_message
|
|
77
74
|
|
|
75
|
+
@tags = Array(tags).map(&:to_sym)
|
|
78
76
|
@extra = extra
|
|
79
77
|
|
|
80
78
|
@cable_channel._room_memberships << self
|
|
@@ -89,7 +87,22 @@ module CableRoom
|
|
|
89
87
|
handle_received_message(message)
|
|
90
88
|
end
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
# Listen to user-specific channel
|
|
91
|
+
if extra && extra[:as]
|
|
92
|
+
stream_port(extra[:as]) do |message|
|
|
93
|
+
handle_received_message(message)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
@tags.each do |tag|
|
|
98
|
+
stream_port(tag) do |message|
|
|
99
|
+
handle_received_message(message)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
preconfigure&.call(self)
|
|
104
|
+
|
|
105
|
+
transmit_port_connected
|
|
93
106
|
|
|
94
107
|
maybe_provision_room
|
|
95
108
|
end
|
|
@@ -107,7 +120,7 @@ module CableRoom
|
|
|
107
120
|
def ping!
|
|
108
121
|
return if left?
|
|
109
122
|
|
|
110
|
-
self << { type: '
|
|
123
|
+
self << { type: 'port_ping' }
|
|
111
124
|
maybe_provision_room
|
|
112
125
|
end
|
|
113
126
|
|
|
@@ -116,7 +129,7 @@ module CableRoom
|
|
|
116
129
|
|
|
117
130
|
close_streamed_ports!
|
|
118
131
|
@cable_channel._room_memberships.delete(self)
|
|
119
|
-
self << { type: '
|
|
132
|
+
self << { type: 'port_disconnected' }
|
|
120
133
|
@has_left = true
|
|
121
134
|
@on_closed&.call(self)
|
|
122
135
|
end
|
|
@@ -139,7 +152,7 @@ module CableRoom
|
|
|
139
152
|
|
|
140
153
|
case message['type']
|
|
141
154
|
when 'room_opened'
|
|
142
|
-
|
|
155
|
+
transmit_port_connected
|
|
143
156
|
@on_opened&.call(self)
|
|
144
157
|
when 'room_closed'
|
|
145
158
|
@on_closed&.call(self)
|
|
@@ -153,8 +166,11 @@ module CableRoom
|
|
|
153
166
|
|
|
154
167
|
private
|
|
155
168
|
|
|
156
|
-
def
|
|
157
|
-
msg = {
|
|
169
|
+
def transmit_port_connected
|
|
170
|
+
msg = {
|
|
171
|
+
type: 'port_connected',
|
|
172
|
+
tags: @tags,
|
|
173
|
+
}
|
|
158
174
|
msg[:extra] = ::ActiveJob::Arguments.serialize([@extra]) if @extra
|
|
159
175
|
self << msg
|
|
160
176
|
end
|
data/lib/cable_room/version.rb
CHANGED