anycable-rails-core 1.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +203 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +106 -0
  5. data/lib/action_cable/subscription_adapter/any_cable.rb +40 -0
  6. data/lib/action_cable/subscription_adapter/anycable.rb +10 -0
  7. data/lib/anycable/rails/action_cable_ext/channel.rb +51 -0
  8. data/lib/anycable/rails/action_cable_ext/connection.rb +90 -0
  9. data/lib/anycable/rails/action_cable_ext/remote_connections.rb +13 -0
  10. data/lib/anycable/rails/channel_state.rb +108 -0
  11. data/lib/anycable/rails/compatibility/rubocop/config/default.yml +14 -0
  12. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/instance_vars.rb +50 -0
  13. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/periodical_timers.rb +29 -0
  14. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/stream_from.rb +100 -0
  15. data/lib/anycable/rails/compatibility/rubocop.rb +27 -0
  16. data/lib/anycable/rails/compatibility.rb +63 -0
  17. data/lib/anycable/rails/config.rb +19 -0
  18. data/lib/anycable/rails/connection.rb +211 -0
  19. data/lib/anycable/rails/connection_factory.rb +44 -0
  20. data/lib/anycable/rails/connections/persistent_session.rb +40 -0
  21. data/lib/anycable/rails/connections/serializable_identification.rb +46 -0
  22. data/lib/anycable/rails/connections/session_proxy.rb +81 -0
  23. data/lib/anycable/rails/middlewares/executor.rb +31 -0
  24. data/lib/anycable/rails/middlewares/log_tagging.rb +21 -0
  25. data/lib/anycable/rails/rack.rb +56 -0
  26. data/lib/anycable/rails/railtie.rb +92 -0
  27. data/lib/anycable/rails/version.rb +7 -0
  28. data/lib/anycable/rails.rb +76 -0
  29. data/lib/anycable-rails.rb +3 -0
  30. data/lib/generators/anycable/download/USAGE +14 -0
  31. data/lib/generators/anycable/download/download_generator.rb +85 -0
  32. data/lib/generators/anycable/setup/USAGE +2 -0
  33. data/lib/generators/anycable/setup/setup_generator.rb +300 -0
  34. data/lib/generators/anycable/setup/templates/Procfile.dev.tt +6 -0
  35. data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +48 -0
  36. data/lib/generators/anycable/setup/templates/config/cable.yml.tt +11 -0
  37. data/lib/generators/anycable/setup/templates/config/initializers/anycable.rb.tt +9 -0
  38. data/lib/generators/anycable/with_os_helpers.rb +55 -0
  39. metadata +128 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7bc0b1eac8c453d0054d508826fd33e58b32684c89694fbbc393d2796db8f0c1
