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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +203 -0
- data/MIT-LICENSE +20 -0
- data/README.md +106 -0
- data/lib/action_cable/subscription_adapter/any_cable.rb +40 -0
- data/lib/action_cable/subscription_adapter/anycable.rb +10 -0
- data/lib/anycable/rails/action_cable_ext/channel.rb +51 -0
- data/lib/anycable/rails/action_cable_ext/connection.rb +90 -0
- data/lib/anycable/rails/action_cable_ext/remote_connections.rb +13 -0
- data/lib/anycable/rails/channel_state.rb +108 -0
- data/lib/anycable/rails/compatibility/rubocop/config/default.yml +14 -0
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/instance_vars.rb +50 -0
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/periodical_timers.rb +29 -0
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/stream_from.rb +100 -0
- data/lib/anycable/rails/compatibility/rubocop.rb +27 -0
- data/lib/anycable/rails/compatibility.rb +63 -0
- data/lib/anycable/rails/config.rb +19 -0
- data/lib/anycable/rails/connection.rb +211 -0
- data/lib/anycable/rails/connection_factory.rb +44 -0
- data/lib/anycable/rails/connections/persistent_session.rb +40 -0
- data/lib/anycable/rails/connections/serializable_identification.rb +46 -0
- data/lib/anycable/rails/connections/session_proxy.rb +81 -0
- data/lib/anycable/rails/middlewares/executor.rb +31 -0
- data/lib/anycable/rails/middlewares/log_tagging.rb +21 -0
- data/lib/anycable/rails/rack.rb +56 -0
- data/lib/anycable/rails/railtie.rb +92 -0
- data/lib/anycable/rails/version.rb +7 -0
- data/lib/anycable/rails.rb +76 -0
- data/lib/anycable-rails.rb +3 -0
- data/lib/generators/anycable/download/USAGE +14 -0
- data/lib/generators/anycable/download/download_generator.rb +85 -0
- data/lib/generators/anycable/setup/USAGE +2 -0
- data/lib/generators/anycable/setup/setup_generator.rb +300 -0
- data/lib/generators/anycable/setup/templates/Procfile.dev.tt +6 -0
- data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +48 -0
- data/lib/generators/anycable/setup/templates/config/cable.yml.tt +11 -0
- data/lib/generators/anycable/setup/templates/config/initializers/anycable.rb.tt +9 -0
- data/lib/generators/anycable/with_os_helpers.rb +55 -0
- 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
|
+
[](https://rubygems.org/gems/anycable-rails)
|
2
|
+
[](https://github.com/anycable/anycable-rails/actions)
|
3
|
+
[](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,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
|