pakyow-realtime 0.11.3 → 1.0.0.rc1
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 +5 -5
- data/{pakyow-realtime/CHANGELOG.md → CHANGELOG.md} +5 -0
- data/LICENSE +4 -0
- data/{pakyow-realtime/README.md → README.md} +1 -2
- data/lib/pakyow/environment/realtime/config.rb +29 -0
- data/lib/pakyow/realtime/actions/upgrader.rb +29 -0
- data/lib/pakyow/realtime/behavior/config.rb +42 -0
- data/lib/pakyow/realtime/behavior/rendering/install_websocket.rb +57 -0
- data/lib/pakyow/realtime/behavior/serialization.rb +42 -0
- data/lib/pakyow/realtime/behavior/server.rb +42 -0
- data/lib/pakyow/realtime/behavior/silencing.rb +25 -0
- data/lib/pakyow/realtime/channel.rb +23 -0
- data/lib/pakyow/realtime/context.rb +38 -0
- data/lib/pakyow/realtime/framework.rb +49 -0
- data/lib/pakyow/realtime/helpers/broadcasting.rb +13 -0
- data/lib/pakyow/realtime/helpers/socket.rb +13 -0
- data/lib/pakyow/realtime/helpers/subscriptions.rb +35 -0
- data/lib/pakyow/realtime/server/adapters/memory.rb +127 -0
- data/lib/pakyow/realtime/server/adapters/redis.rb +277 -0
- data/lib/pakyow/realtime/server.rb +152 -0
- data/lib/pakyow/realtime/websocket.rb +157 -0
- data/lib/pakyow/realtime.rb +13 -0
- metadata +73 -44
- data/pakyow-realtime/LICENSE +0 -20
- data/pakyow-realtime/lib/pakyow/realtime/config.rb +0 -20
- data/pakyow-realtime/lib/pakyow/realtime/connection.rb +0 -18
- data/pakyow-realtime/lib/pakyow/realtime/context.rb +0 -68
- data/pakyow-realtime/lib/pakyow/realtime/delegate.rb +0 -112
- data/pakyow-realtime/lib/pakyow/realtime/exceptions.rb +0 -6
- data/pakyow-realtime/lib/pakyow/realtime/ext/request.rb +0 -10
- data/pakyow-realtime/lib/pakyow/realtime/helpers.rb +0 -40
- data/pakyow-realtime/lib/pakyow/realtime/hooks.rb +0 -41
- data/pakyow-realtime/lib/pakyow/realtime/message_handler.rb +0 -57
- data/pakyow-realtime/lib/pakyow/realtime/message_handlers/call_route.rb +0 -34
- data/pakyow-realtime/lib/pakyow/realtime/message_handlers/ping.rb +0 -8
- data/pakyow-realtime/lib/pakyow/realtime/redis_subscription.rb +0 -61
- data/pakyow-realtime/lib/pakyow/realtime/registries/redis_registry.rb +0 -107
- data/pakyow-realtime/lib/pakyow/realtime/registries/simple_registry.rb +0 -40
- data/pakyow-realtime/lib/pakyow/realtime/websocket.rb +0 -209
- data/pakyow-realtime/lib/pakyow/realtime.rb +0 -19
- data/pakyow-realtime/lib/pakyow-realtime.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e741f872b4f4c8c70d0b0435f69dea7a686e1d8ba95b3416ae89b8f3a50bd6a2
|
4
|
+
data.tar.gz: da45c2b4b7238ab709aeb7a243d6e2ee3f6869a86fc0d4d99e02a701960cc56a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a44fd08cb285611e91b7129d266885ad30e6cecc02b33ba3b7bbacb36cee82228515437b027f305fa7cedd03af4c0c502be4a3b7d95ba9d0da83d60dc3b31576
|
7
|
+
data.tar.gz: 9524a3586f595db6a0c9d4f9538b9f8424be88aa627f8ad8f91030d1157ef9e84ee242ef9ca48ac2405f443a5a70d8b787e265c60c4ee4ca703064a0fb0dd1c4
|
data/LICENSE
ADDED
@@ -146,8 +146,7 @@ Source code can be downloaded as part of the Pakyow project on Github:
|
|
146
146
|
|
147
147
|
# License
|
148
148
|
|
149
|
-
Pakyow Realtime is
|
150
|
-
License](http://opensource.org/licenses/MIT).
|
149
|
+
Pakyow Realtime is free and open-source under the [LGPLv3 license](https://choosealicense.com/licenses/lgpl-3.0/).
|
151
150
|
|
152
151
|
# Support
|
153
152
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Environment
|
7
|
+
module Realtime
|
8
|
+
module Config
|
9
|
+
extend Support::Extension
|
10
|
+
|
11
|
+
apply_extension do
|
12
|
+
configurable :realtime do
|
13
|
+
setting :server, true
|
14
|
+
|
15
|
+
setting :adapter, :memory
|
16
|
+
setting :adapter_settings, {}
|
17
|
+
|
18
|
+
defaults :production do
|
19
|
+
setting :adapter, :redis
|
20
|
+
setting :adapter_settings do
|
21
|
+
Pakyow.config.redis.to_h
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/message_verifier"
|
4
|
+
|
5
|
+
require "pakyow/realtime/websocket"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
module Realtime
|
9
|
+
module Actions
|
10
|
+
class Upgrader
|
11
|
+
def call(connection)
|
12
|
+
if websocket?(connection)
|
13
|
+
WebSocket.new(connection.verifier.verify(connection.params[:id]), connection)
|
14
|
+
connection.halt
|
15
|
+
end
|
16
|
+
rescue Support::MessageVerifier::TamperedMessage
|
17
|
+
connection.status = 403
|
18
|
+
connection.halt
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def websocket?(connection)
|
24
|
+
connection.path == "/pw-socket"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Realtime
|
7
|
+
module Behavior
|
8
|
+
module Config
|
9
|
+
extend Support::Extension
|
10
|
+
|
11
|
+
apply_extension do
|
12
|
+
configurable :realtime do
|
13
|
+
setting :adapter_settings, {}
|
14
|
+
setting :path, "pw-socket"
|
15
|
+
setting :endpoint
|
16
|
+
setting :log_initial_request, false
|
17
|
+
|
18
|
+
defaults :production do
|
19
|
+
setting :adapter_settings do
|
20
|
+
{ key_prefix: [Pakyow.config.redis.key_prefix, config.name].join("/") }
|
21
|
+
end
|
22
|
+
|
23
|
+
setting :log_initial_request, true
|
24
|
+
end
|
25
|
+
|
26
|
+
configurable :timeouts do
|
27
|
+
# Give sockets 60 seconds to connect before cleaning up their state.
|
28
|
+
#
|
29
|
+
setting :initial, 60
|
30
|
+
|
31
|
+
# When a socket disconnects, keep state around for 24 hours before
|
32
|
+
# cleaning up. This improves the user experience in cases such as
|
33
|
+
# when a browser window is left open on a sleeping computer.
|
34
|
+
#
|
35
|
+
setting :disconnect, 24 * 60 * 60
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
require "pakyow/presenter/view"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
module Realtime
|
9
|
+
module Behavior
|
10
|
+
module Rendering
|
11
|
+
module InstallWebsocket
|
12
|
+
extend Support::Extension
|
13
|
+
|
14
|
+
apply_extension do
|
15
|
+
build do |view|
|
16
|
+
if head = view.head
|
17
|
+
head.append(Support::SafeStringHelpers.html_safe("<meta name=\"pw-socket\" ui=\"socket\">"))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attach do |presenter, app:|
|
22
|
+
presenter.render node: -> {
|
23
|
+
node = object.each_significant_node(:meta).find { |meta_node|
|
24
|
+
meta_node.attributes[:name] == "pw-socket"
|
25
|
+
}
|
26
|
+
|
27
|
+
unless node.nil?
|
28
|
+
Presenter::View.from_object(node)
|
29
|
+
end
|
30
|
+
} do
|
31
|
+
endpoint = app.config.realtime.endpoint
|
32
|
+
|
33
|
+
unless endpoint
|
34
|
+
endpoint = if Pakyow.config.server.proxy
|
35
|
+
# Connect directly to the app in development, since the proxy does not support websocket connections.
|
36
|
+
#
|
37
|
+
File.join("ws://#{Pakyow.config.server.host}:#{Pakyow.config.server.port}", app.config.realtime.path)
|
38
|
+
else
|
39
|
+
File.join("#{presentables[:__ws_protocol]}://#{presentables[:__ws_authority]}", app.config.realtime.path)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
attributes["data-ui"] = "socket(endpoint: #{endpoint}?id=#{presentables[:__verifier].sign(presentables[:__socket_client_id])})"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
expose do |connection|
|
48
|
+
connection.set(:__verifier, connection.verifier)
|
49
|
+
connection.set(:__ws_protocol, connection.secure? ? "wss" : "ws")
|
50
|
+
connection.set(:__ws_authority, connection.authority)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
require "pakyow/support/extension"
|
6
|
+
require "pakyow/support/serializer"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Realtime
|
10
|
+
module Behavior
|
11
|
+
# Persists the in-memory realtime server across restarts.
|
12
|
+
#
|
13
|
+
module Serialization
|
14
|
+
extend Support::Extension
|
15
|
+
|
16
|
+
apply_extension do
|
17
|
+
on "shutdown", priority: :high do
|
18
|
+
if Pakyow.config.realtime.adapter == :memory && instance_variable_defined?(:@websocket_server)
|
19
|
+
realtime_server_serializer.serialize
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
after "boot" do
|
24
|
+
if Pakyow.config.realtime.adapter == :memory
|
25
|
+
realtime_server_serializer.deserialize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private def realtime_server_serializer
|
31
|
+
Support::Serializer.new(
|
32
|
+
@websocket_server.adapter,
|
33
|
+
name: "#{config.name}-realtime",
|
34
|
+
path: File.join(
|
35
|
+
Pakyow.config.root, "tmp", "state"
|
36
|
+
)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/deep_freeze"
|
4
|
+
require "pakyow/support/extension"
|
5
|
+
|
6
|
+
require "pakyow/realtime/server"
|
7
|
+
|
8
|
+
module Pakyow
|
9
|
+
module Realtime
|
10
|
+
module Behavior
|
11
|
+
module Server
|
12
|
+
extend Support::Extension
|
13
|
+
|
14
|
+
apply_extension do
|
15
|
+
extend Support::DeepFreeze
|
16
|
+
unfreezable :websocket_server
|
17
|
+
attr_reader :websocket_server
|
18
|
+
|
19
|
+
after "initialize", priority: :high do
|
20
|
+
@websocket_server = if is_a?(Plugin)
|
21
|
+
parent.websocket_server
|
22
|
+
else
|
23
|
+
Realtime::Server.new(
|
24
|
+
Pakyow.config.realtime.adapter,
|
25
|
+
Pakyow.config.realtime.adapter_settings.to_h.merge(
|
26
|
+
config.realtime.adapter_settings.to_h
|
27
|
+
),
|
28
|
+
config.realtime.timeouts
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
on "shutdown" do
|
34
|
+
if instance_variable_defined?(:@websocket_server)
|
35
|
+
@websocket_server.shutdown
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Realtime
|
7
|
+
module Behavior
|
8
|
+
# Silences asset requests from being logged.
|
9
|
+
#
|
10
|
+
module Silencing
|
11
|
+
extend Support::Extension
|
12
|
+
|
13
|
+
apply_extension do
|
14
|
+
on "load" do
|
15
|
+
unless config.realtime.log_initial_request
|
16
|
+
Pakyow.silence do |connection|
|
17
|
+
connection.path.start_with?(File.join("/", config.realtime.path))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Realtime
|
5
|
+
class Channel
|
6
|
+
class << self
|
7
|
+
def parse(qualified_channel)
|
8
|
+
Channel.new(*qualified_channel.split("::", 2))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :name, :qualifier
|
13
|
+
|
14
|
+
def initialize(channel_name, qualifier = nil)
|
15
|
+
@name, @qualifier = channel_name, qualifier
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
[@name, @qualifier].join("::")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pakyow
|
4
|
+
module Realtime
|
5
|
+
# Deals with realtime connections in context of an app. Instances are
|
6
|
+
# returned by the `socket` helper method during routing.
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
class Context
|
10
|
+
# @api private
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
# Push a message down one or more channels.
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def push(msg, *channels)
|
19
|
+
delegate.push(msg, *channels)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Push a message down a channel directed at a specific client,
|
23
|
+
# identified by key.
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def push_to_key(msg, channel, key, propagated: false)
|
27
|
+
delegate.push_to_key(msg, channel, key, propagated: propagated)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an instance of the connection delegate.
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def delegate
|
34
|
+
Delegate.instance
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/framework"
|
4
|
+
|
5
|
+
require "pakyow/realtime/helpers/broadcasting"
|
6
|
+
require "pakyow/realtime/helpers/subscriptions"
|
7
|
+
require "pakyow/realtime/helpers/socket"
|
8
|
+
|
9
|
+
require "pakyow/realtime/behavior/config"
|
10
|
+
require "pakyow/realtime/behavior/serialization"
|
11
|
+
require "pakyow/realtime/behavior/server"
|
12
|
+
require "pakyow/realtime/behavior/silencing"
|
13
|
+
|
14
|
+
require "pakyow/realtime/actions/upgrader"
|
15
|
+
|
16
|
+
require "pakyow/realtime/behavior/rendering/install_websocket"
|
17
|
+
|
18
|
+
module Pakyow
|
19
|
+
module Realtime
|
20
|
+
class Framework < Pakyow::Framework(:realtime)
|
21
|
+
def boot
|
22
|
+
object.class_eval do
|
23
|
+
register_helper :active, Helpers::Broadcasting
|
24
|
+
register_helper :active, Helpers::Subscriptions
|
25
|
+
register_helper :passive, Helpers::Socket
|
26
|
+
|
27
|
+
# Socket events are triggered on the app.
|
28
|
+
#
|
29
|
+
events :join, :leave
|
30
|
+
|
31
|
+
include Behavior::Config
|
32
|
+
include Behavior::Server
|
33
|
+
include Behavior::Silencing
|
34
|
+
include Behavior::Serialization
|
35
|
+
|
36
|
+
isolated :Renderer do
|
37
|
+
include Behavior::Rendering::InstallWebsocket
|
38
|
+
end
|
39
|
+
|
40
|
+
isolated :Connection do
|
41
|
+
after "initialize" do
|
42
|
+
set(:__socket_client_id, params[:socket_client_id] || Support::MessageVerifier.key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/realtime/channel"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Realtime
|
7
|
+
module Helpers
|
8
|
+
module Subscriptions
|
9
|
+
def subscribe(channel, *qualifiers)
|
10
|
+
channels = if qualifiers.empty?
|
11
|
+
Channel.new(channel)
|
12
|
+
else
|
13
|
+
qualifiers.map { |qualifier|
|
14
|
+
Channel.new(channel, qualifier)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
app.websocket_server.socket_subscribe(socket_client_id, *channels)
|
19
|
+
end
|
20
|
+
|
21
|
+
def unsubscribe(channel, *qualifiers)
|
22
|
+
channels = if qualifiers.empty?
|
23
|
+
Channel.new(channel, "*")
|
24
|
+
else
|
25
|
+
qualifiers.map { |qualifier|
|
26
|
+
Channel.new(channel, qualifier)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
app.websocket_server.socket_unsubscribe(*channels)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "concurrent/array"
|
4
|
+
require "concurrent/hash"
|
5
|
+
require "concurrent/scheduled_task"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
module Realtime
|
9
|
+
class Server
|
10
|
+
module Adapters
|
11
|
+
# Manages websocket channels in memory.
|
12
|
+
#
|
13
|
+
# Great for development, not for use in production!
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class Memory
|
17
|
+
def initialize(server, _config)
|
18
|
+
@server = server
|
19
|
+
|
20
|
+
@socket_ids_by_channel = Concurrent::Hash.new
|
21
|
+
@channels_by_socket_id = Concurrent::Hash.new
|
22
|
+
@expirations_for_socket_id = Concurrent::Hash.new
|
23
|
+
@socket_instances_by_socket_id = Concurrent::Hash.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def connect
|
27
|
+
# intentionally empty
|
28
|
+
end
|
29
|
+
|
30
|
+
def disconnect
|
31
|
+
# intentionally empty
|
32
|
+
end
|
33
|
+
|
34
|
+
def socket_subscribe(socket_id, *channels)
|
35
|
+
channels.each do |channel|
|
36
|
+
channel = channel.to_s.to_sym
|
37
|
+
(@socket_ids_by_channel[channel] ||= Concurrent::Array.new) << socket_id
|
38
|
+
(@channels_by_socket_id[socket_id] ||= Concurrent::Array.new) << channel
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def socket_unsubscribe(*channels)
|
43
|
+
channels.each do |channel|
|
44
|
+
channel = Regexp.new(channel.to_s)
|
45
|
+
|
46
|
+
@socket_ids_by_channel.select { |key|
|
47
|
+
key.to_s.match?(channel)
|
48
|
+
}.each do |key, socket_ids|
|
49
|
+
@socket_ids_by_channel.delete(key)
|
50
|
+
|
51
|
+
socket_ids.each do |socket_id|
|
52
|
+
@channels_by_socket_id[socket_id]&.delete(key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def subscription_broadcast(channel, message)
|
59
|
+
@server.transmit_message_to_connection_ids(message, socket_ids_for_channel(channel))
|
60
|
+
end
|
61
|
+
|
62
|
+
def expire(socket_id, seconds)
|
63
|
+
task = Concurrent::ScheduledTask.execute(seconds) {
|
64
|
+
channels_for_socket_id(socket_id).each do |channel|
|
65
|
+
@channels_by_socket_id.delete(socket_id)
|
66
|
+
@socket_ids_by_channel[channel].delete(socket_id)
|
67
|
+
@socket_instances_by_socket_id.delete(socket_id)
|
68
|
+
end
|
69
|
+
}
|
70
|
+
|
71
|
+
@expirations_for_socket_id[socket_id] ||= []
|
72
|
+
@expirations_for_socket_id[socket_id] << task
|
73
|
+
end
|
74
|
+
|
75
|
+
def persist(socket_id)
|
76
|
+
(@expirations_for_socket_id[socket_id] || []).each(&:cancel)
|
77
|
+
@expirations_for_socket_id.delete(socket_id)
|
78
|
+
end
|
79
|
+
|
80
|
+
def expiring?(socket_id)
|
81
|
+
@expirations_for_socket_id[socket_id]&.any?
|
82
|
+
end
|
83
|
+
|
84
|
+
def current!(socket_id, socket_instance_id)
|
85
|
+
@socket_instances_by_socket_id[socket_id] = socket_instance_id
|
86
|
+
end
|
87
|
+
|
88
|
+
def current?(socket_id, socket_instance_id)
|
89
|
+
@socket_instances_by_socket_id[socket_id] == socket_instance_id
|
90
|
+
end
|
91
|
+
|
92
|
+
SERIALIZABLE_IVARS = %i(
|
93
|
+
@socket_ids_by_channel
|
94
|
+
@channels_by_socket_id
|
95
|
+
@socket_instances_by_socket_id
|
96
|
+
).freeze
|
97
|
+
|
98
|
+
def serialize
|
99
|
+
SERIALIZABLE_IVARS.each_with_object({}) do |ivar, hash|
|
100
|
+
hash[ivar] = instance_variable_get(ivar)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
def socket_ids_for_channel(channel)
|
107
|
+
channel = Regexp.new(channel.to_s)
|
108
|
+
|
109
|
+
@socket_ids_by_channel.select { |key|
|
110
|
+
key.to_s.match?(channel)
|
111
|
+
}.each_with_object([]) do |(_, socket_ids_for_channel), socket_ids|
|
112
|
+
socket_ids.concat(
|
113
|
+
socket_ids_for_channel.reject { |socket_id|
|
114
|
+
expiring?(socket_id)
|
115
|
+
}
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def channels_for_socket_id(socket_id)
|
121
|
+
@channels_by_socket_id[socket_id] || []
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|