4
+ data.tar.gz: 82ff10fabf21471a9fdcc14e6d76d294902b89372002734538b66e1e7569ab1d
5
+ SHA512:
6
+ metadata.gz: 53cda30136d94edc95e319a0e80bed3ce19716d15dd0e69eae0fc14ffb0c45d58ec0fb466bece171736f4821a7aeeba6ec774c228e8915deb7b2eea01fed1565
7
+ data.tar.gz: 2787f8c23179f2283fe9b68982f0e3f0ea8fde5222ef97dba7294464523d8968f57f1c71f166f0d44583047747bbd40433e7603afb07c45f3b58eac98bba3cf4
data/CHANGELOG.md ADDED
@@ -0,0 +1,203 @@
1
+ # Change log
2
+
3
+ ## master
4
+
5
+ ## 1.4.0 (2023-07-07)
6
+
7
+ - Add HTTP RPC integration. ([@palkan][])
8
+
9
+ Specify `http_rpc_mounth_path` in your `anycable.yml` to enable HTTP RPC.
10
+
11
+ - Fix `anycable:download` command. ([@palkan][])
12
+
13
+ Detect MacOS arm64, create target bin path if it doesn't exist.
14
+
15
+ ## 1.3.7 (2023-02-28)
16
+
17
+ - Fix `anycable` gem dependency constraints.
18
+
19
+ - Require Ruby 2.7+.
20
+
21
+ ## 1.3.6 (2023-02-28)
22
+
23
+ - Handle `nil` streams gracefully. ([@palkan][])
24
+
25
+ - Report exceptions via the `Rails.error.report` interface. ([@palkan][])
26
+
27
+ ## 1.3.5 (2023-01-04)
28
+
29
+ - Make misconfiguration error more informative. ([@palkan][])
30
+
31
+ ## 1.3.4 (2022-06-28)
32
+
33
+ - Add support and backport for Connection command callbacks. ([@palkan][])
34
+
35
+ ## 1.3.3 (2022-04-20)
36
+
37
+ - Added `sid` (unique connection identifier) field to the `welcome` message if present. ([@palkan][])
38
+
39
+ - Fixed handling Ruby Logger incompatible loggers. ([@palkan][])
40
+
41
+ ## 1.3.2 (2022-03-04)
42
+
43
+ - Allow Ruby 2.6.
44
+
45
+ ## 1.3.1 (2022-02-28)
46
+
47
+ - Fix Action Cable Channel patch to not change methods signatures. ([@palkan][])
48
+
49
+ Otherwise it could lead to conflicts with other patches.
50
+
51
+ ## 1.3.0 (2022-02-21)
52
+
53
+ - Introduce `AnyCable::Rails.extend_adapter!` to make any pubsub adapter AnyCable-compatible. ([@palkan][])
54
+
55
+ - Refactored Action Cable patching to preserve original functionality and avoid monkey-patching collisions. ([@palkan][])
56
+
57
+ ## 1.2.1 (2022-01-31)
58
+
59
+ - Add a temporary fix to be compatible with `sentry-rails`. ([@palkan][])
60
+
61
+ See [#165](https://github.com/anycable/anycable-rails/issues/165).
62
+
63
+ - Run embedded RPC server only if `any_cable` adapter is used for Action Cable. ([@palkan][])
64
+
65
+ ## 1.2.0 (2021-12-21) 🎄
66
+
67
+ - Drop Rails 5 support.
68
+
69
+ - Drop Ruby 2.6 support.
70
+
71
+ ## 1.1.4 (2021-11-11)
72
+
73
+ - Added `Connection#state_attr_accessor`. ([@palkan][])
74
+
75
+ ## 1.1.3 (2021-10-11)
76
+
77
+ - Relax Action Cable dependency. ([@palkan][])
78
+
79
+ Action Cable 5.1 is allowed (though not recommended).
80
+
81
+ ## 1.1.2 (2021-06-23)
82
+
83
+ - Bring back dependency on `anycable` (instead of `anycable-core`). ([@palkan][])
84
+
85
+ Make it easier to get started by adding just a single gem.
86
+
87
+ ## 1.1.1 (2021-06-08)
88
+
89
+ - Updated documentation links in the generator. ([@palkan][])
90
+
91
+ ## 1.1.0 🚸 (2021-06-01)
92
+
93
+ - No changes since 1.1.0.rc1.1.
94
+
95
+ ## 1.1.0.rc1.1 (2021-05-12)
96
+
97
+ - Fixed config loading regression introduced in 1.1.0.rc1.
98
+
99
+ ## 1.1.0.rc1 (2021-05-12)
100
+
101
+ - Adding `anycable` or `grpc` gem as an explicit dependency is required.
102
+
103
+ Now, `anycable-rails` depends on `anycable-core`, which doesn't include gRPC server implementation.
104
+ You should either add `anycable` or `grpc` (>= 1.37) gem as an explicit dependency.
105
+
106
+ - Add option to embed AnyCable RPC into a Rails server process. ([@palkan][])
107
+
108
+ Set `embedded: true` in the configuration to launch RPC along with `rails s` (only for Rails 6.1+).
109
+
110
+ - **Ruby >= 2.6** is required.
111
+ - **Rails >= 6.0** is required.
112
+
113
+ ## 1.0.7 (2021-03-05)
114
+
115
+ - Ruby 3 compatibility. ([@palkan][])
116
+
117
+ ## 1.0.6 (2021-02-25)
118
+
119
+ - Keep an explicit list of instance vars to ignore in compatibility checks. ([@palkan][])
120
+
121
+ You can ignore custom vars by adding them to the list: `AnyCable::Compatibility::IGNORE_INSTANCE_VARS << :@my_var`.
122
+
123
+ ## 1.0.5 (2021-02-24)
124
+
125
+ - Fixed bug with compatibility false negatives in development. ([@palkan][])
126
+
127
+ See [#151](https://github.com/anycable/anycable-rails/issues/151).
128
+
129
+ ## 1.0.4 (2020-10-02)
130
+
131
+ - Relax Rails dependencies. ([@palkan][])
132
+
133
+ Only add `actioncable` and `globalid` as runtime dependencies, not the whole `rails`.
134
+
135
+ ## 1.0.3 (2020-09-16)
136
+
137
+ - Fixed bug with building a request object when session store is absent. ([@palkan][])
138
+
139
+ ## 1.0.2 (2020-09-08)
140
+
141
+ - Added missing channel state support to `#unsubscribed` callbacks. ([@palkan][])
142
+
143
+ ## 1.0.1 (2020-07-07)
144
+
145
+ - Fixed patching Action Cable testing classes. ([@palkan][])
146
+
147
+ ## 1.0.0 (2020-07-01)
148
+
149
+ - Support `rescue_from` in connections (Rails 6.1). ([@palkan][])
150
+
151
+ - Make AnyCable patches compatible with Action Cable testing. ([@palkan][])
152
+
153
+ - Do not add localhost `redis_url` to `anycable.yml` when Docker development method is chosen in `anycable:setup`. ([@palkan][])
154
+
155
+ - Fix connection identifiers deserialization regression. ([@palkan][])
156
+
157
+ Using non-strings or non-GlobalId-encoded objects was broken.
158
+
159
+ - Improve `anycable:setup` generator. ([@palkan][])
160
+
161
+ Update Docker snippet, do not enable persistent sessions automatically,
162
+ fix setting `config.action_cable.url` in environment configuration.
163
+
164
+ - Add `state_attr_accessor` for channels. ([@palkan][])
165
+
166
+ Just like `attr_accessor` but "persists" the state between RPC calls.
167
+
168
+ - Add `Channel#stop_stream_from` support. ([@palkan][])
169
+
170
+ - Add `RemoteConnections` support. ([@palkan][])
171
+
172
+ - Add `AnyCable::Rails.enabled?` method which returns true if Action Cable uses AnyCable adapter. ([@palkan][])
173
+
174
+ - Add `anycable:download` generator to download `anycable-go` binary. ([@palkan][])
175
+
176
+ - **Ruby 2.5+ is required**. ([@palkan][])
177
+
178
+ - Support `disconnect` messages. ([@palkan][])
179
+
180
+ Added in Rails 6 (see [PR#34194](https://github.com/rails/rails/pull/34194)).
181
+
182
+ - Add ability to persist _dirty_ `request.session` between RPC calls. ([@palkan][])
183
+
184
+ This feature emulates the Action Cable behaviour where it's possible to use `request.session` as a shared Hash-like store.
185
+ This could be used by some applications (e.g., [StimulusReflex](https://github.com/hopsoft/stimulus_reflex)-based).
186
+
187
+ You must turn this feature on by setting `persistent_session_enabled: true` in the AnyCable configuration.
188
+
189
+ - Add ability to use Rack middlewares when build a request for a connection. ([@bibendi][])
190
+
191
+ - Add set up generator to configure a Rails application by running `bin/rails g anycable:setup`. ([@bibendi][])
192
+
193
+ - Require a minimum version of Ruby when installing the gem. ([@bibendi][])
194
+
195
+ - Add ability to develop the gem with Docker. ([@bibendi][])
196
+
197
+ See [Changelog](https://github.com/anycable/anycable-rails/blob/0-6-stable/CHANGELOG.md) for versions <1.0.0.
198
+
199
+ [@palkan]: https://github.com/palkan
200
+ [@alekseyl]: https://github.com/alekseyl
201
+ [@DmitryTsepelev]: https://github.com/DmitryTsepelev
202
+ [@sponomarev]: https://github.com/sponomarev
203
+ [@bibendi]: https://github.com/bibendi
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017-2023 palkan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ [![Gem Version](https://badge.fury.io/rb/anycable-rails.svg)](https://rubygems.org/gems/anycable-rails)
2
+ [![Build](https://github.com/anycable/anycable-rails/workflows/Build/badge.svg)](https://github.com/anycable/anycable-rails/actions)
3
+ [![Documentation](https://img.shields.io/badge/docs-link-brightgreen.svg)](https://docs.anycable.io/rails/getting_started)
4
+
5
+ # AnyCable Rails
6
+
7
+ AnyCable allows you to use any WebSocket server (written in any language) as a replacement for built-in Rails Action Cable server.
8
+
9
+ With AnyCable you can use channels, client-side JS, broadcasting - (almost) all that you can do with Action Cable.
10
+
11
+ You can even use Action Cable in development and not be afraid of [compatibility issues](#compatibility).
12
+
13
+ 💾 [Example Application](https://github.com/anycable/anycable_rails_demo)
14
+
15
+ 📑 [Documentation](https://docs.anycable.io/rails/getting_started).
16
+
17
+ > [AnyCable Pro](https://docs.anycable.io/pro) has been launched 🚀
18
+
19
+ <a href="https://evilmartians.com/">
20
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
21
+
22
+ ## Requirements
23
+
24
+ - Ruby >= 2.6
25
+ - Rails >= 6.0 (Rails 5.1 could work but we're no longer enforce compatibility on CI)
26
+ - Redis (see [other options](https://github.com/anycable/anycable/issues/2) for broadcasting)
27
+
28
+ ## Usage
29
+
30
+ Add `anycable-rails` gem to your Gemfile:
31
+
32
+ ```ruby
33
+ gem "anycable-rails"
34
+
35
+ # when using Redis broadcast adapter
36
+ gem "redis", ">= 4.0"
37
+ ```
38
+
39
+ ### Interactive set up
40
+
41
+ After the gem was installed, you can run an interactive wizard to configure your Rails application for using with AnyCable by running a generator:
42
+
43
+ ```sh
44
+ bundle exec rails g anycable:setup
45
+ ```
46
+
47
+ ### Manual set up
48
+
49
+ Specify AnyCable subscription adapter for Action Cable:
50
+
51
+ ```yml
52
+ # config/cable.yml
53
+ development:
54
+ adapter: any_cable # or anycable
55
+
56
+ production:
57
+ adapter: any_cable
58
+ ```
59
+
60
+ and specify AnyCable WebSocket server URL:
61
+
62
+ ```ruby
63
+ # For development it's likely the localhost
64
+
65
+ # config/environments/development.rb
66
+ config.action_cable.url = "ws://localhost:8080/cable"
67
+
68
+ # For production it's likely to have a sub-domain and secure connection
69
+
70
+ # config/environments/production.rb
71
+ config.action_cable.url = "wss://ws.example.com/cable"
72
+ ```
73
+
74
+ Then, run AnyCable RPC server:
75
+
76
+ ```sh
77
+ $ bundle exec anycable
78
+
79
+ # don't forget to provide Rails env
80
+
81
+ $ RAILS_ENV=production bundle exec anycable
82
+ ```
83
+
84
+ And, finally, run AnyCable WebSocket server, e.g. [anycable-go](https://docs.anycable.io/anycable-go/getting_started):
85
+
86
+ ```sh
87
+ anycable-go --host=localhost --port=8080
88
+ ```
89
+
90
+ See [documentation](https://docs.anycable.io/rails/getting_started) for more information on AnyCable + Rails usage.
91
+
92
+ ## Action Cable Compatibility
93
+
94
+ See [documentation](https://docs.anycable.io/rails/compatibility).
95
+
96
+ ## Contributing
97
+
98
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/anycable/anycable-rails](https://github.com/anycable/anycable-rails).
99
+
100
+ ## License
101
+
102
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
103
+
104
+ ## Security Contact
105
+
106
+ To report a security vulnerability, please contact us at `anycable@evilmartians.com`. We will coordinate the fix and disclosure.
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "anycable-rails"
4
+
5
+ module ActionCable
6
+ module SubscriptionAdapter
7
+ # AnyCable subscription adapter delegates broadcasts
8
+ # to AnyCable
9
+ class AnyCable < Base
10
+ ACTION_CABLE_SERVER_ERROR_MESSAGE = <<~STR
11
+ Looks like you're trying to connect to Rails Action Cable server, not an AnyCable one.
12
+
13
+ Please make sure your client is configured to connect to AnyCable server.
14
+
15
+ See https://docs.anycable.io/troubleshooting
16
+ STR
17
+
18
+ def initialize(*)
19
+ end
20
+
21
+ def broadcast(channel, payload)
22
+ ::AnyCable.broadcast(channel, payload)
23
+ end
24
+
25
+ def subscribe(*)
26
+ raise NotImplementedError, ACTION_CABLE_SERVER_ERROR_MESSAGE
27
+ end
28
+
29
+ def unsubscribe(*)
30
+ raise NotImplementedError, ACTION_CABLE_SERVER_ERROR_MESSAGE
31
+ end
32
+
33
+ def shutdown
34
+ # nothing to do
35
+ # we only need this method for development,
36
+ # 'cause code reloading triggers `server.restart` -> `pubsub.shutdown`
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "any_cable"
4
+
5
+ module ActionCable
6
+ module SubscriptionAdapter
7
+ # Aliasing adapter
8
+ Anycable = AnyCable
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_cable"
4
+
5
+ ActionCable::Channel::Base.prepend(Module.new do
6
+ def subscribe_to_channel
7
+ super unless anycabled? && !@__anycable_subscribing__
8
+ end
9
+
10
+ def handle_subscribe
11
+ @__anycable_subscribing__ = true
12
+ subscribe_to_channel
13
+ ensure
14
+ @__anycable_subscribing__ = false
15
+ end
16
+
17
+ def start_periodic_timers
18
+ super unless anycabled?
19
+ end
20
+
21
+ def stop_periodic_timers
22
+ super unless anycabled?
23
+ end
24
+
25
+ def stream_from(broadcasting, _callback = nil, **)
26
+ return super unless anycabled?
27
+
28
+ broadcasting = String(broadcasting)
29
+
30
+ connection.anycable_socket.subscribe identifier, broadcasting
31
+ end
32
+
33
+ def stop_stream_from(broadcasting)
34
+ return super unless anycabled?
35
+
36
+ connection.anycable_socket.unsubscribe identifier, broadcasting
37
+ end
38
+
39
+ def stop_all_streams
40
+ return super unless anycabled?
41
+
42
+ connection.anycable_socket.unsubscribe_from_all identifier
43
+ end
44
+
45
+ private
46
+
47
+ def anycabled?
48
+ # Use instance variable check here for testing compatibility
49
+ connection.instance_variable_defined?(:@anycable_socket)
50
+ end
51
+ end)
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_cable"
4
+ require "anycable/rails/connections/serializable_identification"
5
+
6
+ ActionCable::Connection::Base.include(AnyCable::Rails::Connections::SerializableIdentification)
7
+ ActionCable::Connection::Base.prepend(Module.new do
8
+ attr_reader :anycable_socket
9
+ attr_accessor :anycable_request_builder
10
+
11
+ # In AnyCable, we lazily populate env by passing it through the middleware chain,
12
+ # so we access it via #request
13
+ def env
14
+ return super unless anycabled?
15
+
16
+ request.env
17
+ end
18
+
19
+ def anycabled?
20
+ @anycable_socket
21
+ end
22
+
23
+ private
24
+
25
+ def request
26
+ return super unless anycabled?
27
+
28
+ @request ||= anycable_request_builder.build_rack_request(@env)
29
+ end
30
+ end)
31
+
32
+ # Backport command callbacks: https://github.com/rails/rails/pull/44696
33
+ unless ActionCable::Connection::Base.respond_to?(:before_command)
34
+ ActionCable::Connection::Base.include ActiveSupport::Callbacks
35
+ ActionCable::Connection::Base.define_callbacks :command
36
+ ActionCable::Connection::Base.extend(Module.new do
37
+ def before_command(*methods, &block)
38
+ set_callback(:command, :before, *methods, &block)
39
+ end
40
+
41
+ def after_command(*methods, &block)
42
+ set_callback(:command, :after, *methods, &block)
43
+ end
44
+
45
+ def around_command(*methods, &block)
46
+ set_callback(:command, :around, *methods, &block)
47
+ end
48
+ end)
49
+
50
+ ActionCable::Connection::Base.prepend(Module.new do
51
+ def dispatch_websocket_message(websocket_message)
52
+ return super unless websocket.alive?
53
+
54
+ handle_channel_command(decode(websocket_message))
55
+ end
56
+
57
+ def handle_channel_command(payload)
58
+ run_callbacks :command do
59
+ subscriptions.execute_command payload
60
+ end
61
+ end
62
+ end)
63
+ end
64
+
65
+ # Trigger autoload
66
+ test_case_defined = false
67
+
68
+ begin
69
+ ActionCable::Connection::TestCase # rubocop:disable Lint/Void
70
+ test_case_defined = true
71
+ rescue NameError
72
+ end
73
+
74
+ # Backport: https://github.com/rails/rails/pull/45445
75
+ if test_case_defined && !ActionCable::Connection::TestConnection.method_defined?(:transmissions)
76
+ ActionCable::Connection::TestConnection.prepend(Module.new do
77
+ attr_reader :transmissions
78
+
79
+ def initialize(*)
80
+ super
81
+
82
+ @transmissions = []
83
+ @subscriptions = ActionCable::Connection::Subscriptions.new(self)
84
+ end
85
+
86
+ def transmit(cable_message)
87
+ transmissions << cable_message.with_indifferent_access
88
+ end
89
+ end)
90
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_cable/remote_connections"
4
+
5
+ ActionCable::RemoteConnections::RemoteConnection.include(AnyCable::Rails::Connections::SerializableIdentification)
6
+
7
+ ActionCable::RemoteConnections::RemoteConnection.prepend(Module.new do
8
+ def disconnect(reconnect: true)
9
+ # Legacy Action Cable functionality if case we're not fully migrated yet
10
+ super() unless AnyCable::Rails.enabled?
11
+ ::AnyCable.broadcast_adapter.broadcast_command("disconnect", identifier: identifiers_json, reconnect: reconnect)
12
+ end
13
+ end)
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCable
4
+ module Rails
5
+ module ChannelState
6
+ module ClassMethods
7
+ def state_attr_accessor(*names)
8
+ names.each do |name|
9
+ channel_state_attributes << name
10
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
11
+ def #{name}
12
+ return @#{name} if instance_variable_defined?(:@#{name})
13
+ @#{name} = AnyCable::Rails.deserialize(__istate__["#{name}"], json: true) if anycabled?
14
+ end
15
+
16
+ def #{name}=(val)
17
+ __istate__["#{name}"] = AnyCable::Rails.serialize(val, json: true) if anycabled?
18
+ instance_variable_set(:@#{name}, val)
19
+ end
20
+ RUBY
21
+ end
22
+ end
23
+
24
+ def channel_state_attributes
25
+ return @channel_state_attributes if instance_variable_defined?(:@channel_state_attributes)
26
+
27
+ @channel_state_attributes =
28
+ if superclass.respond_to?(:channel_state_attributes)
29
+ superclass.channel_state_attributes.dup
30
+ else
31
+ []
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.included(base)
37
+ base.extend ClassMethods
38
+ end
39
+
40
+ # Make it possible to provide istate explicitly for a channel instance
41
+ attr_writer :__istate__
42
+
43
+ def __istate__
44
+ @__istate__ ||= connection.anycable_socket.istate
45
+ end
46
+ end
47
+
48
+ module ConnectionState
49
+ module ClassMethods
50
+ def state_attr_accessor(*names)
51
+ names.each do |name|
52
+ connection_state_attributes << name
53
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
54
+ def #{name}
55
+ return @#{name} if instance_variable_defined?(:@#{name})
56
+ @#{name} = AnyCable::Rails.deserialize(__cstate__["#{name}"], json: true) if anycabled?
57
+ end
58
+
59
+ def #{name}=(val)
60
+ __cstate__["#{name}"] = AnyCable::Rails.serialize(val, json: true) if anycabled?
61
+ instance_variable_set(:@#{name}, val)
62
+ end
63
+ RUBY
64
+ end
65
+ end
66
+
67
+ def connection_state_attributes
68
+ return @connection_state_attributes if instance_variable_defined?(:@connection_state_attributes)
69
+
70
+ @connection_state_attributes =
71
+ if superclass.respond_to?(:connection_state_attributes)
72
+ superclass.connection_state_attributes.dup
73
+ else
74
+ []
75
+ end
76
+ end
77
+ end
78
+
79
+ def self.included(base)
80
+ base.extend ClassMethods
81
+ end
82
+
83
+ # Make it possible to provide istate explicitly for a connection instance
84
+ attr_writer :__cstate__
85
+
86
+ def __cstate__
87
+ @__cstate__ ||= anycable_socket.cstate
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ if ActiveSupport::VERSION::MAJOR < 6
94
+ # `state_attr_accessor` must be available in Action Cable
95
+ ActiveSupport.on_load(:action_cable) do
96
+ ::ActionCable::Connection::Base.include(AnyCable::Rails::ConnectionState)
97
+ ::ActionCable::Channel::Base.include(AnyCable::Rails::ChannelState)
98
+ end
99
+ else
100
+ # `state_attr_accessor` must be available in Action Cable
101
+ ActiveSupport.on_load(:action_cable_connection) do
102
+ ::ActionCable::Connection::Base.include(AnyCable::Rails::ConnectionState)
103
+ end
104
+
105
+ ActiveSupport.on_load(:action_cable_channel) do
106
+ ::ActionCable::Channel::Base.include(AnyCable::Rails::ChannelState)
107
+ end
108
+ end
@@ -0,0 +1,14 @@
1
+ AnyCable/InstanceVars:
2
+ Enabled: true
3
+ Include:
4
+ - "**/channels/**/*.rb"
5
+
6
+ AnyCable/StreamFrom:
7
+ Enabled: true
8
+ Include:
9
+ - "**/channels/**/*.rb"
10
+
11
+ AnyCable/PeriodicalTimers:
12
+ Enabled: true
13
+ Include:
14
+ - "**/channels/**/*.rb"