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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -110
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +34 -37
  5. data/lib/action_cable/subscription_adapter/any_cable.rb +2 -1
  6. data/lib/anycable/rails.rb +37 -2
  7. data/lib/anycable/rails/actioncable/channel.rb +4 -0
  8. data/lib/anycable/rails/actioncable/connection.rb +72 -50
  9. data/lib/anycable/rails/actioncable/connection/persistent_session.rb +34 -0
  10. data/lib/anycable/rails/actioncable/connection/serializable_identification.rb +42 -0
  11. data/lib/anycable/rails/actioncable/remote_connections.rb +11 -0
  12. data/lib/anycable/rails/actioncable/testing.rb +35 -0
  13. data/lib/anycable/rails/channel_state.rb +46 -0
  14. data/lib/anycable/rails/compatibility.rb +7 -10
  15. data/lib/anycable/rails/compatibility/rubocop.rb +0 -1
  16. data/lib/anycable/rails/compatibility/rubocop/config/default.yml +3 -1
  17. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/instance_vars.rb +1 -1
  18. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/stream_from.rb +4 -4
  19. data/lib/anycable/rails/config.rb +8 -4
  20. data/lib/anycable/rails/rack.rb +56 -0
  21. data/lib/anycable/rails/railtie.rb +28 -13
  22. data/lib/anycable/rails/refinements/subscriptions.rb +1 -1
  23. data/lib/anycable/rails/session_proxy.rb +79 -0
  24. data/lib/anycable/rails/version.rb +1 -1
  25. data/lib/generators/anycable/download/USAGE +14 -0
  26. data/lib/generators/anycable/download/download_generator.rb +83 -0
  27. data/lib/generators/anycable/setup/USAGE +2 -0
  28. data/lib/generators/anycable/setup/setup_generator.rb +266 -0
  29. data/lib/generators/anycable/setup/templates/Procfile.dev +3 -0
  30. data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +43 -0
  31. data/lib/generators/anycable/setup/templates/config/cable.yml.tt +11 -0
  32. data/lib/generators/anycable/setup/templates/config/initializers/anycable.rb.tt +9 -0
  33. data/lib/generators/anycable/with_os_helpers.rb +55 -0
  34. metadata +45 -30
  35. 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: d538541df27b5712aadd225d788d43c7d6de563a15dcbb85dd9ef51ff1b13be4
4
- data.tar.gz: e7e5c055860a07f2554af925cee5076a07f97cfcdfa7d540891cb187bbc32f72
3
+ metadata.gz: 3ebb4dc7b8483998770f7168cc8884d8a56a0e5376e04550b2f98b1d11046cdf
4
+ data.tar.gz: 29a21773378af2c3bcc6cd3265d58d028a7bef7b8fc2be13bafda3f54677d8b1
5
5
  SHA512:
6
- metadata.gz: 007b964f71b796feb189e76d82f2ae3e16c679c56811b9a1b7105bc5663e5e432bcebe4f9a16a971e3819be658f2fcfb8198576d7c9d75495dcc9dcd9db7949e
7
- data.tar.gz: 257f761cfdd1fc3b05d8e1446297a7b31119c667e88e73db1a72485252f5f57e672ee6ac3c39b72e32286b4994d7b62f30f888c4aa12039202c8ccc93fb8df38
6
+ metadata.gz: cde255681a0348c2edc41fc3130d632f8f17ea02937691b62a388f8a73a699b9e1669e9c7ea55f1dad3a74b6e0d289a3a07feda97adbcbbfcc5d1e316213a704
7
+ data.tar.gz: 88c80148d66a610472bf8a129a381198d044c89884a800f4209c19f67a6cf527763620bfd804b03cbddb0f6752b6e69c8065e4bfbf1c33da11e66cb7def49688
@@ -2,141 +2,59 @@
2
2
 
3
3
  ## master
4
4
 
5
- ## 0.6.5 (2020-02-05)
5
+ ## 1.0.0.rc3 (2020-06-24)
6
6
 
7
- - Make channel not found exception more descriptive. ([@palkan][])
7
+ - Make AnyCable patches compatible with Action Cable testing. ([@palkan][])
8
8
 
9
- Previusly, we returned `Undefined method handle_subscribe for nil` when Action Cable
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
- - Require a minimum version of Ruby when installing the gem. ([@bibendi][])
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
- **NOTE**: this version has been yanked from RubyGems due to the regression bug. Use 0.6.1.
13
+ - Fix connection identifiers deserialization regression. ([@palkan][])
57
14
 
