anycable-rails 0.6.4 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -102
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +37 -36
  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 +70 -50
  9. data/lib/anycable/rails/actioncable/connection/persistent_session.rb +30 -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/channel_state.rb +48 -0
  13. data/lib/anycable/rails/compatibility.rb +7 -10
  14. data/lib/anycable/rails/compatibility/rubocop.rb +0 -1
  15. data/lib/anycable/rails/compatibility/rubocop/config/default.yml +3 -1
  16. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/instance_vars.rb +1 -1
  17. data/lib/anycable/rails/compatibility/rubocop/cops/anycable/stream_from.rb +4 -4
  18. data/lib/anycable/rails/config.rb +8 -4
  19. data/lib/anycable/rails/rack.rb +56 -0
  20. data/lib/anycable/rails/railtie.rb +17 -10
  21. data/lib/anycable/rails/refinements/subscriptions.rb +5 -0
  22. data/lib/anycable/rails/session_proxy.rb +79 -0
  23. data/lib/anycable/rails/version.rb +1 -1
  24. data/lib/generators/anycable/download/USAGE +14 -0
  25. data/lib/generators/anycable/download/download_generator.rb +77 -0
  26. data/lib/generators/anycable/setup/USAGE +2 -0
  27. data/lib/generators/anycable/setup/setup_generator.rb +258 -0
  28. data/lib/generators/anycable/setup/templates/Procfile.dev +3 -0
  29. data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +43 -0
  30. data/lib/generators/anycable/setup/templates/config/cable.yml.tt +11 -0
  31. data/lib/generators/anycable/setup/templates/config/initializers/anycable.rb.tt +9 -0
  32. data/lib/generators/anycable/with_os_helpers.rb +55 -0
  33. metadata +42 -28
  34. 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: a64b470ef4ab3faa836fbea01ae21be1cbeae3d2693dc3e92c01acb5113451bc
4
- data.tar.gz: 2d68392cf3649b5496c72298d8baf1fa720309a3f69cd337e55317f116ee7c37
3
+ metadata.gz: e0de4d95da59574a14f3f56219154cf3e12513a74e677520acf0cffbbf566e49
4
+ data.tar.gz: c6a4e9b87c3c59aac495663f8acc9f3150a8de5f43d5ab55d19c265039ba2af1
5
5
  SHA512:
6
- metadata.gz: 13282898b856f2a9751d7c3d69c4a6d4f62ebe25a3e7ca03405a53f56f4e70a5f32e869950d557affa09d0fcd6657f0a8c9c3574d33f8cc73e9c7ebd580ebf63
7
- data.tar.gz: 9552cec222800c6e706096d28c58e58ad8b41412d99a2a0ed813fdec194dd1bf1063352dd9694f67ff2efb30bf0d780eaeb3159885fa97069ab2521f5d3d7712
6
+ metadata.gz: 93f85efbfa20cffe71b3b52115b98321158577a36439b9875e6bbfb18ecee32c44fd31376a05f8883b8eff7d8b06b4d2d5abf762f86f6765248e3051869f3b17
7
+ data.tar.gz: 2ca2cd646321b0ed567af383847e4ae5f5cab116be0a7c410ea18d91f43378c024c47e3002c0aa70ddd0970a4e2bad50fd173c0b1fdf9088f229bad3ea53a05d
@@ -2,132 +2,56 @@
2
2
 
3
3
  ## master
4
4
 
5
- ## 0.6.4 (2019-06-26) 👶
5
+ ## 1.0.0.rc2 (2020-06-16)
6
6
 
7
- - Fix Compatibility bug when using with AnyCable. ([@palkan][])
7
+ - Fix connection identifiers deserialization regression. ([@palkan][])
8
8
 
9
- Compatibility patching (with `prepend` + `super`) conflicted with
10
- the `ActionCable::Channel::Base` patching in the core functionality (which uses `alias`).
9
+ Using non-strings or non-GlobalId-encoded objects was broken.
11
10
 
