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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9aa3fe6a825d58f713ffd71b32b26bd034de7f3175ee6b9505e4f53433f6999
4
- data.tar.gz: 5bea7df4792f6f0bf2ed0847437ac13f23972de50b443854f597b4f9b8b6defa
3
+ metadata.gz: 64b5004bfcc84dfe1543ece45d15e55d3ac076d0df64f92b14da2f2ebcc0fd15
4
+ data.tar.gz: 0e7dc74beaeee2474d7f9bbe4105c27635428e0a10ce1e3cd4780f0fc7ddbf14
5
5
  SHA512:
6
- metadata.gz: 2291b430d4dbfd1072d8dadb1643857e71e84ef749dd08f6bb97168cdb842af6edf6da703d41acc370d9899e0130fffd068ac568a0d5bf269306746e3aeefe11
7
- data.tar.gz: aa8346b8289d1dbe14e606631506ee5a2801cef846a67b13cb0e092806f0da1c6cdf980358b43163c3b2a614fea71bd5f8363383051f741ff39a03794a0e5ff7
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|
@@ -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
@@ -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::Cable
7
- class Socket
8
- def initialize(env, websocket, server, coder: ActiveSupport::JSON)
9
- @env = env
10
- @websocket = websocket
11
- @server = server
12
- @coder = coder
13
-
14
- @output = ::Thread::Queue.new
15
- end
16
-
17
- attr :env
18
-
19
- def logger
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
- ActionDispatch::Request.new(environment || @env)
21
+ @output = ::Thread::Queue.new
31
22
  end
32
- end
33
-
34
- def run(parent: Async::Task.current)
35
- parent.async do
36
- while buffer = @output.pop
37
- # Console.debug(self, "Sending cable data:", buffer, flush: @output.empty?)
38
- @websocket.send_text(buffer)
39
- @websocket.flush if @output.empty?
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
- rescue => error
42
- Console.error(self, "Error while sending cable data:", error)
43
- ensure
44
- unless @websocket.closed?
45
- @websocket.close_write(error)
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
- end
49
-
50
- def transmit(data)
51
- # Console.info(self, "Transmitting data:", data, task: Async::Task.current?)
52
- @output.push(@coder.encode(data))
53
- end
54
-
55
- def close
56
- # Console.info(self, "Closing socket.", task: Async::Task.current?)
57
- @output.close
58
- end
59
-
60
- # This can be called from the work pool, off the event loop.
61
- def perform_work(receiver, ...)
62
- # Console.info(self, "Performing work:", receiver)
63
- receiver.send(...)
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
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2023-2024, by Samuel Williams.
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.0"
10
+ VERSION = "0.3.1"
9
11
  end
10
12
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2023-2024, by Samuel Williams.
3
+ Copyright, 2023-2026, by Samuel Williams.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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.0
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.2'
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: 3.6.7
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