actioncable-next 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/CHANGELOG.md +8 -0
- data/README.md +22 -0
- data/lib/action_cable/channel/streams.rb +12 -1
- data/lib/action_cable/connection/base.rb +5 -1
- data/lib/action_cable/connection/internal_channel.rb +1 -1
- data/lib/action_cable/server/configuration.rb +3 -0
- data/lib/action_cable/server/connections.rb +8 -6
- data/lib/action_cable/server/socket.rb +6 -0
- data/lib/action_cable/subscription_adapter/subscriber_map.rb +16 -1
- data/lib/action_cable.rb +1 -0
- data/lib/actioncable-next.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5831ed0f565c3bc58899a26ec3097bf47ea7cb518f380e0db05a8bad6fcc5dd
|
4
|
+
data.tar.gz: 92aae3e36883530c9b51ee7acdb0e7df231aed27d60b5f8a4d31426c7158822e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef8e96d02d595e9004acc936acc8c116d1ac846664dbdf3455b0cfb8f872ba3dbbecfd3dfb3772a53b796505c02a592947bf838690d9c5f0b2c844a40e70e7a4
|
7
|
+
data.tar.gz: bf36b4a97cd76f02d4162a70d27751ae15333d5c1c23654199bd59214dc061b0b779aa9dd28c73ca080f075fc5bc8972db86d6e98ce137c4b78f330bd3e5540c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
## main
|
4
4
|
|
5
|
+
## 0.2.0
|
6
|
+
|
7
|
+
- Performance: store connections in a Hash, not an Array.
|
8
|
+
|
9
|
+
- Add `Connection#broadcast` as an interface for broadcasting from channels.
|
10
|
+
|
11
|
+
- Add `config.fastlane_broadcasts_enabled` to opt-in for optimized broadcasts (no double JSON encoding).
|
12
|
+
|
5
13
|
## 0.1.2
|
6
14
|
|
7
15
|
- Added a hack to prevent third-party extensions from changing the methods visibility.
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@ This gem provides the functionality of the _server adapterization_ PR: [rails/ra
|
|
4
4
|
|
5
5
|
See the PR description for more information on the purpose of this refactoring.
|
6
6
|
|
7
|
+
There are also some additional improvements added on top of the PR (see below).
|
8
|
+
|
7
9
|
## Usage
|
8
10
|
|
9
11
|
Add this line to your application's Gemfile **before Rails or Action Cable**:
|
@@ -26,3 +28,23 @@ by adding the following line to your `spec/rails_helper.rb`:
|
|
26
28
|
require "rspec/rails"
|
27
29
|
require "action_cable/next/rspec"
|
28
30
|
```
|
31
|
+
|
32
|
+
### New features
|
33
|
+
|
34
|
+
#### `ActionCable.server.config.fastlane_broadcasts_enabled = true`
|
35
|
+
|
36
|
+
This option allows you to enable the _fast lane_ for broadcasting messages. When enabled, messages sent via `ActionCable.server.broadcast` are only decoded-encoded from/to JSON once per channel identifier and not for every connected client. This significantly reduces the broadcasting latency (up to 2x faster).
|
37
|
+
|
38
|
+
#### `Connection#broadcast`
|
39
|
+
|
40
|
+
You can now broadcast message from connection or channel instances using the connection `#broadcast` method. For example:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class TestChannel < ActionCable::Channel::Base
|
44
|
+
def notify_all(data)
|
45
|
+
connection.broadcast("testing-#{test_id}", data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
The purpose of this interface is to avoid direct usage of `server` or `ActionCable.server` in channels code.
|
@@ -157,10 +157,21 @@ module ActionCable
|
|
157
157
|
# Always wrap the outermost handler to invoke the user handler on the worker
|
158
158
|
# pool rather than blocking the event loop.
|
159
159
|
def worker_pool_stream_handler(broadcasting, user_handler, coder: nil)
|
160
|
+
if !user_handler && !coder && connection.config.fastlane_broadcasts_enabled
|
161
|
+
return opt_worker_pool_stream_handler(broadcasting)
|
162
|
+
end
|
163
|
+
|
160
164
|
handler = stream_handler(broadcasting, user_handler, coder: coder)
|
161
165
|
|
162
166
|
-> message do
|
163
|
-
connection.perform_work handler, :call, message
|
167
|
+
connection.perform_work handler, :call, message.data
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Optimized stream handler that avoids double JSON encoding/decoding on broadcast
|
172
|
+
def opt_worker_pool_stream_handler(broadcasting)
|
173
|
+
-> (message) do
|
174
|
+
connection.raw_transmit message.encoded_for(@identifier)
|
164
175
|
end
|
165
176
|
end
|
166
177
|
|
@@ -62,7 +62,7 @@ module ActionCable
|
|
62
62
|
attr_reader :subscriptions, :logger
|
63
63
|
private attr_reader :server, :socket
|
64
64
|
|
65
|
-
delegate :pubsub, :executor, :config, to: :server
|
65
|
+
delegate :pubsub, :executor, :config, :broadcast, to: :server
|
66
66
|
delegate :env, :request, :protocol, :perform_work, to: :socket, allow_nil: true
|
67
67
|
|
68
68
|
def initialize(server, socket)
|
@@ -117,6 +117,10 @@ module ActionCable
|
|
117
117
|
socket.transmit(data)
|
118
118
|
end
|
119
119
|
|
120
|
+
def raw_transmit(data) # :nodoc:
|
121
|
+
socket.raw_transmit(data)
|
122
|
+
end
|
123
|
+
|
120
124
|
# Close the connection.
|
121
125
|
def close(reason: nil, reconnect: true)
|
122
126
|
transmit(
|
@@ -18,7 +18,7 @@ module ActionCable
|
|
18
18
|
|
19
19
|
def subscribe_to_internal_channel
|
20
20
|
if connection_identifier.present?
|
21
|
-
callback = -> (message) { process_internal_message ActiveSupport::JSON.decode(message) }
|
21
|
+
callback = -> (message) { process_internal_message ActiveSupport::JSON.decode(message.data) }
|
22
22
|
@_internal_subscriptions ||= []
|
23
23
|
@_internal_subscriptions << [ internal_channel, callback ]
|
24
24
|
|
@@ -19,6 +19,7 @@ module ActionCable
|
|
19
19
|
attr_accessor :precompile_assets
|
20
20
|
attr_accessor :health_check_path, :health_check_application
|
21
21
|
attr_writer :pubsub_adapter
|
22
|
+
attr_accessor :fastlane_broadcasts_enabled
|
22
23
|
|
23
24
|
def initialize
|
24
25
|
@log_tags = []
|
@@ -31,6 +32,8 @@ module ActionCable
|
|
31
32
|
@allow_same_origin_as_host = true
|
32
33
|
@filter_parameters = []
|
33
34
|
|
35
|
+
@fastlane_broadcasts_enabled = false
|
36
|
+
|
34
37
|
@health_check_application = ->(env) {
|
35
38
|
[200, { Rack::CONTENT_TYPE => "text/html", "date" => Time.now.httpdate }, []]
|
36
39
|
}
|
@@ -13,16 +13,18 @@ module ActionCable
|
|
13
13
|
module Connections # :nodoc:
|
14
14
|
BEAT_INTERVAL = 3
|
15
15
|
|
16
|
-
def
|
17
|
-
@
|
16
|
+
def connections_map
|
17
|
+
@connections_map ||= {}
|
18
18
|
end
|
19
19
|
|
20
|
+
def connections = connections_map.values
|
21
|
+
|
20
22
|
def add_connection(connection)
|
21
|
-
|
23
|
+
connections_map[connection.object_id] = connection
|
22
24
|
end
|
23
25
|
|
24
26
|
def remove_connection(connection)
|
25
|
-
|
27
|
+
connections_map.delete connection.object_id
|
26
28
|
end
|
27
29
|
|
28
30
|
# WebSocket connection implementations differ on when they'll mark a connection
|
@@ -32,12 +34,12 @@ module ActionCable
|
|
32
34
|
# disconnect.
|
33
35
|
def setup_heartbeat_timer
|
34
36
|
@heartbeat_timer ||= executor.timer(BEAT_INTERVAL) do
|
35
|
-
executor.post {
|
37
|
+
executor.post { connections_map.each_value(&:beat) }
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
def open_connections_statistics
|
40
|
-
|
42
|
+
connections_map.each_value.map(&:statistics)
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -47,6 +47,12 @@ module ActionCable
|
|
47
47
|
websocket.transmit encode(cable_message)
|
48
48
|
end
|
49
49
|
|
50
|
+
def raw_transmit(message)
|
51
|
+
return unless websocket.alive?
|
52
|
+
|
53
|
+
websocket.transmit message
|
54
|
+
end
|
55
|
+
|
50
56
|
# Close the WebSocket connection.
|
51
57
|
def close(...)
|
52
58
|
websocket.close(...) if websocket.alive?
|
@@ -5,6 +5,19 @@
|
|
5
5
|
module ActionCable
|
6
6
|
module SubscriptionAdapter
|
7
7
|
class SubscriberMap
|
8
|
+
class Message < Struct.new(:data)
|
9
|
+
def initialize(...)
|
10
|
+
super
|
11
|
+
@cache = Concurrent::Map.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def encoded_for(identifier)
|
15
|
+
@cache.compute_if_absent(identifier) do
|
16
|
+
ActiveSupport::JSON.encode({ identifier: identifier, message: ActiveSupport::JSON.decode(data) })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
8
21
|
def initialize
|
9
22
|
@subscribers = Hash.new { |h, k| h[k] = [] }
|
10
23
|
@sync = Mutex.new
|
@@ -41,8 +54,10 @@ module ActionCable
|
|
41
54
|
@subscribers[channel].dup
|
42
55
|
end
|
43
56
|
|
57
|
+
msg = Message.new(message)
|
58
|
+
|
44
59
|
list.each do |subscriber|
|
45
|
-
invoke_callback(subscriber,
|
60
|
+
invoke_callback(subscriber, msg)
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
data/lib/action_cable.rb
CHANGED
data/lib/actioncable-next.rb
CHANGED
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actioncable-next
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pratik Naik
|
8
8
|
- David Heinemeier Hansson
|
9
9
|
- Vladimir Dementyev
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-
|
13
|
+
date: 2025-02-04 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -167,10 +167,10 @@ licenses:
|
|
167
167
|
- MIT
|
168
168
|
metadata:
|
169
169
|
bug_tracker_uri: https://github.com/anycable/actioncable-next
|
170
|
-
changelog_uri: https://github.com/anycable/actioncable-next/blob/v0.
|
170
|
+
changelog_uri: https://github.com/anycable/actioncable-next/blob/v0.2.0/CHANGELOG.md
|
171
171
|
source_code_uri: https://github.com/anycable/actioncable-next
|
172
172
|
rubygems_mfa_required: 'true'
|
173
|
-
post_install_message:
|
173
|
+
post_install_message:
|
174
174
|
rdoc_options: []
|
175
175
|
require_paths:
|
176
176
|
- lib
|
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
186
|
version: '0'
|
187
187
|
requirements: []
|
188
188
|
rubygems_version: 3.5.22
|
189
|
-
signing_key:
|
189
|
+
signing_key:
|
190
190
|
specification_version: 4
|
191
191
|
summary: Next-gen version of Action Cable
|
192
192
|
test_files: []
|