58
- - [PR #56](https://github.com/anycable/anycable-rails/pull/56) Request verification based on ActionCable config. ([@DmitryTsepelev][])
15
+ Using non-strings or non-GlobalId-encoded objects was broken.
59
16
 
60
- - Add WS server session ID to log tags if present. ([@palkan][])
17
+ - Improve `anycable:setup` generator. ([@palkan][])
61
18
 
62
- - Support tagged logging. ([@palkan][])
19
+ Update Docker snippet, do not enable persistent sessions automatically,
20
+ fix setting `config.action_cable.url` in environment configuration.
63
21
 
64
- - Action Cable monkey-patches are only loaded in the context of AnyCable CLI. ([@palkan][])
22
+ ## 1.0.0.rc1 (2020-06-10)
65
23
 
66
- No need to think about `requie` and `group` for `anycable-rails`, just add it to Gemfile.
24
+ - Add `state_attr_accessor` for channels. ([@palkan][])
67
25
 
68
- - Add `:any_cable` subscription adapter for Action Cable. ([@palkan][])
26
+ Just like `attr_accessor` but "persists" the state between RPC calls.
69
27
 
70
- Use `:any_cable` adapter for Action Cable to broadcast data to AnyCable.
28
+ - Add `Channel#stop_stream_from` support. ([@palkan][])
71
29
 
72
- No more `pubsub` monkey-patches 🎉.
30
+ - Add `RemoteConnections` support. ([@palkan][])
73
31
 
74
- - Added Rails executor/reloader support. ([@palkan][])
32
+ - Add `AnyCable::Rails.enabled?` method which returns true if Action Cable uses AnyCable adapter. ([@palkan][])
75
33
 
76
- - **[Breaking]** No more generators. ([@palkan][])
34
+ - Add `anycable:download` generator to download `anycable-go` binary. ([@palkan][])
77
35
 
78
- No need to generate AnyCable runner script since `anycable` gem ships with
79
- the CLI.
36
+ - **Ruby 2.5+ is required**. ([@palkan][])
80
37
 
81
- - Add dynamic (`AnyCable::CompatibilityError`) compatibility checks. ([@DmitryTsepelev][])
38
+ - Support `disconnect` messages. ([@palkan][])
82
39
 
83
- - Added static (RuboCop) compatibility checks. ([@DmitryTsepelev][])
40
+ Added in Rails 6 (see [PR#34194](https://github.com/rails/rails/pull/34194)).
84
41
 
85
- See https://github.com/anycable/anycable-rails/issues/52
42
+ - Add ability to persist _dirty_ `request.session` between RPC calls. ([@palkan][])
86
43
 
87
- ## 0.5.4 (2018-06-13)
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
- - Fix duplicate logs in development. ([@palkan][])
47
+ You must turn this feature on by setting `persistent_session_enabled: true` in the AnyCable configuration.
90
48
 
91
- Fixes https://github.com/anycable/anycable_demo/issues/5.
49
+ - Add ability to use Rack middlewares when build a request for a connection. ([@bibendi][])
92
50
 
93
- ## 0.5.3
51
+ - Add set up generator to configure a Rails application by running `bin/rails g anycable:setup`. ([@bibendi][])
94
52
 
95
- - Fix return value of `Connection#handle_close`. ([@palkan][])
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
- ## 0.4.0
55
+ - Add ability to develop the gem with Docker. ([@bibendi][])
138
56
 
139
- - Initial version. ([@palkan][])
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
@@ -1,4 +1,4 @@
1
- Copyright 2017 palkan
1
+ Copyright 2017-2020 palkan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- [![GitPitch](https://gitpitch.com/assets/badge.svg)](https://gitpitch.com/anycable/anycable/master?grs=github) [![Gem Version](https://badge.fury.io/rb/anycable-rails.svg)](https://rubygems.org/gems/anycable-rails) [![Build Status](https://travis-ci.org/anycable/anycable-rails.svg?branch=master)](https://travis-ci.org/anycable/anycable-rails)
1
+ [![GitPitch](https://gitpitch.com/assets/badge.svg)](https://gitpitch.com/anycable/anycable/master?grs=github)
2
+ [![Gem Version](https://badge.fury.io/rb/anycable-rails.svg)](https://rubygems.org/gems/anycable-rails)
3
+ [![Build](https://github.com/anycable/anycable-rails/workflows/Build/badge.svg)](https://github.com/anycable/anycable-rails/actions)
2
4
  [![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/anycable/Lobby)
3
- [![Documentation](https://img.shields.io/badge/docs-link-brightgreen.svg)](https://docs.anycable.io/#/ruby/rails)
5
+ [![Documentation](https://img.shields.io/badge/docs-link-brightgreen.svg)](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
- 💾 [Example Application](https://github.com/anycable/anycable_demo)
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
- 📑 [Documentation](https://docs.anycable.io).
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.4; **NOTE:** for Ruby 2.6 use RC version of `google-protobuf` gem. In your Gemfile: `gem "google-protobuf", '>=3.7.0.rc.2'`
24
- - Rails >= 5.0;
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
- (and don't forget to run `bundle install`).
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
- Next, specify AnyCable subscription adapter for Action Cable:
51
+ Specify AnyCable subscription adapter for Action Cable:
46
52
 
47
53
  ```yml
48
54
  # config/cable.yml
49
- production:
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
- ```ruby
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.
@@ -7,7 +7,8 @@ module ActionCable
7
7
  # AnyCable subscription adapter delegates broadcasts
8
8
  # to AnyCable
9
9
  class AnyCable < Base
10
- def initialize(*); end
10
+ def initialize(*)
11
+ end
11
12
 
12
13
  def broadcast(channel, payload)
13
14
  ::AnyCable.broadcast(channel, payload)
@@ -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
- def self.compatible_adapter?(adapter)
15
- ADAPTER_ALIASES.include?(adapter)
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 identifiers to be able
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
- def identified_by(*identifiers)
25
- super
26
- Array(identifiers).each do |identifier|
27
- define_method(identifier) do
28
- instance_variable_get(:"@#{identifier}") || fetch_identifier(identifier)
29
- end
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 = ids.delete(LOG_TAGS_IDENTIFIER)
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
- raise(
166
- ActionCable::Connection::Authorization::UnauthorizedError,
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