cable_room 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 319532a2546c5bbd96b89ca34c9a44ba963a5bc97bc62e5faacf8417cb815783
4
- data.tar.gz: 2d1c92b8e36af65a69182537ba25b2ba5652569e21d398f9bccbd91011e6e411
3
+ metadata.gz: 4a274c3350a931d2c0260aea67d0474b9297de7201bf5dad12fe2caa0177685d
4
+ data.tar.gz: 20840a647279a6e5f07a4a6bb7aac528543d9cb82c8bfef4fb637b7274fc0a4f
5
5
  SHA512:
6
- metadata.gz: 25afc8414cc55c14d41a72c2d8898c026d442f204744a1a67721e2fd6e6b6b9ea9013bfe727ba98984475c504b00eb95bda324fdf2c60a6e2b9269d5e3fb4e17
7
- data.tar.gz: 903fa66437dec42ba12b87c49a0864b561b0b8b2f302de05f80482d8a086a1e7971ba5f03e04146e4905b6854f017c2d311e222393ba977cca9936d5b656f306
6
+ metadata.gz: 7ad1d254f3f02a6dffc54aa4c40f4f57968c2364a3fe27633af97b0df76513abd4eeff8064f9ba2ce8e1929a9817edf3cf82d7d04270563596da128b74833f88
7
+ data.tar.gz: de1eb655d4f6071f603e0e4fe69ae904bd507c8e3b15108ccd4339838fa1748a244266b406645657bd713b93a4719741045be0b60e50b0ea80ec07ea9e62976f
@@ -25,7 +25,7 @@ module CableRoom
25
25
  protected
26
26
 
27
27
  def _room_channel_class
28
- room_class.channel_class
28
+ room_class::Channel
29
29
  end
30
30
 
31
31
  def _streamed_ports
@@ -13,7 +13,7 @@ module CableRoom
13
13
  lock_info = CableRoom.lock_manager.lock(lock_key, self::LOCK_DURATION.in_milliseconds)
14
14
  return false unless lock_info
15
15
 
