anycable-rails 0.6.5 → 1.0.0.rc3
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 +28 -110
- data/MIT-LICENSE +1 -1
- data/README.md +34 -37
- data/lib/action_cable/subscription_adapter/any_cable.rb +2 -1
- data/lib/anycable/rails.rb +37 -2
- data/lib/anycable/rails/actioncable/channel.rb +4 -0
- data/lib/anycable/rails/actioncable/connection.rb +72 -50
- data/lib/anycable/rails/actioncable/connection/persistent_session.rb +34 -0
- data/lib/anycable/rails/actioncable/connection/serializable_identification.rb +42 -0
- data/lib/anycable/rails/actioncable/remote_connections.rb +11 -0
- data/lib/anycable/rails/actioncable/testing.rb +35 -0
- data/lib/anycable/rails/channel_state.rb +46 -0
- data/lib/anycable/rails/compatibility.rb +7 -10
- data/lib/anycable/rails/compatibility/rubocop.rb +0 -1
- data/lib/anycable/rails/compatibility/rubocop/config/default.yml +3 -1
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/instance_vars.rb +1 -1
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/stream_from.rb +4 -4
- data/lib/anycable/rails/config.rb +8 -4
- data/lib/anycable/rails/rack.rb +56 -0
- data/lib/anycable/rails/railtie.rb +28 -13
- data/lib/anycable/rails/refinements/subscriptions.rb +1 -1
- data/lib/anycable/rails/session_proxy.rb +79 -0
- data/lib/anycable/rails/version.rb +1 -1
- data/lib/generators/anycable/download/USAGE +14 -0
- data/lib/generators/anycable/download/download_generator.rb +83 -0
- data/lib/generators/anycable/setup/USAGE +2 -0
- data/lib/generators/anycable/setup/setup_generator.rb +266 -0
- data/lib/generators/anycable/setup/templates/Procfile.dev +3 -0
- data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +43 -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 +45 -30
- data/lib/anycable/rails/compatibility/rubocop/cops/anycable/remote_disconnect.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ebb4dc7b8483998770f7168cc8884d8a56a0e5376e04550b2f98b1d11046cdf
|
4
|
+
data.tar.gz: 29a21773378af2c3bcc6cd3265d58d028a7bef7b8fc2be13bafda3f54677d8b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cde255681a0348c2edc41fc3130d632f8f17ea02937691b62a388f8a73a699b9e1669e9c7ea55f1dad3a74b6e0d289a3a07feda97adbcbbfcc5d1e316213a704
|
7
|
+
data.tar.gz: 88c80148d66a610472bf8a129a381198d044c89884a800f4209c19f67a6cf527763620bfd804b03cbddb0f6752b6e69c8065e4bfbf1c33da11e66cb7def49688
|
data/CHANGELOG.md
CHANGED
@@ -2,141 +2,59 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
-
## 0.
|
5
|
+
## 1.0.0.rc3 (2020-06-24)
|
6
6
|
|
7
|
-
- Make
|
7
|
+
- Make AnyCable patches compatible with Action Cable testing. ([@palkan][])
|
8
8
|
|
9
|
-
|
10
|
-
couldn't resolve the channel class. Now we return `Channel not found: <name>`.
|
9
|
+
- Do not add localhost `redis_url` to `anycable.yml` when Docker development method is chosen in `anycable:setup`. ([@palkan][])
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
- Add ability to develop the gem with Docker. ([@bibendi][])
|
15
|
-
|
16
|
-
## 0.6.4 (2019-06-26) 👶
|
17
|
-
|
18
|
-
- Fix Compatibility bug when using with AnyCable. ([@palkan][])
|
19
|
-
|
20
|
-
Compatibility patching (with `prepend` + `super`) conflicted with
|
21
|
-
the `ActionCable::Channel::Base` patching in the core functionality (which uses `alias`).
|
22
|
-
|
23
|
-
See [#95](https://github.com/anycable/anycable-rails/issues/95).
|
24
|
-
|
25
|
-
## 0.6.3 (2019-03-26)
|
26
|
-
|
27
|
-
- Fix connection factory reloading for development sake. ([@sponomarev][])
|
28
|
-
|
29
|
-
- Add `:anycable` subscription adapter alias. ([@sponomarev][])
|
30
|
-
|
31
|
-
- Don't set AnyCable connection factory for incompatible adapter ([@sponomarev][])
|
32
|
-
|
33
|
-
`anycable` server won't start with unpatched vanilla `ApplicationCable::Connection`.
|
34
|
-
|
35
|
-
Motivation in [#74](https://github.com/anycable/anycable-rails/issues/74).
|
36
|
-
|
37
|
-
- Fix instance detection inside complex cases in compatibility cops ([@sponomarev][])
|
38
|
-
|
39
|
-
## 0.6.2 (2019-01-10)
|
40
|
-
|
41
|
-
- Fixed `anycable` 0.6.1 compatibility. ([@palkan][])
|
42
|
-
|
43
|
-
- Broadcast logs to STDOUT in development only when server is running. ([@palkan][])
|
44
|
-
|
45
|
-
Fixes #59.
|
46
|
-
|
47
|
-
## 0.6.1 (2018-11-15)
|
48
|
-
|
49
|
-
- Fix regression introduced in [e64a366e](https://github.com/anycable/anycable-rails/commit/e64a366ea21293925e0c5c0b8e6595d65d5d0981#diff-fd0e56a6e825002eac978507c3581af7R14) ([@palkan][])
|
50
|
-
|
51
|
-
`Connection` patch could be loaded after `identify_by` is called, thus breaking
|
52
|
-
identifiers.
|
53
|
-
|
54
|
-
## 0.6.0 (2018-11-15)
|
11
|
+
## 1.0.0.rc2 (2020-06-16)
|
55
12
|
|
56
|
-
|
13
|
+
- Fix connection identifiers deserialization regression. ([@palkan][])
|
57
14
|
|
58
|
-
-
|
15
|
+
Using non-strings or non-GlobalId-encoded objects was broken.
|
59
16
|
|
60
|
-
-
|
17
|
+
- Improve `anycable:setup` generator. ([@palkan][])
|
61
18
|
|
62
|
-
|
19
|
+
Update Docker snippet, do not enable persistent sessions automatically,
|
20
|
+
fix setting `config.action_cable.url` in environment configuration.
|
63
21
|
|
64
|
-
|
22
|
+
## 1.0.0.rc1 (2020-06-10)
|
65
23
|
|
66
|
-
|
24
|
+
- Add `state_attr_accessor` for channels. ([@palkan][])
|
67
25
|
|
68
|
-
|
26
|
+
Just like `attr_accessor` but "persists" the state between RPC calls.
|
69
27
|
|
70
|
-
|
28
|
+
- Add `Channel#stop_stream_from` support. ([@palkan][])
|
71
29
|
|
72
|
-
|
30
|
+
- Add `RemoteConnections` support. ([@palkan][])
|
73
31
|
|
74
|
-
-
|
32
|
+
- Add `AnyCable::Rails.enabled?` method which returns true if Action Cable uses AnyCable adapter. ([@palkan][])
|
75
33
|
|
76
|
-
-
|
34
|
+
- Add `anycable:download` generator to download `anycable-go` binary. ([@palkan][])
|
77
35
|
|
78
|
-
|
79
|
-
the CLI.
|
36
|
+
- **Ruby 2.5+ is required**. ([@palkan][])
|
80
37
|
|
81
|
-
-
|
38
|
+
- Support `disconnect` messages. ([@palkan][])
|
82
39
|
|
83
|
-
|
40
|
+
Added in Rails 6 (see [PR#34194](https://github.com/rails/rails/pull/34194)).
|
84
41
|
|
85
|
-
|
42
|
+
- Add ability to persist _dirty_ `request.session` between RPC calls. ([@palkan][])
|
86
43
|
|
87
|
-
|
44
|
+
This feature emulates the Action Cable behaviour where it's possible to use `request.session` as a shared Hash-like store.
|
45
|
+
This could be used by some applications (e.g., [StimulusReflex](https://github.com/hopsoft/stimulus_reflex)-based).
|
88
46
|
|
89
|
-
|
47
|
+
You must turn this feature on by setting `persistent_session_enabled: true` in the AnyCable configuration.
|
90
48
|
|
91
|
-
|
49
|
+
- Add ability to use Rack middlewares when build a request for a connection. ([@bibendi][])
|
92
50
|
|
93
|
-
|
51
|
+
- Add set up generator to configure a Rails application by running `bin/rails g anycable:setup`. ([@bibendi][])
|
94
52
|
|
95
|
-
-
|
96
|
-
|
97
|
-
Should always be `true`, we do not expect a failure here.
|
98
|
-
|
99
|
-
## 0.5.2
|
100
|
-
|
101
|
-
- Add config/anycable.yml to Rails generator. ([@alekseyl][])
|
102
|
-
|
103
|
-
## 0.5.1
|
104
|
-
|
105
|
-
- Improve Rails integration. ([@palkan][])
|
106
|
-
|
107
|
-
Log to STDOUT in development.
|
108
|
-
Make order of initializers more deterministic.
|
109
|
-
Show warning if AnyCable is loaded after application initialization.
|
110
|
-
|
111
|
-
## 0.5.0
|
112
|
-
|
113
|
-
- [#17](https://github.com/anycable/anycable-rails/issues/17) Refactor logging. ([@palkan][])
|
114
|
-
|
115
|
-
Use Rails logger everywhere.
|
116
|
-
|
117
|
-
Add access logs ([anycable/anycable#20](https://github.com/anycable/anycable/issues/20)).
|
118
|
-
|
119
|
-
## 0.4.7
|
120
|
-
|
121
|
-
- Minor fixes. ([@palkan][])
|
122
|
-
|
123
|
-
## 0.4.6
|
124
|
-
|
125
|
-
- Disable mounting default Action Cable server when AnyCable is loaded. ([@palkan][])
|
126
|
-
|
127
|
-
## 0.4.5
|
128
|
-
|
129
|
-
- Handle tagged logger. ([@palkan][])
|
130
|
-
|
131
|
-
Ignore tagged logger features ('cause we do not have _persistent_ logger).
|
132
|
-
|
133
|
-
## 0.4.4
|
134
|
-
|
135
|
-
- Fix bug with ActiveRecord connections (https://github.com/anycable/anycable/issues/9). ([@palkan][])
|
53
|
+
- Require a minimum version of Ruby when installing the gem. ([@bibendi][])
|
136
54
|
|
137
|
-
|
55
|
+
- Add ability to develop the gem with Docker. ([@bibendi][])
|
138
56
|
|
139
|
-
-
|
57
|
+
See [Changelog](https://github.com/anycable/anycable-rails/blob/0-6-stable/CHANGELOG.md) for versions <1.0.0.
|
140
58
|
|
141
59
|
[@palkan]: https://github.com/palkan
|
142
60
|
[@alekseyl]: https://github.com/alekseyl
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
[](https://gitpitch.com/anycable/anycable/master?grs=github)
|
1
|
+
[](https://gitpitch.com/anycable/anycable/master?grs=github)
|
2
|
+
[](https://rubygems.org/gems/anycable-rails)
|
3
|
+
[](https://github.com/anycable/anycable-rails/actions)
|
2
4
|
[](https://gitter.im/anycable/Lobby)
|
3
|
-
[](https://docs.anycable.io/#/ruby/rails)
|
5
|
+
[](https://docs.anycable.io/v1/#/ruby/rails)
|
4
6
|
|
5
7
|
# AnyCable Rails
|
6
8
|
|
@@ -10,27 +12,23 @@ With AnyCable you can use channels, client-side JS, broadcasting - (almost) all
|
|
10
12
|
|
11
13
|
You can even use Action Cable in development and not be afraid of [compatibility issues](#compatibility).
|
12
14
|
|
13
|
-
|
15
|
+
**Important** This is a readme for the upcoming v1.0 release. For v0.6.x see the readme from the [0-6-stable](https://github.com/anycable/anycable-rails/tree/0-6-stable) branch.
|
14
16
|
|
15
|
-
|
17
|
+
<!-- 💾 [Example Application](https://github.com/anycable/anycable_demo) -->
|
16
18
|
|
19
|
+
📑 [Documentation](https://docs.anycable.io/v1/#/ruby/rails).
|
17
20
|
|
18
21
|
<a href="https://evilmartians.com/">
|
19
22
|
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
|
20
23
|
|
21
24
|
## Requirements
|
22
25
|
|
23
|
-
- Ruby >= 2.
|
24
|
-
- Rails >= 5.
|
25
|
-
- Redis (see [other options]() for broadcasting)
|
26
|
-
|
27
|
-
## How It Works?
|
28
|
-
|
29
|
-
<img src="https://trello-attachments.s3.amazonaws.com/5781e0ed48e4679e302833d3/820x987/5b6a305417b04e20e75f49c5816e027c/Anycable_vs_ActionCable_copy.jpg" width="400" />
|
26
|
+
- Ruby >= 2.5
|
27
|
+
- Rails >= 5.2
|
28
|
+
- Redis (see [other options](https://github.com/anycable/anycable/issues/2) for broadcasting)
|
30
29
|
|
31
30
|
## Usage
|
32
31
|
|
33
|
-
|
34
32
|
Add `anycable-rails` gem to your Gemfile:
|
35
33
|
|
36
34
|
```ruby
|
@@ -40,14 +38,25 @@ gem "anycable-rails"
|
|
40
38
|
gem "redis", ">= 4.0"
|
41
39
|
```
|
42
40
|
|
43
|
-
|
41
|
+
### Interactive set up
|
42
|
+
|
43
|
+
After the gem was installed, you can run an interactive wizard to configure your Rails application for using with AnyCable by running a generator:
|
44
|
+
|
45
|
+
```sh
|
46
|
+
bundle exec rails g anycable:setup
|
47
|
+
```
|
48
|
+
|
49
|
+
### Manual set up
|
44
50
|
|
45
|
-
|
51
|
+
Specify AnyCable subscription adapter for Action Cable:
|
46
52
|
|
47
53
|
```yml
|
48
54
|
# config/cable.yml
|
49
|
-
|
55
|
+
development:
|
50
56
|
adapter: any_cable # or anycable
|
57
|
+
|
58
|
+
production:
|
59
|
+
adapter: any_cable
|
51
60
|
```
|
52
61
|
|
53
62
|
and specify AnyCable WebSocket server URL:
|
@@ -66,7 +75,7 @@ config.action_cable.url = "wss://ws.example.com/cable"
|
|
66
75
|
|
67
76
|
Then, run AnyCable RPC server:
|
68
77
|
|
69
|
-
```
|
78
|
+
```sh
|
70
79
|
$ bundle exec anycable
|
71
80
|
|
72
81
|
# don't forget to provide Rails env
|
@@ -74,42 +83,30 @@ $ bundle exec anycable
|
|
74
83
|
$ RAILS_ENV=production bundle exec anycable
|
75
84
|
```
|
76
85
|
|
77
|
-
And, finally, run AnyCable WebSocket server, e.g. [anycable-go](https://docs.anycable.io/#/anycable-go/getting_started):
|
86
|
+
And, finally, run AnyCable WebSocket server, e.g. [anycable-go](https://docs.anycable.io/v1/#/anycable-go/getting_started):
|
78
87
|
|
79
88
|
```sh
|
80
89
|
anycable-go --host=localhost --port=3334
|
81
90
|
```
|
82
91
|
|
83
|
-
See [documentation](https://docs.anycable.io/#/ruby/rails) for more information on AnyCable + Rails usage.
|
92
|
+
See [documentation](https://docs.anycable.io/v1/#/ruby/rails) for more information on AnyCable + Rails usage.
|
84
93
|
|
85
94
|
## Action Cable Compatibility
|
86
95
|
|
87
|
-
See [documentation](https://docs.anycable.io/#/ruby/compatibility).
|
88
|
-
|
89
|
-
## Links
|
90
|
-
|
91
|
-
- [AnyCable: Action Cable on steroids!](https://evilmartians.com/chronicles/anycable-actioncable-on-steroids)
|
92
|
-
|
93
|
-
- [From Action to Any](https://medium.com/@leshchuk/from-action-to-any-1e8d863dd4cf) by [@alekseyl](https://github.com/alekseyl)
|
94
|
-
|
95
|
-
## Talks
|
96
|
-
|
97
|
-
- One cable to rule them all, RubyKaigi 2018, [slides](https://speakerdeck.com/palkan/rubykaigi-2018-anycable-one-cable-to-rule-them-all) and [video](https://www.youtube.com/watch?v=jXCPuNICT8s) (EN)
|
98
|
-
|
99
|
-
- Wroc_Love.rb 2018 [slides](https://speakerdeck.com/palkan/wroc-love-dot-rb-2018-cables-cables-cables) and [video](https://www.youtube.com/watch?v=AUxFFOehiy0) (EN)
|
100
|
-
|
101
|
-
## Compatible WebSocket servers
|
102
|
-
|
103
|
-
- [AnyCable Go](https://github.com/anycable/anycable-go)
|
104
|
-
- [ErlyCable](https://github.com/anycable/erlycable)
|
96
|
+
See [documentation](https://docs.anycable.io/v1/#/ruby/compatibility).
|
105
97
|
|
106
98
|
## Contributing
|
107
99
|
|
108
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable-rails.
|
100
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/anycable/anycable-rails](https://github.com/anycable/anycable-rails).
|
109
101
|
|
110
102
|
## Development
|
111
103
|
|
112
104
|
If you are familiar with Docker, you can use [DIP](https://github.com/bibendi/dip) to start developing the gem quickly.
|
113
105
|
|
114
106
|
## License
|
107
|
+
|
115
108
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
109
|
+
|
110
|
+
## Security Contact
|
111
|
+
|
112
|
+
To report a security vulnerability, please contact us at `anycable@evilmartians.com`. We will coordinate the fix and disclosure.
|
data/lib/anycable/rails.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require "anycable"
|
4
4
|
require "anycable/rails/version"
|
5
5
|
require "anycable/rails/config"
|
6
|
+
require "anycable/rails/rack"
|
7
|
+
|
8
|
+
require "globalid"
|
6
9
|
|
7
10
|
module AnyCable
|
8
11
|
# Rails handler for AnyCable
|
@@ -11,8 +14,40 @@ module AnyCable
|
|
11
14
|
|
12
15
|
ADAPTER_ALIASES = %w[any_cable anycable].freeze
|
13
16
|
|
14
|
-
|
15
|
-
|
17
|
+
class << self
|
18
|
+
def enabled?
|
19
|
+
adapter = ::ActionCable.server.config.cable&.fetch("adapter", nil)
|
20
|
+
compatible_adapter?(adapter)
|
21
|
+
end
|
22
|
+
|
23
|
+
def compatible_adapter?(adapter)
|
24
|
+
ADAPTER_ALIASES.include?(adapter)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Serialize connection/channel state variable to string
|
28
|
+
# using GlobalID where possible or JSON (if json: true)
|
29
|
+
def serialize(obj, json: false)
|
30
|
+
obj.try(:to_gid_param) || (json ? obj.to_json : obj)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Deserialize previously serialized value from string to
|
34
|
+
# Ruby object.
|
35
|
+
# If the resulting object is a Hash, make it indifferent
|
36
|
+
def deserialize(str, json: false)
|
37
|
+
str.yield_self do |val|
|
38
|
+
next val unless val.is_a?(String)
|
39
|
+
|
40
|
+
gval = GlobalID::Locator.locate(val)
|
41
|
+
return gval if gval
|
42
|
+
|
43
|
+
next val unless json
|
44
|
+
|
45
|
+
JSON.parse(val)
|
46
|
+
end.yield_self do |val|
|
47
|
+
next val.with_indifferent_access if val.is_a?(Hash)
|
48
|
+
val
|
49
|
+
end
|
50
|
+
end
|
16
51
|
end
|
17
52
|
end
|
18
53
|
end
|
@@ -28,6 +28,10 @@ module ActionCable
|
|
28
28
|
connection.socket.subscribe identifier, broadcasting
|
29
29
|
end
|
30
30
|
|
31
|
+
def stop_stream_from(broadcasting)
|
32
|
+
connection.socket.unsubscribe identifier, broadcasting
|
33
|
+
end
|
34
|
+
|
31
35
|
def stop_all_streams
|
32
36
|
connection.socket.unsubscribe_from_all identifier
|
33
37
|
end
|
@@ -1,43 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "action_cable/connection"
|
4
|
+
require "anycable/rails/actioncable/connection/serializable_identification"
|
4
5
|
require "anycable/rails/refinements/subscriptions"
|
5
6
|
require "anycable/rails/actioncable/channel"
|
7
|
+
require "anycable/rails/actioncable/remote_connections"
|
8
|
+
require "anycable/rails/session_proxy"
|
6
9
|
|
7
10
|
module ActionCable
|
8
11
|
module Connection
|
9
12
|
# rubocop: disable Metrics/ClassLength
|
10
13
|
class Base # :nodoc:
|
11
|
-
# We store logger tags in
|
14
|
+
# We store logger tags in the connection state to be able
|
12
15
|
# to re-use them in the subsequent calls
|
13
16
|
LOG_TAGS_IDENTIFIER = "__ltags__"
|
14
17
|
|
15
18
|
using AnyCable::Refinements::Subscriptions
|
16
19
|
|
20
|
+
include SerializableIdentification
|
21
|
+
|
17
22
|
attr_reader :socket
|
18
23
|
|
24
|
+
alias anycable_socket socket
|
25
|
+
|
26
|
+
delegate :env, :session, to: :request
|
27
|
+
|
19
28
|
class << self
|
20
29
|
def call(socket, **options)
|
21
|
-
new(socket, options)
|
30
|
+
new(socket, nil, options)
|
22
31
|
end
|
32
|
+
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
34
|
+
def initialize(socket, env, identifiers: "{}", subscriptions: [])
|
35
|
+
if env
|
36
|
+
# If env is set, then somehow we're in the context of Action Cable
|
37
|
+
# Return and print a warning in #process
|
38
|
+
@request = ActionDispatch::Request.new(env)
|
39
|
+
return
|
31
40
|
end
|
32
|
-
end
|
33
41
|
|
34
|
-
def initialize(socket, identifiers: "{}", subscriptions: [])
|
35
42
|
@ids = ActiveSupport::JSON.decode(identifiers)
|
36
43
|
|
37
|
-
@ltags =
|
44
|
+
@ltags = socket.cstate.read(LOG_TAGS_IDENTIFIER).yield_self do |raw_tags|
|
45
|
+
next unless raw_tags
|
46
|
+
ActiveSupport::JSON.decode(raw_tags)
|
47
|
+
end
|
38
48
|
|
39
49
|
@cached_ids = {}
|
40
|
-
@env = socket.env
|
41
50
|
@coder = ActiveSupport::JSON
|
42
51
|
@socket = socket
|
43
52
|
@subscriptions = ActionCable::Connection::Subscriptions.new(self)
|
@@ -46,15 +55,32 @@ module ActionCable
|
|
46
55
|
subscriptions.each { |id| @subscriptions.fetch(id) }
|
47
56
|
end
|
48
57
|
|
58
|
+
def process
|
59
|
+
# Use Rails logger here to print to stdout in development
|
60
|
+
logger.error invalid_request_message
|
61
|
+
logger.info finished_request_message
|
62
|
+
[404, {"Content-Type" => "text/plain"}, ["Page not found"]]
|
63
|
+
end
|
64
|
+
|
65
|
+
def invalid_request_message
|
66
|
+
"You're trying to connect to Action Cable server while using AnyCable. " \
|
67
|
+
"See https://docs.anycable.io/v1/#/troubleshooting?id=server-raises-an-argumenterror-exception-when-client-tries-to-connect"
|
68
|
+
end
|
69
|
+
|
49
70
|
def handle_open
|
50
71
|
logger.info started_request_message if access_logs?
|
51
72
|
|
52
|
-
verify_origin!
|
73
|
+
verify_origin! || return
|
53
74
|
|
54
75
|
connect if respond_to?(:connect)
|
76
|
+
|
77
|
+
socket.cstate.write(LOG_TAGS_IDENTIFIER, fetch_ltags.to_json)
|
78
|
+
|
55
79
|
send_welcome_message
|
56
80
|
rescue ActionCable::Connection::Authorization::UnauthorizedError
|
57
|
-
reject_request
|
81
|
+
reject_request(
|
82
|
+
ActionCable::INTERNAL[:disconnect_reasons]&.[](:unauthorized) || "unauthorized"
|
83
|
+
)
|
58
84
|
end
|
59
85
|
|
60
86
|
def handle_close
|
@@ -84,7 +110,12 @@ module ActionCable
|
|
84
110
|
end
|
85
111
|
# rubocop:enable Metrics/MethodLength
|
86
112
|
|
87
|
-
def close
|
113
|
+
def close(reason: nil, reconnect: nil)
|
114
|
+
transmit(
|
115
|
+
type: ActionCable::INTERNAL[:message_types].fetch(:disconnect, "disconnect"),
|
116
|
+
reason: reason,
|
117
|
+
reconnect: reconnect
|
118
|
+
)
|
88
119
|
socket.close
|
89
120
|
end
|
90
121
|
|
@@ -92,37 +123,14 @@ module ActionCable
|
|
92
123
|
socket.transmit encode(cable_message)
|
93
124
|
end
|
94
125
|
|
95
|
-
# Generate identifiers info.
|
96
|
-
# Converts GlobalID compatible vars to corresponding global IDs params.
|
97
|
-
def identifiers_hash
|
98
|
-
obj = { LOG_TAGS_IDENTIFIER => fetch_ltags }
|
99
|
-
|
100
|
-
identifiers.each_with_object(obj) do |id, acc|
|
101
|
-
obj = instance_variable_get("@#{id}")
|
102
|
-
next unless obj
|
103
|
-
|
104
|
-
acc[id] = obj.try(:to_gid_param) || obj
|
105
|
-
end.compact
|
106
|
-
end
|
107
|
-
|
108
|
-
def identifiers_json
|
109
|
-
identifiers_hash.to_json
|
110
|
-
end
|
111
|
-
|
112
|
-
# Fetch identifier and deserialize if neccessary
|
113
|
-
def fetch_identifier(name)
|
114
|
-
@cached_ids[name] ||= @cached_ids.fetch(name) do
|
115
|
-
val = ids[name.to_s]
|
116
|
-
next val unless val.is_a?(String)
|
117
|
-
|
118
|
-
GlobalID::Locator.locate(val) || val
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
126
|
def logger
|
123
127
|
@logger ||= TaggedLoggerProxy.new(AnyCable.logger, tags: ltags || [])
|
124
128
|
end
|
125
129
|
|
130
|
+
def request
|
131
|
+
@request ||= build_rack_request
|
132
|
+
end
|
133
|
+
|
126
134
|
private
|
127
135
|
|
128
136
|
attr_reader :ids, :ltags
|
@@ -158,19 +166,33 @@ module ActionCable
|
|
158
166
|
end
|
159
167
|
|
160
168
|
def verify_origin!
|
161
|
-
return unless socket.env.key?("HTTP_ORIGIN")
|
169
|
+
return true unless socket.env.key?("HTTP_ORIGIN")
|
162
170
|
|
163
|
-
return if allow_request_origin?
|
171
|
+
return true if allow_request_origin?
|
164
172
|
|
165
|
-
|
166
|
-
ActionCable::
|
167
|
-
"Origin is not allowed"
|
173
|
+
reject_request(
|
174
|
+
ActionCable::INTERNAL[:disconnect_reasons]&.[](:invalid_request) || "invalid_request"
|
168
175
|
)
|
176
|
+
false
|
169
177
|
end
|
170
178
|
|
171
|
-
def reject_request
|
179
|
+
def reject_request(reason, reconnect = false)
|
172
180
|
logger.info finished_request_message("Rejected") if access_logs?
|
173
|
-
close
|
181
|
+
close(
|
182
|
+
reason: reason,
|
183
|
+
reconnect: reconnect
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
def build_rack_request
|
188
|
+
environment = Rails.application.env_config.merge(socket.env)
|
189
|
+
AnyCable::Rails::Rack.app.call(environment)
|
190
|
+
|
191
|
+
ActionDispatch::Request.new(environment)
|
192
|
+
end
|
193
|
+
|
194
|
+
def request_loaded?
|
195
|
+
instance_variable_defined?(:@request)
|
174
196
|
end
|
175
197
|
end
|
176
198
|
# rubocop:enable Metrics/ClassLength
|