async-cable 0.3.0 → 0.3.1
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
- checksums.yaml.gz.sig +0 -0
- data/lib/async/cable/middleware.rb +12 -1
- data/lib/async/cable/railtie.rb +1 -0
- data/lib/async/cable/socket.rb +72 -54
- data/lib/async/cable/version.rb +4 -2
- data/license.md +1 -1
- data/readme.md +16 -0
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64b5004bfcc84dfe1543ece45d15e55d3ac076d0df64f92b14da2f2ebcc0fd15
|
|
4
|
+
data.tar.gz: 0e7dc74beaeee2474d7f9bbe4105c27635428e0a10ce1e3cd4780f0fc7ddbf14
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87dca6eb0c213a4cc5ee212b302849c90343d8b5f391ec9b01e992320186d2663de721e7e448e0e536d63b7f68b19ea941c23a94cd75933bc2371c8587baa1dc
|
|
7
|
+
data.tar.gz: 25d1d6593eba5a4feb0af33355fda19510abde0f9dddcd0f8833d49c1ae7097af9c938011fac1dbbb4fbf0e77670b7c13ac9238be709c46d203bc6f1a51842cd
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2024, by Samuel Williams.
|
|
4
|
+
# Copyright, 2024-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require "async/websocket/adapters/rack"
|
|
7
7
|
require "action_cable"
|
|
@@ -10,7 +10,12 @@ require_relative "socket"
|
|
|
10
10
|
|
|
11
11
|
module Async
|
|
12
12
|
module Cable
|
|
13
|
+
# Rack middleware that intercepts WebSocket upgrade requests and dispatches them to ActionCable, passing all other requests to the next app in the middleware stack.
|
|
13
14
|
class Middleware
|
|
15
|
+
# Create a new middleware instance.
|
|
16
|
+
# @parameter app [#call] The next Rack application in the middleware stack.
|
|
17
|
+
# @parameter path [String] The URL path that the cable endpoint is mounted at.
|
|
18
|
+
# @parameter server [ActionCable::Server::Base] The ActionCable server to use.
|
|
14
19
|
def initialize(app, path: "/cable", server: ActionCable.server)
|
|
15
20
|
@app = app
|
|
16
21
|
@path = path
|
|
@@ -21,10 +26,16 @@ module Async
|
|
|
21
26
|
|
|
22
27
|
attr :server
|
|
23
28
|
|
|
29
|
+
# Check whether the request path matches the configured cable path.
|
|
30
|
+
# @parameter env [Hash] The Rack environment.
|
|
31
|
+
# @returns [Boolean] Whether the request is for the cable endpoint.
|
|
24
32
|
def valid_path?(env)
|
|
25
33
|
env["PATH_INFO"] == @path
|
|
26
34
|
end
|
|
27
35
|
|
|
36
|
+
# Handle an incoming Rack request. WebSocket upgrade requests on the configured path are handed off to ActionCable; all other requests are forwarded to the next app in the middleware stack.
|
|
37
|
+
# @parameter env [Hash] The Rack environment.
|
|
38
|
+
# @returns [Array] A Rack response triple.
|
|
28
39
|
def call(env)
|
|
29
40
|
if valid_path?(env) and Async::WebSocket::Adapters::Rack.websocket?(env) and allow_request_origin?(env)
|
|
30
41
|
Async::WebSocket::Adapters::Rack.open(env, protocols: @protocols) do |websocket|
|
data/lib/async/cable/railtie.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "middleware"
|
|
|
7
7
|
|
|
8
8
|
module Async
|
|
9
9
|
module Cable
|
|
10
|
+
# Rails integration that automatically inserts {Middleware} into the application middleware stack during initialization.
|
|
10
11
|
class Railtie < Rails::Railtie
|
|
11
12
|
initializer "async.cable.configure_rails_initialization" do |app|
|
|
12
13
|
app.middleware.use Async::Cable::Middleware
|
data/lib/async/cable/socket.rb
CHANGED
|
@@ -1,66 +1,84 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2024, by Samuel Williams.
|
|
4
|
+
# Copyright, 2024-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
-
module Async
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
|
|
14
|
-
@
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@server.logger
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def request
|
|
24
|
-
# Copied from ActionCable::Server::Socket#request
|
|
25
|
-
@request ||= begin
|
|
26
|
-
if defined?(Rails.application) && Rails.application
|
|
27
|
-
environment = Rails.application.env_config.merge(@env)
|
|
28
|
-
end
|
|
6
|
+
module Async
|
|
7
|
+
module Cable
|
|
8
|
+
# Wraps a WebSocket connection to provide the interface expected by ActionCable connections. Buffers outbound messages in a queue and drains them asynchronously so that transmission never blocks the event loop.
|
|
9
|
+
class Socket
|
|
10
|
+
# Create a new socket wrapper.
|
|
11
|
+
# @parameter env [Hash] The Rack environment for the originating request.
|
|
12
|
+
# @parameter websocket [Async::WebSocket::Connection] The underlying WebSocket connection.
|
|
13
|
+
# @parameter server [ActionCable::Server::Base] The ActionCable server instance.
|
|
14
|
+
# @parameter coder [#encode, #decode] Coder used to serialise messages (defaults to `ActiveSupport::JSON`).
|
|
15
|
+
def initialize(env, websocket, server, coder: ActiveSupport::JSON)
|
|
16
|
+
@env = env
|
|
17
|
+
@websocket = websocket
|
|
18
|
+
@server = server
|
|
19
|
+
@coder = coder
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
@output = ::Thread::Queue.new
|
|
31
22
|
end
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
23
|
+
|
|
24
|
+
attr :env
|
|
25
|
+
|
|
26
|
+
# The ActionCable server logger.
|
|
27
|
+
# @returns [Logger]
|
|
28
|
+
def logger
|
|
29
|
+
@server.logger
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Build an `ActionDispatch::Request` from the Rack environment, merging Rails application config when available.
|
|
33
|
+
# @returns [ActionDispatch::Request]
|
|
34
|
+
def request
|
|
35
|
+
# Copied from `ActionCable::Server::Socket#request`:
|
|
36
|
+
@request ||= begin
|
|
37
|
+
if defined?(Rails.application) && Rails.application
|
|
38
|
+
environment = Rails.application.env_config.merge(@env)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
ActionDispatch::Request.new(environment || @env)
|
|
40
42
|
end
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Start an async task that drains the outbound message queue and writes each message to the WebSocket. The task stops when the queue is closed.
|
|
46
|
+
# @parameter parent [Async::Task] The parent task to spawn under.
|
|
47
|
+
# @returns [Async::Task]
|
|
48
|
+
def run(parent: Async::Task.current)
|
|
49
|
+
parent.async do
|
|
50
|
+
while buffer = @output.pop
|
|
51
|
+
# Console.debug(self, "Sending cable data:", buffer, flush: @output.empty?)
|
|
52
|
+
@websocket.send_text(buffer)
|
|
53
|
+
@websocket.flush if @output.empty?
|
|
54
|
+
end
|
|
55
|
+
rescue => error
|
|
56
|
+
Console.error(self, "Error while sending cable data:", error)
|
|
57
|
+
ensure
|
|
58
|
+
unless @websocket.closed?
|
|
59
|
+
@websocket.close_write(error)
|
|
60
|
+
end
|
|
46
61
|
end
|
|
47
62
|
end
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
#
|
|
63
|
-
receiver
|
|
63
|
+
|
|
64
|
+
# Encode and enqueue a message for asynchronous delivery to the client.
|
|
65
|
+
# @parameter data [Object] The data to transmit, which will be encoded by the coder.
|
|
66
|
+
def transmit(data)
|
|
67
|
+
# Console.info(self, "Transmitting data:", data, task: Async::Task.current?)
|
|
68
|
+
@output.push(@coder.encode(data))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Close the outbound queue, causing the drain task to terminate once all pending messages have been sent.
|
|
72
|
+
def close
|
|
73
|
+
# Console.info(self, "Closing socket.", task: Async::Task.current?)
|
|
74
|
+
@output.close
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# This can be called from the work pool, off the event loop.
|
|
78
|
+
def perform_work(receiver, ...)
|
|
79
|
+
# Console.info(self, "Performing work:", receiver)
|
|
80
|
+
receiver.send(...)
|
|
81
|
+
end
|
|
64
82
|
end
|
|
65
83
|
end
|
|
66
84
|
end
|
data/lib/async/cable/version.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2023-
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
|
+
# @namespace
|
|
6
7
|
module Async
|
|
8
|
+
# @namespace
|
|
7
9
|
module Cable
|
|
8
|
-
VERSION = "0.3.
|
|
10
|
+
VERSION = "0.3.1"
|
|
9
11
|
end
|
|
10
12
|
end
|
data/license.md
CHANGED
data/readme.md
CHANGED
|
@@ -36,6 +36,22 @@ We welcome contributions to this project.
|
|
|
36
36
|
4. Push to the branch (`git push origin my-new-feature`).
|
|
37
37
|
5. Create new Pull Request.
|
|
38
38
|
|
|
39
|
+
### Running Tests
|
|
40
|
+
|
|
41
|
+
To run the test suite:
|
|
42
|
+
|
|
43
|
+
``` shell
|
|
44
|
+
bundle exec sus
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Making Releases
|
|
48
|
+
|
|
49
|
+
To make a new release:
|
|
50
|
+
|
|
51
|
+
``` shell
|
|
52
|
+
bundle exec bake gem:release:patch # or minor or major
|
|
53
|
+
```
|
|
54
|
+
|
|
39
55
|
### Developer Certificate of Origin
|
|
40
56
|
|
|
41
57
|
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-cable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -104,14 +104,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
104
104
|
requirements:
|
|
105
105
|
- - ">="
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: '3.
|
|
107
|
+
version: '3.3'
|
|
108
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
requirements:
|
|
110
110
|
- - ">="
|
|
111
111
|
- !ruby/object:Gem::Version
|
|
112
112
|
version: '0'
|
|
113
113
|
requirements: []
|
|
114
|
-
rubygems_version:
|
|
114
|
+
rubygems_version: 4.0.10
|
|
115
115
|
specification_version: 4
|
|
116
116
|
summary: An asynchronous adapter for ActionCable.
|
|
117
117
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|