12
- See [#95](https://github.com/anycable/anycable-rails/issues/95).
11
+ - Improve `anycable:setup` generator. ([@palkan][])
13
12
 
14
- ## 0.6.3 (2019-03-26)
13
+ Update Docker snippet, do not enable persistent sessions automatically,
14
+ fix setting `config.action_cable.url` in environment configuration.
15
15
 
16
- - Fix connection factory reloading for development sake. ([@sponomarev][])
16
+ ## 1.0.0.rc1 (2020-06-10)
17
17
 
18
- - Add `:anycable` subscription adapter alias. ([@sponomarev][])
18
+ - Add `state_attr_accessor` for channels. ([@palkan][])
19
19
 
20
- - Don't set AnyCable connection factory for incompatible adapter ([@sponomarev][])
20
+ Just like `attr_accessor` but "persists" the state between RPC calls.
21
21
 
22
- `anycable` server won't start with unpatched vanilla `ApplicationCable::Connection`.
22
+ - Add `Channel#stop_stream_from` support. ([@palkan][])
23
23
 
24
- Motivation in [#74](https://github.com/anycable/anycable-rails/issues/74).
24
+ - Add `RemoteConnections` support. ([@palkan][])
25
25
 
26
- - Fix instance detection inside complex cases in compatibility cops ([@sponomarev][])
26
+ - Add `AnyCable::Rails.enabled?` method which returns true if Action Cable uses AnyCable adapter. ([@palkan][])
27
27
 
28
- ## 0.6.2 (2019-01-10)
28
+ - Add `anycable:download` generator to download `anycable-go` binary. ([@palkan][])
29
29
 
30
- - Fixed `anycable` 0.6.1 compatibility. ([@palkan][])
30
+ - **Ruby 2.5+ is required**. ([@palkan][])
31
31
 
32
- - Broadcast logs to STDOUT in development only when server is running. ([@palkan][])
32
+ - Support `disconnect` messages. ([@palkan][])
33
33
 
34
- Fixes #59.
34
+ Added in Rails 6 (see [PR#34194](https://github.com/rails/rails/pull/34194)).
35
35
 
36
- ## 0.6.1 (2018-11-15)
36
+ - Add ability to persist _dirty_ `request.session` between RPC calls. ([@palkan][])
37
37
 
38
- - Fix regression introduced in [e64a366e](https://github.com/anycable/anycable-rails/commit/e64a366ea21293925e0c5c0b8e6595d65d5d0981#diff-fd0e56a6e825002eac978507c3581af7R14) ([@palkan][])
38
+ This feature emulates the Action Cable behaviour where it's possible to use `request.session` as a shared Hash-like store.
39
+ This could be used by some applications (e.g., [StimulusReflex](https://github.com/hopsoft/stimulus_reflex)-based).
39
40
 
40
- `Connection` patch could be loaded after `identify_by` is called, thus breaking
41
- identifiers.
41
+ You must turn this feature on by setting `persistent_session_enabled: true` in the AnyCable configuration.
42
42
 
43
- ## 0.6.0 (2018-11-15)
43
+ - Add ability to use Rack middlewares when build a request for a connection. ([@bibendi][])
44
44
 
45
- **NOTE**: this version has been yanked from RubyGems due to the regression bug. Use 0.6.1.
45
+ - Add set up generator to configure a Rails application by running `bin/rails g anycable:setup`. ([@bibendi][])
46
46
 
47
- - [PR #56](https://github.com/anycable/anycable-rails/pull/56) Request verification based on ActionCable config. ([@DmitryTsepelev][])
47
+ - Require a minimum version of Ruby when installing the gem. ([@bibendi][])
48
48
 
49
- - Add WS server session ID to log tags if present. ([@palkan][])
49
+ - Add ability to develop the gem with Docker. ([@bibendi][])
50
50
 
51
- - Support tagged logging. ([@palkan][])
52
-
53
- - Action Cable monkey-patches are only loaded in the context of AnyCable CLI. ([@palkan][])
54
-
55
- No need to think about `requie` and `group` for `anycable-rails`, just add it to Gemfile.
56
-
57
- - Add `:any_cable` subscription adapter for Action Cable. ([@palkan][])
58
-
59
- Use `:any_cable` adapter for Action Cable to broadcast data to AnyCable.
60
-
61
- No more `pubsub` monkey-patches 🎉.
62
-
63
- - Added Rails executor/reloader support. ([@palkan][])
64
-
65
- - **[Breaking]** No more generators. ([@palkan][])
66
-
67
- No need to generate AnyCable runner script since `anycable` gem ships with
68
- the CLI.
69
-
70
- - Add dynamic (`AnyCable::CompatibilityError`) compatibility checks. ([@DmitryTsepelev][])
71
-
72
- - Added static (RuboCop) compatibility checks. ([@DmitryTsepelev][])
73
-
74
- See https://github.com/anycable/anycable-rails/issues/52
75
-
76
- ## 0.5.4 (2018-06-13)
77
-
78
- - Fix duplicate logs in development. ([@palkan][])
79
-
80
- Fixes https://github.com/anycable/anycable_demo/issues/5.
81
-
82
- ## 0.5.3
83
-
84
- - Fix return value of `Connection#handle_close`. ([@palkan][])
85
-
86
- Should always be `true`, we do not expect a failure here.
87
-
88
- ## 0.5.2
89
-
90
- - Add config/anycable.yml to Rails generator. ([@alekseyl][])
91
-
92
- ## 0.5.1
93
-
94
- - Improve Rails integration. ([@palkan][])
95
-
96
- Log to STDOUT in development.
97
- Make order of initializers more deterministic.
98
- Show warning if AnyCable is loaded after application initialization.
99
-
100
- ## 0.5.0
101
-
102
- - [#17](https://github.com/anycable/anycable-rails/issues/17) Refactor logging. ([@palkan][])
103
-
104
- Use Rails logger everywhere.
105
-
106
- Add access logs ([anycable/anycable#20](https://github.com/anycable/anycable/issues/20)).
107
-
108
- ## 0.4.7
109
-
110
- - Minor fixes. ([@palkan][])
111
-
112
- ## 0.4.6
113
-
114
- - Disable mounting default Action Cable server when AnyCable is loaded. ([@palkan][])
115
-
116
- ## 0.4.5
117
-
118
- - Handle tagged logger. ([@palkan][])
119
-
120
- Ignore tagged logger features ('cause we do not have _persistent_ logger).
121
-
122
- ## 0.4.4
123
-
124
- - Fix bug with ActiveRecord connections (https://github.com/anycable/anycable/issues/9). ([@palkan][])
125
-
126
- ## 0.4.0
127
-
128
- - Initial version. ([@palkan][])
51
+ See [Changelog](https://github.com/anycable/anycable-rails/blob/0-6-stable/CHANGELOG.md) for versions <1.0.0.
129
52
 
130
53
  [@palkan]: https://github.com/palkan
131
54
  [@alekseyl]: https://github.com/alekseyl
132
55
  [@DmitryTsepelev]: https://github.com/DmitryTsepelev
133
56
  [@sponomarev]: https://github.com/sponomarev
57
+ [@bibendi]: https://github.com/bibendi
@@ -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/#using_with_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
44
42
 
45
- Next, specify AnyCable subscription adapter for Action Cable:
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
50
+
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:
@@ -64,9 +73,9 @@ config.action_cable.url = "ws://localhost:3334/cable"
64
73
  config.action_cable.url = "wss://ws.example.com/cable"
65
74
  ```
66
75
 
67
- hen, run AnyCable RPC server:
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,38 +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/#go_getting_started.md):
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/#using_with_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/#compatibility).
88
-
89
- ## Links
96
+ See [documentation](https://docs.anycable.io/v1/#/ruby/compatibility).
90
97
 
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
98
+ ## Contributing
96
99
 
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)
100
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/anycable/anycable-rails](https://github.com/anycable/anycable-rails).
98
101
 
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)
102
+ ## Development
100
103
 
101
- ## Compatible WebSocket servers
104
+ If you are familiar with Docker, you can use [DIP](https://github.com/bibendi/dip) to start developing the gem quickly.
102
105
 
103
- - [AnyCable Go](https://github.com/anycable/anycable-go)
104
- - [ErlyCable](https://github.com/anycable/erlycable)
106
+ ## License
105
107
 
106
- ## Contributing
108
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
107
109
 
108
- Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable-rails.
110
+ ## Security Contact
109
111
 
110
- ## License
111
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
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,50 @@
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
+ delegate :env, :session, to: :request
25
+
19
26
  class << self
20
27
  def call(socket, **options)
21
- new(socket, options)
28
+ new(socket, nil, options)
22
29
  end
30
+ end
23
31
 
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
32
+ def initialize(socket, env, identifiers: "{}", subscriptions: [])
33
+ if env
34
+ # If env is set, then somehow we're in the context of Action Cable
35
+ # Return and print a warning in #process
36
+ @request = ActionDispatch::Request.new(env)
37
+ return
31
38
  end
32
- end
33
39
 
34
- def initialize(socket, identifiers: "{}", subscriptions: [])
35
40
  @ids = ActiveSupport::JSON.decode(identifiers)
36
41
 
37
- @ltags = ids.delete(LOG_TAGS_IDENTIFIER)
42
+ @ltags = socket.cstate.read(LOG_TAGS_IDENTIFIER).yield_self do |raw_tags|
43
+ next unless raw_tags
44
+ ActiveSupport::JSON.decode(raw_tags)
45
+ end
38
46
 
39
47
  @cached_ids = {}
40
- @env = socket.env
41
48
  @coder = ActiveSupport::JSON
42
49
  @socket = socket
43
50
  @subscriptions = ActionCable::Connection::Subscriptions.new(self)
@@ -46,15 +53,32 @@ module ActionCable
46
53
  subscriptions.each { |id| @subscriptions.fetch(id) }
47
54
  end
48
55
 
56
+ def process
57
+ # Use Rails logger here to print to stdout in development
58
+ logger.error invalid_request_message
59
+ logger.info finished_request_message
60
+ [404, {"Content-Type" => "text/plain"}, ["Page not found"]]
61
+ end
62
+
63
+ def invalid_request_message
64
+ "You're trying to connect to Action Cable server while using AnyCable. " \
65
+ "See https://docs.anycable.io/v1/#/troubleshooting?id=server-raises-an-argumenterror-exception-when-client-tries-to-connect"
66
+ end
67
+
49
68
  def handle_open
50
69
  logger.info started_request_message if access_logs?
51
70
 
52
- verify_origin!
71
+ verify_origin! || return
53
72
 
54
73
  connect if respond_to?(:connect)
74
+
75
+ socket.cstate.write(LOG_TAGS_IDENTIFIER, fetch_ltags.to_json)
76
+
55
77
  send_welcome_message
56
78
  rescue ActionCable::Connection::Authorization::UnauthorizedError
57
- reject_request
79
+ reject_request(
80
+ ActionCable::INTERNAL[:disconnect_reasons]&.[](:unauthorized) || "unauthorized"
81
+ )
58
82
  end
59
83
 
60
84
  def handle_close
@@ -84,7 +108,12 @@ module ActionCable
84
108
  end
85
109
  # rubocop:enable Metrics/MethodLength
86
110
 
87
- def close
111
+ def close(reason: nil, reconnect: nil)
112
+ transmit(
113
+ type: ActionCable::INTERNAL[:message_types].fetch(:disconnect, "disconnect"),
114
+ reason: reason,
115
+ reconnect: reconnect
116
+ )
88
117
  socket.close
89
118
  end
90
119
 
@@ -92,37 +121,14 @@ module ActionCable
92
121
  socket.transmit encode(cable_message)
93
122
  end
94
123
 
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
124
  def logger
123
125
  @logger ||= TaggedLoggerProxy.new(AnyCable.logger, tags: ltags || [])
124
126
  end
125
127
 
128
+ def request
129
+ @request ||= build_rack_request
130
+ end
131
+
126
132
  private
127
133
 
128
134
  attr_reader :ids, :ltags
@@ -158,19 +164,33 @@ module ActionCable
158
164
  end
159
165
 
160
166
  def verify_origin!
161
- return unless socket.env.key?("HTTP_ORIGIN")
167
+ return true unless socket.env.key?("HTTP_ORIGIN")
162
168
 
163
- return if allow_request_origin?
169
+ return true if allow_request_origin?
164
170
 
165
- raise(
166
- ActionCable::Connection::Authorization::UnauthorizedError,
167
- "Origin is not allowed"
171
+ reject_request(
172
+ ActionCable::INTERNAL[:disconnect_reasons]&.[](:invalid_request) || "invalid_request"
168
173
  )
174
+ false
169
175
  end
170
176
 
171
- def reject_request
177
+ def reject_request(reason, reconnect = false)
172
178
  logger.info finished_request_message("Rejected") if access_logs?
173
- close
179
+ close(
180
+ reason: reason,
181
+ reconnect: reconnect
182
+ )
183
+ end
184
+
185
+ def build_rack_request
186
+ environment = Rails.application.env_config.merge(socket.env)
187
+ AnyCable::Rails::Rack.app.call(environment)
188
+
189
+ ActionDispatch::Request.new(environment)
190
+ end
191
+
192
+ def request_loaded?
193
+ instance_variable_defined?(:@request)
174
194
  end
175
195
  end
176
196
  # rubocop:enable Metrics/ClassLength