16
- vchannel = channel_class.new(
16
+ vchannel = self::Channel.new(
17
17
  lock_info,
18
18
  self,
19
19
  key,
@@ -42,8 +42,7 @@ module CableRoom
42
42
  def periodically(method, every:, &blk)
43
43
  blk ||= method
44
44
  blk = -> { send(method) } unless blk.is_a?(Proc)
45
- # TODO Looking at the docs, this creates a thread for each timer - that seems expensive
46
- channel_class.periodically(every:) do
45
+ self::Channel.periodically(every:) do
47
46
  room.instance_exec(&blk)
48
47
  end
49
48
  end
@@ -5,6 +5,7 @@ module CableRoom
5
5
 
6
6
  def broadcast(message, **kwargs)
7
7
  with_port_scope!(**kwargs) do |client_port: nil|
8
+ client_port = client_port.token if client_port.respond_to?(:token)
8
9
  ports[client_port || self.class::ROOM_OUT_CHANNEL] << message
9
10
  end
10
11
  end
@@ -7,13 +7,9 @@ module CableRoom
7
7
 
8
8
  class_methods do
9
9
  def inherited(subclass)
10
- subclass.const_set(:Channel, Class.new(channel_class))
10
+ subclass.const_set(:Channel, Class.new(Channel))
11
11
  super
12
12
  end
13
-
14
- def channel_class
15
- self::Channel
16
- end
17
13
  end
18
14
  end
19
15
  end
@@ -3,32 +3,12 @@ module CableRoom
3
3
  module PortManagement
4
4
  extend ActiveSupport::Concern
5
5
 
6
+ require_relative 'port_policies'
7
+ include PortPolicies
8
+
6
9
  PORT_TIMEOUT = 30.seconds
7
10
 
8
11
  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 inbound_tag_policy(**kwargs, &blk)
17
- if blk
18
- self._port_policy_blocks = [*(_port_policy_blocks || []), {
19
- **kwargs,
20
- block: blk,
21
- }]
22
- else
23
- @_tag_policy ||= TagPolicy.new().tap do |pol|
24
- (_port_policy_blocks || []).each do |p|
25
- pol.evaluate(**p.except(:block), &p[:block])
26
- end
27
- end
28
- @_tag_policy
29
- end
30
- end
31
-
32
12
  def on_port_connected(...)
33
13
  set_callback(:port_connected, :before, ...)
34
14
  end
@@ -36,11 +16,14 @@ module CableRoom
36
16
  def on_port_disconnected(...)
37
17
  set_callback(:port_disconnected, :after, ...)
38
18
  end
19
+
20
+ def inherited(subclass)
21
+ subclass.const_set(:PortClient, Class.new(PortClient))
22
+ super
23
+ end
39
24
  end
40
25
 
41
26
  included do
42
- class_attribute :_port_policy_blocks, instance_writer: false, default: {}
43
-
44
27
  periodically :check_port_inactivity, every: PORT_TIMEOUT
45
28
 
46
29
  define_callbacks :port_connected, :port_disconnected
@@ -55,239 +38,134 @@ module CableRoom
55
38
  @current_message_origin = previous_mtok
56
39
  end
57
40
  end
58
-
59
- authorize_inbound do |message|
60
- msg_type = message['type'].to_s.underscore.to_sym
61
- next true if %i[port_connected port_disconnected].include?(msg_type)
62
- policy_allows?(msg_type)
63
- end
64
-
65
- inbound_tag_policy(priority: -10) do
66
- allow :*, :connect
67
- end
68
41
  end
69
42
 
70
43
  def initialize(...)
71
44
  super
72
- @port_data = {}
45
+ @_port_clients = {}
73
46
  end
74
47
 
75
48
  def _apply_port_scope(client_port: nil, tag: nil, **kwargs)
76
49
  if client_port && tag
77
- throw :abort unless port_data(client_port)[:tags]&.include?(tag)
50
+ client_port = resolve_client_port(client_port)
51
+ throw :abort unless client_port && client_port[:tags]&.include?(tag)
78
52
  end
79
53
 
80
54
  { client_port: client_port || tag, **kwargs }
81
55
  end
82
56
 
83
57
  def reply(message = nil, **kwargs)
84
- raise ArgumentError, "Can only use reply when handling a message" unless origin_port
58
+ raise ArgumentError, "Can only use reply when handling a message" unless message_origin
85
59
  raise ArgumentError, "Must provide message or block" unless message || block_given?
86
60
  raise ArgumentError, "Cannot specify client_port: when using reply" if kwargs.key?(:client_port)
87
61
 
88
62
  if block_given?
89
- with_port_scope(client_port: origin_port) do
63
+ with_port_scope(client_port: message_origin) do
90
64
  yield
91
65
  end
92
66
  else
93
- broadcast(message, **kwargs, client_port: origin_port)
67
+ broadcast(message, **kwargs, client_port: message_origin)
94
68
  end
95
69
  end
96
70
 
97
71
  protected
98
72
 
99
- def policy_allows?(method)
100
- self.class.inbound_tag_policy.pass?(method, origin_tags)
101
- end
102
-
103
73
  def on_port_disconnected(); end
104
74
 
105
75
  def on_port_connected(); end
106
76
 
107
- def touch_port_activity(mtok = nil)
108
- port_data(mtok)[:last_seen_at] = Time.now
77
+ def touch_port_activity
78
+ message_origin[:last_seen_at] = Time.now
109
79
  end
110
80
 
111
- def port_data(mtok = nil)
112
- mtok ||= @current_message_origin
113
- @port_data[mtok] ||= HashWithIndifferentAccess.new
81
+ def message_origin
82
+ @_port_clients[@current_message_origin]
114
83
  end
115
84
 
116
- def origin_port
117
- @current_message_origin
85
+ def connected_clients
86
+ @_port_clients.values
118
87
  end
119
88
 
120
- def origin_tags
121
- port_data[:tags] || []
122
- end
123
-
124
- def origin_tagged?(tag)
125
- origin_tags.include?(tag)
126
- end
127
-
128
- def tag_origin!(*tags)
129
- port_data[:tags] ||= Set.new
130
- port_data[:tags].merge(tags.flatten.map(&:to_sym))
89
+ def resolve_client_port(client = @current_message_origin)
90
+ return client unless client.is_a?(String)
91
+ @_port_clients[client]
131
92
  end
132
93
 
133
94
  def handle_received_message(message)
134
95
  case message['type']
135
96
  when 'port_connected'
136
- mdata = port_data
137
- mdata[:last_seen_at] = Time.now
138
- touch_port_activity
97
+ message_origin = @_port_clients[@current_message_origin] ||= PortClient.new(@current_message_origin)
98
+
99
+ message_origin.touch_activity!
100
+ message_origin.tag!(message['tags'])
139
101
 
140
- mdata.merge! ::ActiveJob::Arguments.deserialize(message['extra'])[0] if message['extra'].present?
141
- tag_origin!(message['tags'])
102
+ if policy_allows?(message['type'].to_sym)
103
+ message_origin.merge!(::ActiveJob::Arguments.deserialize(message['extra'])[0])
142
104
 
143
- if self.class.inbound_tag_policy.pass?(message['type'].to_sym, origin_tags)
144
105
  run_callbacks :port_connected do
145
106
  on_port_connected
146
107
  end
147
108
  else
148
- @port_data.delete(origin_port)
109
+ @_port_clients.delete(@current_message_origin)
149
110
  end
150
111
  when 'port_disconnected'
151
- if self.class.inbound_tag_policy.pass?(message['type'].to_sym, origin_tags)
112
+ if policy_allows?(message['type'].to_sym)
152
113
  run_callbacks :port_disconnected do
153
114
  on_port_disconnected
154
115
  end
155
116
  end
156
- @port_data.delete(origin_port)
117
+ @_port_clients.delete(@current_message_origin)
157
118
  when 'port_ping'
158
- touch_port_activity
119
+ message_origin&.touch_activity!
159
120
  else
160
121
  super
161
122
  end
162
123
  end
163
124
 
164
125
  def check_port_inactivity
165
- return unless @port_data
126
+ return unless @_port_clients
166
127
 
167
128
  threshold = PORT_TIMEOUT.ago
168
- @port_data.each do |mtok, data|
169
- next unless data[:last_seen_at] && data[:last_seen_at] < threshold
129
+ @_port_clients.each do |mtok, data|
130
+ next if data.recently_seen?
170
131
 
171
132
  run_callbacks :port_disconnected do
172
133
  on_port_disconnected
173
134
  end
174
- @port_data.delete(mtok)
135
+ @_port_clients.delete(mtok)
175
136
  end
176
137
  end
177
138
 
178
- class TagPolicy
179
- ALIASES = {}
139
+ class PortClient
140
+ attr_reader :token
180
141
 
181
- def self.define_tag_alias(key, implies)
182
- Array(implies).each do |i|
183
- ALIASES[i] ||= Set.new
184
- ALIASES[i] << key
185
- end
142
+ def initialize(token)
143
+ @token = token
144
+ @metadata = HashWithIndifferentAccess.new
145
+ @metadata[:tags] = Set.new
146
+ touch_activity!
186
147
  end
187
148
 
188
- define_tag_alias :connect, [:port_connected, :port_ping, :port_disconnected]
149
+ delegate :[], :[]=, to: :@metadata
189
150
 
190
- def initialize()
191
- @policy_rules = []
192
- @fallback_rule = { action: :allow, priority: -100, tag: :*, methods: :* }
193
- append_rule(@fallback_rule)
151
+ def merge!(value)
152
+ @metadata.merge!(value || {})
194
153
  end
195
154
 
196
- def pass?(method, user_tags)
197
- user_tags = Set.new(Array(user_tags).map(&:to_sym))
198
- find_rules_for(method).each do |r|
199
- if r[:tag] == :* || user_tags.include?(r[:tag])
200
- return r[:action] == :allow
201
- end
202
- end
203
-
204
- false
205
- end
206
-
207
- def evaluate(priority: 10, &blk)
208
- @fallback_rule[:action] = :deny if priority > 0
209
-
210
- p = @rule_priority
211
- @rule_priority = priority
212
- instance_exec(&blk)
213
- ensure
214
- @rule_priority = p
215
- end
216
-
217
- protected
218
-
219
- def allow(tag = :*, methods = :*)
220
- append_rule({
221
- action: :allow,
222
- tag: tag,
223
- methods: methods,
224
- })
225
- end
226
-
227
- def deny(tag = :*, methods = :*)
228
- append_rule({
229
- action: :deny,
230
- tag: tag,
231
- methods: methods,
232
- })
233
- end
234
-
235
- private
236
-
237
- def append_rule(rule)
238
- rule[:methods] = Set.new(Array(rule[:methods]).map(&:to_sym))
239
- rule[:priority] ||= @rule_priority || 10
240
- @policy_rules << rule
155
+ def touch_activity!
156
+ self[:last_seen_at] = Time.now
241
157
  end
242
158
 
243
- def find_rules_for(method)
244
- rules ||= select_ruleset(@policy_rules, method).presence
245
- rules ||= []
246
-
247
- rules.sort_by! { |r| -r[:priority] }
248
-
249
- rules
159
+ def recently_seen?
160
+ self[:last_seen_at] && self[:last_seen_at] > PORT_TIMEOUT.ago
250
161
  end
251
162
 
252
- def select_ruleset(set, method)
253
- all_aliases = Set.new
254
- all_aliases << method
255
-
256
- bfs(method) do |m|
257
- all_aliases.merge(ALIASES[m] || [])
258
- ALIASES[m]
259
- end
260
-
261
- all_aliases << :*
262
-
263
- rules = set.select { |r| (Set.new(r[:methods]) & all_aliases).count > 0 }.sort_by { |r| -r[:priority] }
264
-
265
- rules
163
+ def tagged?(tag)
164
+ self[:tags].include?(tag)
266
165
  end
267
166
 
268
- def bfs(base, children = nil)
269
- q = [base]
270
- seen = Set.new
271
- until q.empty?
272
- n = q.shift
273
- next if seen.include?(n)
274
- seen << n
275
-
276
- catch :end_branch do
277
- value = catch :found do
278
- result = yield n
279
- next_set = children ? children.call(n) : Array(result)
280
- (next_set || []).each do |c|
281
- q << c unless seen.include?(c)
282
- end
283
- throw :end_branch
284
- end
285
-
286
- return value || n
287
- end
288
- end
289
-
290
- nil
167
+ def tag!(*tags)
168
+ self[:tags].merge(tags.flatten.map(&:to_sym))
291
169
  end
292
170
  end
293
171
  end
@@ -0,0 +1,168 @@
1
+ module CableRoom
2
+ module Room
3
+ module PortPolicies
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ def inbound_require_tag(tag, **kwargs)
8
+ tag_array = Array(tag).map(&:to_sym)
9
+ authorize_inbound(**kwargs) do |message|
10
+ (tag_array - message_origin[:tags]).empty?
11
+ end
12
+ end
13
+
14
+ def inbound_tag_policy(**kwargs, &blk)
15
+ if blk
16
+ self._port_policy_blocks = [*(_port_policy_blocks || []), {
17
+ **kwargs,
18
+ block: blk,
19
+ }]
20
+ else
21
+ @_tag_policy ||= TagPolicy.new().tap do |pol|
22
+ (_port_policy_blocks || []).each do |p|
23
+ pol.evaluate(**p.except(:block), &p[:block])
24
+ end
25
+ end
26
+ @_tag_policy
27
+ end
28
+ end
29
+ end
30
+
31
+ included do
32
+ class_attribute :_port_policy_blocks, instance_writer: false, default: {}
33
+
34
+ authorize_inbound do |message|
35
+ msg_type = message['type'].to_s.underscore.to_sym
36
+ next true if %i[port_connected port_disconnected].include?(msg_type)
37
+ policy_allows?(msg_type)
38
+ end
39
+
40
+ inbound_tag_policy(priority: -10) do
41
+ allow :*, :connect
42
+ end
43
+ end
44
+
45
+ protected
46
+
47
+ def policy_allows?(method, origin = message_origin)
48
+ self.class.inbound_tag_policy.pass?(method, origin&.[](:tags))
49
+ end
50
+
51
+ class TagPolicy
52
+ ALIASES = {}
53
+
54
+ def self.define_tag_alias(key, implies)
55
+ Array(implies).each do |i|
56
+ ALIASES[i] ||= Set.new
57
+ ALIASES[i] << key
58
+ end
59
+ end
60
+
61
+ define_tag_alias :connect, [:port_connected, :port_ping, :port_disconnected]
62
+
63
+ def initialize()
64
+ @policy_rules = []
65
+ @fallback_rule = { action: :allow, priority: -100, tag: :*, methods: :* }
66
+ append_rule(@fallback_rule)
67
+ end
68
+
69
+ def pass?(method, user_tags)
70
+ user_tags = Set.new(Array(user_tags).map(&:to_sym))
71
+ find_rules_for(method).each do |r|
72
+ if r[:tag] == :* || user_tags.include?(r[:tag])
73
+ return r[:action] == :allow
74
+ end
75
+ end
76
+
77
+ false
78
+ end
79
+
80
+ def evaluate(priority: 10, &blk)
81
+ @fallback_rule[:action] = :deny if priority > 0
82
+
83
+ p = @rule_priority
84
+ @rule_priority = priority
85
+ instance_exec(&blk)
86
+ ensure
87
+ @rule_priority = p
88
+ end
89
+
90
+ protected
91
+
92
+ def allow(tag = :*, methods = :*)
93
+ append_rule({
94
+ action: :allow,
95
+ tag: tag,
96
+ methods: methods,
97
+ })
98
+ end
99
+
100
+ def deny(tag = :*, methods = :*)
101
+ append_rule({
102
+ action: :deny,
103
+ tag: tag,
104
+ methods: methods,
105
+ })
106
+ end
107
+
108
+ private
109
+
110
+ def append_rule(rule)
111
+ rule[:methods] = Set.new(Array(rule[:methods]).map(&:to_sym))
112
+ rule[:priority] ||= @rule_priority || 10
113
+ @policy_rules << rule
114
+ end
115
+
116
+ def find_rules_for(method)
117
+ rules ||= select_ruleset(@policy_rules, method).presence
118
+ rules ||= []
119
+
120
+ rules.sort_by! { |r| -r[:priority] }
121
+
122
+ rules
123
+ end
124
+
125
+ def select_ruleset(set, method)
126
+ all_aliases = Set.new
127
+ all_aliases << method
128
+
129
+ bfs(method) do |m|
130
+ all_aliases.merge(ALIASES[m] || [])
131
+ ALIASES[m]
132
+ end
133
+
134
+ all_aliases << :*
135
+
136
+ rules = set.select { |r| (Set.new(r[:methods]) & all_aliases).count > 0 }.sort_by { |r| -r[:priority] }
137
+
138
+ rules
139
+ end
140
+
141
+ def bfs(base, children = nil)
142
+ q = [base]
143
+ seen = Set.new
144
+ until q.empty?
145
+ n = q.shift
146
+ next if seen.include?(n)
147
+ seen << n
148
+
149
+ catch :end_branch do
150
+ value = catch :found do
151
+ result = yield n
152
+ next_set = children ? children.call(n) : Array(result)
153
+ (next_set || []).each do |c|
154
+ q << c unless seen.include?(c)
155
+ end
156
+ throw :end_branch
157
+ end
158
+
159
+ return value || n
160
+ end
161
+ end
162
+
163
+ nil
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -19,11 +19,17 @@ module CableRoom
19
19
 
20
20
  define_callbacks :user_joined, :user_left
21
21
 
22
+ self::PortClient.class_eval do
23
+ def user
24
+ @metadata[:user]
25
+ end
26
+ end
27
+
22
28
  inbound_tag_policy(priority: -10) do
23
29
  allow :*, :join
24
30
  end
25
31
 
26
- PortManagement::TagPolicy.define_tag_alias :join, [:connect, :user_joined, :user_left]
32
+ PortPolicies::TagPolicy.define_tag_alias :join, [:connect, :user_joined, :user_left]
27
33
  end
28
34
 
29
35
  def initialize(...)
@@ -46,7 +52,7 @@ module CableRoom
46
52
  }
47
53
  is_new = true
48
54
  end
49
- usm[:port_tokens] << origin_port
55
+ usm[:port_tokens] << message_origin.token
50
56
  if is_new
51
57
  run_callbacks :user_joined do
52
58
  on_user_joined
@@ -58,7 +64,7 @@ module CableRoom
58
64
  def _handle_user_cleanup_after_disconnection
59
65
  _user_state_transaction do |usm, u|
60
66
  next unless usm.present?
61
- usm[:port_tokens].delete(origin_port)
67
+ usm[:port_tokens].delete(message_origin.token)
62
68
  if usm[:port_tokens].empty?
63
69
  run_callbacks :user_left do
64
70
  on_user_left
@@ -72,16 +78,16 @@ module CableRoom
72
78
  @_user_state_map.keys
73
79
  end
74
80
 
75
- def origin_user
76
- port_data[:as]
77
- end
78
-
79
81
  def all_user_tags(user = nil)
80
- user ||= origin_user
82
+ user ||= message_origin&.user
83
+ return nil unless user.present?
84
+
81
85
  raw_ports = @_user_state_map[user]&.[](:port_tokens) || []
82
86
  tags = Set.new
83
87
  raw_ports.each do |ptok|
84
- tags.merge(port_data(ptok)&.[](:tags) || [])
88
+ client = resolve_client_port(ptok)
89
+ next unless client
90
+ tags.merge(client[:tags] || [])
85
91
  end
86
92
  tags
87
93
  end
@@ -97,7 +103,7 @@ module CableRoom
97
103
 
98
104
  private
99
105
 
100
- def _user_state_transaction(user = origin_user)
106
+ def _user_state_transaction(user = message_origin&.user)
101
107
  return unless user.present?
102
108
  return unless policy_allows?(:join)
103
109
 
@@ -1,3 +1,3 @@
1
1
  module CableRoom
2
- VERSION = "0.3.0".freeze
2
+ VERSION = "0.4.0".freeze
3
3
  end
@@ -3774,3 +3774,314 @@ Shutting down CableRoom
3774
3774
  [ActionCable] Broadcasting to TestRoom:fb20f57faa7cbd43d9c11fade7aa603a:from_room: {type: "room_closed"}
3775
3775
  [TestRoom d1f3ca2eb83d] Shutting down
3776
3776
  [TestRoom d1f3ca2eb83d] Shutdown complete
3777
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:to_room: {type: "port_connected", tags: [], mtok: "f3b16057c28284e2e8e669f6aa82f71c"}
3778
+ [TestRoom 823eb23206a1] Initializing new TestRoom
3779
+ [TestRoom 823eb23206a1] UUID: 823eb23206a1
3780
+ [TestRoom 823eb23206a1] Key: TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5
3781
+ [TestRoom 823eb23206a1] Ping watchdog
3782
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:from_room: {type: "custom_started"}
3783
+ [TestRoom 823eb23206a1] Started
3784
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:from_room: {type: "room_opened"}
3785
+ [TestRoom 823eb23206a1] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:to_room
3786
+ [TestRoom 823eb23206a1] TestRoom::Channel is transmitting the subscription confirmation
3787
+ [TestRoom 823eb23206a1] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3788
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:to_room: {type: "port_disconnected", mtok: "f3b16057c28284e2e8e669f6aa82f71c"}
3789
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ABC:to_room: {type: "port_connected", tags: [], mtok: "0d3c6b0aba74de7aea969ddec8b4d042"}
3790
+ [TestRoom 823eb23206a1] Received message: {"type" => "port_disconnected", "mtok" => "f3b16057c28284e2e8e669f6aa82f71c"}
3791
+ [TestRoom 4f1dcf21854d] Initializing new TestRoom
3792
+ [TestRoom 4f1dcf21854d] UUID: 4f1dcf21854d
3793
+ [TestRoom 4f1dcf21854d] Key: TestRoom:2d8a1a7a731f0216ABC
3794
+ [TestRoom 4f1dcf21854d] Ping watchdog
3795
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ABC:from_room: {type: "custom_started"}
3796
+ [TestRoom 4f1dcf21854d] Started
3797
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ABC:from_room: {type: "room_opened"}
3798
+ [TestRoom 4f1dcf21854d] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f0216ABC:to_room
3799
+ [TestRoom 4f1dcf21854d] TestRoom::Channel is transmitting the subscription confirmation
3800
+ [TestRoom 4f1dcf21854d] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3801
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ABC:to_room: {type: "port_disconnected", mtok: "0d3c6b0aba74de7aea969ddec8b4d042"}
3802
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f021600ea0ee4980d59bb:to_room: {type: "port_connected", tags: [], mtok: "33e125c52f6ec741b171086f9736cdf2"}
3803
+ [TestRoom 4f1dcf21854d] Received message: {"type" => "port_disconnected", "mtok" => "0d3c6b0aba74de7aea969ddec8b4d042"}
3804
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:to_room: {type: "port_connected", tags: [], mtok: "8a197d37ee4f689a78fd640655e8dca6"}
3805
+ [TestRoom 6ee60144360a] Initializing new TestRoom
3806
+ [TestRoom 6ee60144360a] UUID: 6ee60144360a
3807
+ [TestRoom 6ee60144360a] Key: TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33
3808
+ [TestRoom 6ee60144360a] Ping watchdog
3809
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:from_room: {type: "custom_started"}
3810
+ [TestRoom 6ee60144360a] Started
3811
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:from_room: {type: "room_opened"}
3812
+ [TestRoom 6ee60144360a] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:to_room
3813
+ [TestRoom 6ee60144360a] TestRoom::Channel is transmitting the subscription confirmation
3814
+ [TestRoom 6ee60144360a] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3815
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:to_room: {type: "port_connected", tags: [], mtok: "785b23b0ba036afe8f150b0bc4580bd0"}
3816
+ [TestRoom 6ee60144360a] Received message: {"type" => "port_connected", "tags" => [], "mtok" => "785b23b0ba036afe8f150b0bc4580bd0"}
3817
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:to_room: {type: "port_disconnected", mtok: "785b23b0ba036afe8f150b0bc4580bd0"}
3818
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216A:to_room: {type: "port_connected", tags: [], mtok: "0c5bee0a18fc4b8e56fed5786b71e2fc"}
3819
+ [TestRoom 6ee60144360a] Received message: {"type" => "port_disconnected", "mtok" => "785b23b0ba036afe8f150b0bc4580bd0"}
3820
+ [TestRoom b3676f9c64dd] Initializing new TestRoom
3821
+ [TestRoom b3676f9c64dd] UUID: b3676f9c64dd
3822
+ [TestRoom b3676f9c64dd] Key: TestRoom:2d8a1a7a731f0216A
3823
+ [TestRoom b3676f9c64dd] Ping watchdog
3824
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216A:from_room: {type: "custom_started"}
3825
+ [TestRoom b3676f9c64dd] Started
3826
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216A:from_room: {type: "room_opened"}
3827
+ [TestRoom b3676f9c64dd] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f0216A:to_room
3828
+ [TestRoom b3676f9c64dd] TestRoom::Channel is transmitting the subscription confirmation
3829
+ [TestRoom b3676f9c64dd] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3830
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216B:to_room: {type: "port_connected", tags: [], mtok: "59c629969fdf6f666e622a6643f84d82"}
3831
+ [TestRoom 2ede2abbbfe0] Initializing new TestRoom
3832
+ [TestRoom 2ede2abbbfe0] UUID: 2ede2abbbfe0
3833
+ [TestRoom 2ede2abbbfe0] Key: TestRoom:2d8a1a7a731f0216B
3834
+ [TestRoom 2ede2abbbfe0] Ping watchdog
3835
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216B:from_room: {type: "custom_started"}
3836
+ [TestRoom 2ede2abbbfe0] Started
3837
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216B:from_room: {type: "room_opened"}
3838
+ [TestRoom 2ede2abbbfe0] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f0216B:to_room
3839
+ [TestRoom 2ede2abbbfe0] TestRoom::Channel is transmitting the subscription confirmation
3840
+ [TestRoom 2ede2abbbfe0] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3841
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216B:to_room: {type: "port_disconnected", mtok: "59c629969fdf6f666e622a6643f84d82"}
3842
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02162bf34488744c4883:to_room: {type: "port_connected", tags: [], mtok: "76fe509e62c3e75294f4788a904aacf8"}
3843
+ [TestRoom 2ede2abbbfe0] Received message: {"type" => "port_disconnected", "mtok" => "59c629969fdf6f666e622a6643f84d82"}
3844
+ [TestRoom b37c3a489864] Initializing new TestRoom
3845
+ [TestRoom b37c3a489864] UUID: b37c3a489864
3846
+ [TestRoom b37c3a489864] Key: TestRoom:2d8a1a7a731f02162bf34488744c4883
3847
+ [TestRoom b37c3a489864] Ping watchdog
3848
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02162bf34488744c4883:from_room: {type: "custom_started"}
3849
+ [TestRoom b37c3a489864] Started
3850
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02162bf34488744c4883:from_room: {type: "room_opened"}
3851
+ [TestRoom b37c3a489864] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f02162bf34488744c4883:to_room
3852
+ [TestRoom b37c3a489864] TestRoom::Channel is transmitting the subscription confirmation
3853
+ [TestRoom b37c3a489864] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3854
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02162bf34488744c4883:to_room: {type: "port_disconnected", mtok: "76fe509e62c3e75294f4788a904aacf8"}
3855
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:to_room: {type: "port_connected", tags: [], mtok: "f0d5ca28f79b41ae869eb514358f994d"}
3856
+ [TestRoom b37c3a489864] Received message: {"type" => "port_disconnected", "mtok" => "76fe509e62c3e75294f4788a904aacf8"}
3857
+ [TestRoom 72101f7dd01d] Initializing new TestRoom
3858
+ [TestRoom 72101f7dd01d] UUID: 72101f7dd01d
3859
+ [TestRoom 72101f7dd01d] Key: TestRoom:2d8a1a7a731f0216ebe8247ecd04f602
3860
+ [TestRoom 72101f7dd01d] Ping watchdog
3861
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:from_room: {type: "custom_started"}
3862
+ [TestRoom 72101f7dd01d] Started
3863
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:from_room: {type: "room_opened"}
3864
+ [TestRoom 72101f7dd01d] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:to_room
3865
+ [TestRoom 72101f7dd01d] TestRoom::Channel is transmitting the subscription confirmation
3866
+ [TestRoom 72101f7dd01d] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3867
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:to_room: "KILL"
3868
+ [TestRoom 72101f7dd01d] Received message: "KILL"
3869
+ [TestRoom 72101f7dd01d] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:to_room
3870
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ebe8247ecd04f602:from_room: {type: "room_closed"}
3871
+ [TestRoom 72101f7dd01d] Shutting down
3872
+ [TestRoom 72101f7dd01d] Shutdown complete
3873
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:to_room: {type: "port_connected", tags: [], mtok: "1a8657df22b9b3f87d0e187a3c931bf3"}
3874
+ [TestRoom bf41a49442fc] Initializing new TestRoom
3875
+ [TestRoom bf41a49442fc] UUID: bf41a49442fc
3876
+ [TestRoom bf41a49442fc] Key: TestRoom:2d8a1a7a731f02166abcae7c885d3cc2
3877
+ [TestRoom bf41a49442fc] Ping watchdog
3878
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:from_room: {type: "custom_started"}
3879
+ [TestRoom bf41a49442fc] Started
3880
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:from_room: {type: "room_opened"}
3881
+ [TestRoom bf41a49442fc] TestRoom::Channel is streaming from TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:to_room
3882
+ [TestRoom bf41a49442fc] TestRoom::Channel is transmitting the subscription confirmation
3883
+ [TestRoom bf41a49442fc] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3884
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:to_room: {type: "port_disconnected", mtok: "1a8657df22b9b3f87d0e187a3c931bf3"}
3885
+ [TestRoom bf41a49442fc] Ping watchdog
3886
+ [TestRoom bf41a49442fc] Received message: {"type" => "port_disconnected", "mtok" => "1a8657df22b9b3f87d0e187a3c931bf3"}
3887
+ [TestRoom bf41a49442fc] Watchdog timeout for room TestRoom[2d8a1a7a731f02166abcae7c885d3cc2], shutting down
3888
+ [TestRoom bf41a49442fc] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:to_room
3889
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02166abcae7c885d3cc2:from_room: {type: "room_closed"}
3890
+ [TestRoom bf41a49442fc] Shutting down
3891
+ [TestRoom bf41a49442fc] Shutdown complete
3892
+ Shutting down CableRoom
3893
+ [TestRoom 823eb23206a1] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:to_room
3894
+ [TestRoom 4f1dcf21854d] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f0216ABC:to_room
3895
+ [TestRoom 6ee60144360a] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:to_room
3896
+ [TestRoom b3676f9c64dd] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f0216A:to_room
3897
+ [TestRoom 2ede2abbbfe0] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f0216B:to_room
3898
+ [TestRoom b37c3a489864] TestRoom::Channel stopped streaming from TestRoom:2d8a1a7a731f02162bf34488744c4883:to_room
3899
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02167d8c8e9d5590ec33:from_room: {type: "room_closed"}
3900
+ [TestRoom 6ee60144360a] Shutting down
3901
+ [TestRoom 6ee60144360a] Shutdown complete
3902
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216fb72a9e30d3b18e5:from_room: {type: "room_closed"}
3903
+ [TestRoom 823eb23206a1] Shutting down
3904
+ [TestRoom 823eb23206a1] Shutdown complete
3905
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216ABC:from_room: {type: "room_closed"}
3906
+ [TestRoom 4f1dcf21854d] Shutting down
3907
+ [TestRoom 4f1dcf21854d] Shutdown complete
3908
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216B:from_room: {type: "room_closed"}
3909
+ [TestRoom 2ede2abbbfe0] Shutting down
3910
+ [TestRoom 2ede2abbbfe0] Shutdown complete
3911
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f02162bf34488744c4883:from_room: {type: "room_closed"}
3912
+ [TestRoom b37c3a489864] Shutting down
3913
+ [TestRoom b37c3a489864] Shutdown complete
3914
+ [ActionCable] Broadcasting to TestRoom:2d8a1a7a731f0216A:from_room: {type: "room_closed"}
3915
+ [TestRoom b3676f9c64dd] Shutting down
3916
+ [TestRoom b3676f9c64dd] Shutdown complete
3917
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b302014b31af87967177a:to_room: {type: "port_connected", tags: [], mtok: "2f2213dc7413b8dbfcef352a3a057cd4"}
3918
+ [TestRoom 9ccb05b79cfd] Initializing new TestRoom
3919
+ [TestRoom 9ccb05b79cfd] UUID: 9ccb05b79cfd
3920
+ [TestRoom 9ccb05b79cfd] Key: TestRoom:62970ec7485b302014b31af87967177a
3921
+ [TestRoom 9ccb05b79cfd] Ping watchdog
3922
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b302014b31af87967177a:from_room: {type: "custom_started"}
3923
+ [TestRoom 9ccb05b79cfd] Started
3924
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b302014b31af87967177a:from_room: {type: "room_opened"}
3925
+ [TestRoom 9ccb05b79cfd] TestRoom::Channel is streaming from TestRoom:62970ec7485b302014b31af87967177a:to_room
3926
+ [TestRoom 9ccb05b79cfd] TestRoom::Channel is transmitting the subscription confirmation
3927
+ [TestRoom 9ccb05b79cfd] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3928
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b302014b31af87967177a:to_room: {type: "port_disconnected", mtok: "2f2213dc7413b8dbfcef352a3a057cd4"}
3929
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020ABC:to_room: {type: "port_connected", tags: [], mtok: "323957b6148625d37eae6d68af389ee2"}
3930
+ [TestRoom 9ccb05b79cfd] Received message: {"type" => "port_disconnected", "mtok" => "2f2213dc7413b8dbfcef352a3a057cd4"}
3931
+ [TestRoom fcf730f10996] Initializing new TestRoom
3932
+ [TestRoom fcf730f10996] UUID: fcf730f10996
3933
+ [TestRoom fcf730f10996] Key: TestRoom:62970ec7485b3020ABC
3934
+ [TestRoom fcf730f10996] Ping watchdog
3935
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020ABC:from_room: {type: "custom_started"}
3936
+ [TestRoom fcf730f10996] Started
3937
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020ABC:from_room: {type: "room_opened"}
3938
+ [TestRoom fcf730f10996] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020ABC:to_room
3939
+ [TestRoom fcf730f10996] TestRoom::Channel is transmitting the subscription confirmation
3940
+ [TestRoom fcf730f10996] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3941
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020ABC:to_room: {type: "port_disconnected", mtok: "323957b6148625d37eae6d68af389ee2"}
3942
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d189b52b1b6bb51:to_room: {type: "port_connected", tags: [], mtok: "1d837c9eb1a6407a6dae58d04340fa33"}
3943
+ [TestRoom fcf730f10996] Received message: {"type" => "port_disconnected", "mtok" => "323957b6148625d37eae6d68af389ee2"}
3944
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:to_room: {type: "port_connected", tags: [], mtok: "808fa413d3960c689837e46f78b7fefd"}
3945
+ [TestRoom be84dd707f68] Initializing new TestRoom
3946
+ [TestRoom be84dd707f68] UUID: be84dd707f68
3947
+ [TestRoom be84dd707f68] Key: TestRoom:62970ec7485b3020a7e4d7cc60047033
3948
+ [TestRoom be84dd707f68] Ping watchdog
3949
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:from_room: {type: "custom_started"}
3950
+ [TestRoom be84dd707f68] Started
3951
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:from_room: {type: "room_opened"}
3952
+ [TestRoom be84dd707f68] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020a7e4d7cc60047033:to_room
3953
+ [TestRoom be84dd707f68] TestRoom::Channel is transmitting the subscription confirmation
3954
+ [TestRoom be84dd707f68] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
3955
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:to_room: {type: "port_connected", tags: [], mtok: "656dd78e21c7950c9940680915ee172b"}
3956
+ [TestRoom be84dd707f68] Received message: {"type" => "port_connected", "tags" => [], "mtok" => "656dd78e21c7950c9940680915ee172b"}
3957
+ There was an exception - NameError(uninitialized constant ActiveJob)
3958
+ /Users/eknapp/code/cable_room/lib/cable_room/room/port_management.rb:103:in 'CableRoom::Room::PortManagement#handle_received_message'
3959
+ /Users/eknapp/code/cable_room/lib/cable_room/room/input_handling.rb:52:in 'block (4 levels) in <module:InputHandling>'
3960
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:120:in 'block in ActiveSupport::Callbacks#run_callbacks'
3961
+ /Users/eknapp/code/cable_room/lib/cable_room/room/port_management.rb:36:in 'block (2 levels) in <module:PortManagement>'
3962
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'BasicObject#instance_exec'
3963
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'block in ActiveSupport::Callbacks#run_callbacks'
3964
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:140:in 'ActiveSupport::Callbacks#run_callbacks'
3965
+ /Users/eknapp/code/cable_room/lib/cable_room/room/input_handling.rb:51:in 'block (3 levels) in <module:InputHandling>'
3966
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/channel/streams.rb:198:in 'block in ActionCable::Channel::Streams#stream_decoder'
3967
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/server/worker.rb:60:in 'block in ActionCable::Server::Worker#invoke'
3968
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:120:in 'block in ActiveSupport::Callbacks#run_callbacks'
3969
+ /Users/eknapp/code/cable_room/lib/cable_room/channel_tracker.rb:94:in 'block in <class:ThreadPool>'
3970
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'BasicObject#instance_exec'
3971
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'block in ActiveSupport::Callbacks#run_callbacks'
3972
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/engine.rb:81:in 'block (4 levels) in <class:Engine>'
3973
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/execution_wrapper.rb:91:in 'ActiveSupport::ExecutionWrapper.wrap'
3974
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/engine.rb:76:in 'block (3 levels) in <class:Engine>'
3975
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'BasicObject#instance_exec'
3976
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:129:in 'block in ActiveSupport::Callbacks#run_callbacks'
3977
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/activesupport-8.0.3/lib/active_support/callbacks.rb:140:in 'ActiveSupport::Callbacks#run_callbacks'
3978
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/server/worker.rb:43:in 'ActionCable::Server::Worker#work'
3979
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/actioncable-8.0.3/lib/action_cable/server/worker.rb:59:in 'ActionCable::Server::Worker#invoke'
3980
+ /Users/eknapp/code/cable_room/lib/cable_room/channel_tracker.rb:109:in 'block in CableRoom::ChannelTracker::ThreadPool#async_invoke'
3981
+ /Users/eknapp/code/cable_room/lib/cable_room/channel_base.rb:186:in 'block (2 levels) in CableRoom::ChannelBase#schedule_work'
3982
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:359:in 'Concurrent::RubyThreadPoolExecutor::Worker#run_task'
3983
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:350:in 'block (3 levels) in Concurrent::RubyThreadPoolExecutor::Worker#create_worker'
3984
+ <internal:kernel>:168:in 'Kernel#loop'
3985
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in 'block (2 levels) in Concurrent::RubyThreadPoolExecutor::Worker#create_worker'
3986
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in 'Kernel#catch'
3987
+ /Users/eknapp/.local/share/mise/installs/ruby/3.4.5/lib/ruby/gems/3.4.0/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in 'block in Concurrent::RubyThreadPoolExecutor::Worker#create_worker'
3988
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:to_room: {type: "port_disconnected", mtok: "656dd78e21c7950c9940680915ee172b"}
3989
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020A:to_room: {type: "port_connected", tags: [], mtok: "70835a770436143f154b0a82b2650a95"}
3990
+ [TestRoom be84dd707f68] Received message: {"type" => "port_disconnected", "mtok" => "656dd78e21c7950c9940680915ee172b"}
3991
+ [TestRoom 3b69233bc0b6] Initializing new TestRoom
3992
+ [TestRoom 3b69233bc0b6] UUID: 3b69233bc0b6
3993
+ [TestRoom 3b69233bc0b6] Key: TestRoom:62970ec7485b3020A
3994
+ [TestRoom 3b69233bc0b6] Ping watchdog
3995
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020A:from_room: {type: "custom_started"}
3996
+ [TestRoom 3b69233bc0b6] Started
3997
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020A:from_room: {type: "room_opened"}
3998
+ [TestRoom 3b69233bc0b6] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020A:to_room
3999
+ [TestRoom 3b69233bc0b6] TestRoom::Channel is transmitting the subscription confirmation
4000
+ [TestRoom 3b69233bc0b6] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
4001
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020B:to_room: {type: "port_connected", tags: [], mtok: "48e3b16fb10e1fb72d881e63a75538fb"}
4002
+ [TestRoom e46176f71a3d] Initializing new TestRoom
4003
+ [TestRoom e46176f71a3d] UUID: e46176f71a3d
4004
+ [TestRoom e46176f71a3d] Key: TestRoom:62970ec7485b3020B
4005
+ [TestRoom e46176f71a3d] Ping watchdog
4006
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020B:from_room: {type: "custom_started"}
4007
+ [TestRoom e46176f71a3d] Started
4008
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020B:from_room: {type: "room_opened"}
4009
+ [TestRoom e46176f71a3d] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020B:to_room
4010
+ [TestRoom e46176f71a3d] TestRoom::Channel is transmitting the subscription confirmation
4011
+ [TestRoom e46176f71a3d] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
4012
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020B:to_room: {type: "port_disconnected", mtok: "48e3b16fb10e1fb72d881e63a75538fb"}
4013
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020f9665f1833d09ac1:to_room: {type: "port_connected", tags: [], mtok: "cd5a1af71902d00ccfc26ffb4c360111"}
4014
+ [TestRoom e46176f71a3d] Received message: {"type" => "port_disconnected", "mtok" => "48e3b16fb10e1fb72d881e63a75538fb"}
4015
+ [TestRoom 604eba22ec14] Initializing new TestRoom
4016
+ [TestRoom 604eba22ec14] UUID: 604eba22ec14
4017
+ [TestRoom 604eba22ec14] Key: TestRoom:62970ec7485b3020f9665f1833d09ac1
4018
+ [TestRoom 604eba22ec14] Ping watchdog
4019
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020f9665f1833d09ac1:from_room: {type: "custom_started"}
4020
+ [TestRoom 604eba22ec14] Started
4021
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020f9665f1833d09ac1:from_room: {type: "room_opened"}
4022
+ [TestRoom 604eba22ec14] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020f9665f1833d09ac1:to_room
4023
+ [TestRoom 604eba22ec14] TestRoom::Channel is transmitting the subscription confirmation
4024
+ [TestRoom 604eba22ec14] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
4025
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020f9665f1833d09ac1:to_room: {type: "port_disconnected", mtok: "cd5a1af71902d00ccfc26ffb4c360111"}
4026
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d17e60b8a23b538:to_room: {type: "port_connected", tags: [], mtok: "d976fa3381ab8158aa2f78cfd2de1ad5"}
4027
+ [TestRoom 604eba22ec14] Received message: {"type" => "port_disconnected", "mtok" => "cd5a1af71902d00ccfc26ffb4c360111"}
4028
+ [TestRoom 64056ca6939d] Initializing new TestRoom
4029
+ [TestRoom 64056ca6939d] UUID: 64056ca6939d
4030
+ [TestRoom 64056ca6939d] Key: TestRoom:62970ec7485b30200d17e60b8a23b538
4031
+ [TestRoom 64056ca6939d] Ping watchdog
4032
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d17e60b8a23b538:from_room: {type: "custom_started"}
4033
+ [TestRoom 64056ca6939d] Started
4034
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d17e60b8a23b538:from_room: {type: "room_opened"}
4035
+ [TestRoom 64056ca6939d] TestRoom::Channel is streaming from TestRoom:62970ec7485b30200d17e60b8a23b538:to_room
4036
+ [TestRoom 64056ca6939d] TestRoom::Channel is transmitting the subscription confirmation
4037
+ [TestRoom 64056ca6939d] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
4038
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d17e60b8a23b538:to_room: "KILL"
4039
+ [TestRoom 64056ca6939d] Received message: "KILL"
4040
+ [TestRoom 64056ca6939d] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b30200d17e60b8a23b538:to_room
4041
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b30200d17e60b8a23b538:from_room: {type: "room_closed"}
4042
+ [TestRoom 64056ca6939d] Shutting down
4043
+ [TestRoom 64056ca6939d] Shutdown complete
4044
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020fedd1a59d86ef10f:to_room: {type: "port_connected", tags: [], mtok: "35d2e635586ce33a5003fd7eda4cadd7"}
4045
+ [TestRoom 54562082d444] Initializing new TestRoom
4046
+ [TestRoom 54562082d444] UUID: 54562082d444
4047
+ [TestRoom 54562082d444] Key: TestRoom:62970ec7485b3020fedd1a59d86ef10f
4048
+ [TestRoom 54562082d444] Ping watchdog
4049
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020fedd1a59d86ef10f:from_room: {type: "custom_started"}
4050
+ [TestRoom 54562082d444] Started
4051
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020fedd1a59d86ef10f:from_room: {type: "room_opened"}
4052
+ [TestRoom 54562082d444] TestRoom::Channel is streaming from TestRoom:62970ec7485b3020fedd1a59d86ef10f:to_room
4053
+ [TestRoom 54562082d444] TestRoom::Channel is transmitting the subscription confirmation
4054
+ [TestRoom 54562082d444] Channel.transmit called, ignoring: [{identifier: "Room[]", type: "confirm_subscription"}]
4055
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020fedd1a59d86ef10f:to_room: {type: "port_disconnected", mtok: "35d2e635586ce33a5003fd7eda4cadd7"}
4056
+ [TestRoom 54562082d444] Ping watchdog
4057
+ [TestRoom 54562082d444] Received message: {"type" => "port_disconnected", "mtok" => "35d2e635586ce33a5003fd7eda4cadd7"}
4058
+ [TestRoom 54562082d444] Watchdog timeout for room TestRoom[62970ec7485b3020fedd1a59d86ef10f], shutting down
4059
+ [TestRoom 54562082d444] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020fedd1a59d86ef10f:to_room
4060
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020fedd1a59d86ef10f:from_room: {type: "room_closed"}
4061
+ [TestRoom 54562082d444] Shutting down
4062
+ [TestRoom 54562082d444] Shutdown complete
4063
+ Shutting down CableRoom
4064
+ [TestRoom 9ccb05b79cfd] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b302014b31af87967177a:to_room
4065
+ [TestRoom fcf730f10996] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020ABC:to_room
4066
+ [TestRoom be84dd707f68] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020a7e4d7cc60047033:to_room
4067
+ [TestRoom 3b69233bc0b6] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020A:to_room
4068
+ [TestRoom e46176f71a3d] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020B:to_room
4069
+ [TestRoom 604eba22ec14] TestRoom::Channel stopped streaming from TestRoom:62970ec7485b3020f9665f1833d09ac1:to_room
4070
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020a7e4d7cc60047033:from_room: {type: "room_closed"}
4071
+ [TestRoom be84dd707f68] Shutting down
4072
+ [TestRoom be84dd707f68] Shutdown complete
4073
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b302014b31af87967177a:from_room: {type: "room_closed"}
4074
+ [TestRoom 9ccb05b79cfd] Shutting down
4075
+ [TestRoom 9ccb05b79cfd] Shutdown complete
4076
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020ABC:from_room: {type: "room_closed"}
4077
+ [TestRoom fcf730f10996] Shutting down
4078
+ [TestRoom fcf730f10996] Shutdown complete
4079
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020A:from_room: {type: "room_closed"}
4080
+ [TestRoom 3b69233bc0b6] Shutting down
4081
+ [TestRoom 3b69233bc0b6] Shutdown complete
4082
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020B:from_room: {type: "room_closed"}
4083
+ [TestRoom e46176f71a3d] Shutting down
4084
+ [TestRoom e46176f71a3d] Shutdown complete
4085
+ [ActionCable] Broadcasting to TestRoom:62970ec7485b3020f9665f1833d09ac1:from_room: {type: "room_closed"}
4086
+ [TestRoom 604eba22ec14] Shutting down
4087
+ [TestRoom 604eba22ec14] Shutdown complete
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cable_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan Knapp
@@ -120,6 +120,7 @@ files:
120
120
  - lib/cable_room/room/input_handling.rb
121
121
  - lib/cable_room/room/lifecycle.rb
122
122
  - lib/cable_room/room/port_management.rb
123
+ - lib/cable_room/room/port_policies.rb
123
124
  - lib/cable_room/room/port_scoping.rb
124
125
  - lib/cable_room/room/reaping.rb
125
126
  - lib/cable_room/room/threading.rb