anycable-rails-core 1.6.0.rc.1 → 1.6.0.rc.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 395f76c02adbd3f4878b55bb21bf4bd00969e4394e824fb7a23f086d8b221b1c
4
- data.tar.gz: b300f5b2ab64aa893d462a22045587f65531bbaea8dce3a920c1fb1df67b211e
3
+ metadata.gz: 734dca7d3a224a971ba2e4979e0a33337fa4551ff07cb86acd3c6cc546eea974
4
+ data.tar.gz: 88d96b3f0c85a2259c29cb0f863cdcee92584b801309202cab4a9d03c8152710
5
5
  SHA512:
6
- metadata.gz: f0a2f228649539c86b8e3f1a96f0c456b6ed0f933552fb93c90ef2d4a5c49261fdbdf9f3e7b650cd69b00ca38bddcf202bb6f1d730aa92ad07ec3f8504128904
7
- data.tar.gz: dfce4029440d91a5a7f07abccca089b6b0bb759d152aa2fadad9ccb12ca0533a5d10cba6e200f398ce58c54c76c5b0fa5903c48aeacba2354dc8b5f9ad37d10f
6
+ metadata.gz: 5b0d2f5faf24b406264326771b00b23aadc88cb6b20d62a9055857e31c5e99d6cc770dc835dfabfff66c65aa26768062197c8d67d1e357749f0563d214d2cc30
7
+ data.tar.gz: 2793659e6c349ef838a84e57b4d42b3ddcff7aeabfb9024207e1e8a08b09e85ff28e68aaa1693b4e174512a03ddd0c7cc11450a988470846add034d31742f0b4
data/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Change log
2
2
 
3
- ## master
3
+ ## main
4
+
5
+ ## 1.6.0.rc.3 (2025-02-20)
6
+
7
+ - Update `anycable:download` generator to support v1.6+. ([@palkan][])
8
+
9
+ - Add `#anycable_token_meta_tag` helper. ([@palkan][])
10
+
11
+ It generates a meta tag with the AnyCable JWT token (w/o the URL).
12
+
13
+ ## 1.6.0.rc.2 (2025-02-10)
14
+
15
+ - Add Presence API. ([@palkan][])
4
16
 
5
17
  ## 1.5.5 (2024-12-12)
6
18
 
@@ -3,17 +3,6 @@
3
3
  require "action_cable"
4
4
 
5
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
6
  def start_periodic_timers
18
7
  super unless anycabled?
19
8
  end
@@ -12,7 +12,7 @@ module AnyCable
12
12
 
13
13
  stream ||= connection.anycable_socket.streams[:start].first || raise(ArgumentError, "Provide a stream name for presence updates")
14
14
 
15
- connection.anycable_socket.presence_join(stream, id, info)
15
+ connection.anycable_socket.presence_join(stream, id.to_s, info)
16
16
  end
17
17
 
18
18
  def leave_presence(id = user_presence_id)
@@ -31,15 +31,65 @@ module AnyCable
31
31
  end
32
32
 
33
33
  refine ActionCable::Connection::Subscriptions do
34
- # Find or add a subscription to the list
35
- def fetch(identifier)
36
- add("identifier" => identifier) unless subscriptions[identifier]
34
+ # Override the original #execute_command to pre-initialize the channel for unsubscribe/message and
35
+ # return true/false to indicate successful/unsuccessful subscription.
36
+ # We also must not lose any exceptions raised in the process.
37
+ def execute_rpc_command(data)
38
+ # First, verify the channel name
39
+ raise "Channel not found: #{ActiveSupport::JSON.decode(data["identifier"]).fetch("channel")}" unless subscription_class_from_identifier(data["identifier"])
40
+
41
+ if data["command"] == "subscribe"
42
+ add data
43
+ subscription = subscriptions[data["identifier"]]
44
+ return !(subscription.nil? || subscription.rejected?)
45
+ end
46
+
47
+ load(data["identifier"])
37
48
 
38
- unless subscriptions[identifier]
39
- raise "Channel not found: #{ActiveSupport::JSON.decode(identifier).fetch("channel")}"
49
+ case data["command"]
50
+ when "unsubscribe"
51
+ remove data
52
+ when "message"
53
+ perform_action data
54
+ when "whisper"
55
+ whisper data
56
+ else
57
+ raise UnknownCommandError, data["command"]
40
58
  end
41
59
 
42
- subscriptions[identifier]
60
+ true
61
+ end
62
+
63
+ # Restore channels from the list of identifiers and the state
64
+ def restore(subscriptions, istate)
65
+ subscriptions.each do |id|
66
+ channel = load(id)
67
+ channel.__istate__ = ActiveSupport::JSON.decode(istate[id]) if istate[id]
68
+ end
69
+ end
70
+
71
+ # Find or create a channel for a given identifier
72
+ def load(identifier)
73
+ return subscriptions[identifier] if subscriptions[identifier]
74
+
75
+ subscription = subscription_from_identifier(identifier)
76
+ raise "Channel not found: #{ActiveSupport::JSON.decode(identifier).fetch("channel")}" unless subscription
77
+
78
+ subscriptions[identifier] = subscription
79
+ end
80
+
81
+ def subscription_class_from_identifier(id_key)
82
+ id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
83
+ id_options[:channel].safe_constantize
84
+ end
85
+
86
+ def subscription_from_identifier(id_key)
87
+ subscription_klass = subscription_class_from_identifier(id_key)
88
+
89
+ if subscription_klass && subscription_klass < ActionCable::Channel::Base
90
+ id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
91
+ subscription_klass.new(connection, id_key, id_options)
92
+ end
43
93
  end
44
94
  end
45
95
  end)
@@ -74,15 +124,8 @@ module AnyCable
74
124
  conn.cached_ids = {}
75
125
  conn.anycable_request_builder = self
76
126
 
77
- return unless subscriptions
78
-
79
127
  # Pre-initialize channels (for disconnect)
80
- subscriptions.each do |id|
81
- channel = conn.subscriptions.fetch(id)
82
- next unless socket.istate[id]
83
-
84
- channel.__istate__ = ActiveSupport::JSON.decode(socket.istate[id])
85
- end
128
+ conn.subscriptions.restore(subscriptions, socket.istate) if subscriptions
86
129
  end
87
130
 
88
131
  def handle_open
@@ -111,26 +154,8 @@ module AnyCable
111
154
 
112
155
  def handle_channel_command(identifier, command, data)
113
156
  conn.run_callbacks :command do
114
- # We cannot use subscriptions#execute_command here,
115
- # since we MUST return true of false, depending on the status
116
- # of execution
117
- channel = conn.subscriptions.fetch(identifier)
118
- case command
119
- when "subscribe"
120
- channel.handle_subscribe
121
- !channel.rejected?
122
- when "unsubscribe"
123
- conn.subscriptions.remove_subscription(channel)
124
- true
125
- when "message"
126
- channel.perform_action ActiveSupport::JSON.decode(data)
127
- true
128
- else
129
- false
130
- end
157
+ conn.subscriptions.execute_rpc_command({"command" => command, "identifier" => identifier, "data" => data})
131
158
  end
132
- # Support rescue_from
133
- # https://github.com/rails/rails/commit/d2571e560c62116f60429c933d0c41a0e249b58b
134
159
  rescue Exception => e # rubocop:disable Lint/RescueException
135
160
  rescue_with_handler(e) || raise
136
161
  false
@@ -22,10 +22,10 @@ module AnyCable
22
22
  tag "meta", name: "action-cable-url", content: url
23
23
  end
24
24
 
25
- def any_cable_jwt_meta_tag(**identifiers)
25
+ def anycable_token_meta_tag(**identifiers)
26
26
  token = JWT.encode(identifiers)
27
27
 
28
- tag "meta", name: "any-cable-jwt", content: token
28
+ tag "meta", name: "cable-token", content: token
29
29
  end
30
30
 
31
31
  def signed_stream_name(streamables)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module AnyCable
4
4
  module Rails
5
- VERSION = "1.6.0.rc.1"
5
+ VERSION = "1.6.0.rc.3"
6
6
  end
7
7
  end
@@ -37,24 +37,35 @@ module AnyCableRailsGenerators
37
37
  return latest_release_url(version) if version == "latest"
38
38
 
39
39
  if Gem::Version.new(version).segments.first >= 1
40
- new_release_url("v#{version}")
40
+ new_release_url(version)
41
41
  else
42
- legacy_release_url("v#{version}")
42
+ legacy_release_url(version)
43
+ end
44
+ end
45
+
46
+ def repository_name(version)
47
+ return "anycable/anycable" if version == "latest"
48
+
49
+ major, minor, = Gem::Version.new(version).segments
50
+ if (major >= 1 && minor >= 6) || (major > 1)
51
+ "anycable/anycable"
52
+ else
53
+ "anycable/anycable-go"
43
54
  end
44
55
  end
45
56
 
46
57
  def legacy_release_url(version)
47
- "https://github.com/anycable/anycable-go/releases/download/#{version}/" \
58
+ "https://github.com/#{repository_name(version)}/releases/download/v#{version}/" \
48
59
  "anycable-go-v#{version}-#{os_name}-#{cpu_name}"
49
60
  end
50
61
 
51
62
  def new_release_url(version)
52
- "https://github.com/anycable/anycable-go/releases/download/#{version}/" \
63
+ "https://github.com/#{repository_name(version)}/releases/download/v#{version}/" \
53
64
  "anycable-go-#{os_name}-#{cpu_name}"
54
65
  end
55
66
 
56
67
  def latest_release_url(version)
57
- "https://github.com/anycable/anycable-go/releases/latest/download/" \
68
+ "https://github.com/#{repository_name(version)}/releases/latest/download/" \
58
69
  "anycable-go-#{os_name}-#{cpu_name}"
59
70
  end
60
71
 
@@ -88,6 +88,13 @@ module AnyCableRailsGenerators
88
88
  "`action_cable_meta_tag` or `action_cable_with_jwt_meta_tag` included in your HTML layout"
89
89
  end
90
90
 
91
+ def cable_engine_warning
92
+ return unless application_rb
93
+ return if application_rb.match?(/^require\s+['"](action_cable\/engine|rails\/all)['"]/)
94
+
95
+ say_status :help, "⚠️ Ensure Action Cable is loaded.\nAdd `require \"action_cable/engine\"` to your `config/application.rb`."
96
+ end
97
+
91
98
  def deployment_method
92
99
  say_status :info, "🚢 See our deployment guide to learn how to run AnyCable in production 👉 #{DOCS_ROOT}/deployment"
93
100
 
@@ -139,6 +146,17 @@ module AnyCableRailsGenerators
139
146
  end
140
147
  end
141
148
 
149
+ def application_rb
150
+ @application_rb ||= begin
151
+ res = nil
152
+ in_root do
153
+ next unless File.file?("config/application.rb")
154
+ res = File.read("config/application.rb")
155
+ end
156
+ res
157
+ end
158
+ end
159
+
142
160
  def install_for_docker
143
161
  say_status :help, "️️⚠️ Docker development configuration could vary", :yellow
144
162
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anycable-rails-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0.rc.1
4
+ version: 1.6.0.rc.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-04 00:00:00.000000000 Z
11
+ date: 2025-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: anycable-core
@@ -139,7 +139,7 @@ metadata:
139
139
  homepage_uri: https://anycable.io/
140
140
  source_code_uri: http://github.com/anycable/anycable-rails
141
141
  funding_uri: https://github.com/sponsors/anycable
142
- post_install_message:
142
+ post_install_message:
143
143
  rdoc_options: []
144
144
  require_paths:
145
145
  - lib
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  version: 1.3.1
156
156
  requirements: []
157
157
  rubygems_version: 3.4.19
158
- signing_key:
158
+ signing_key:
159
159
  specification_version: 4
160
160
  summary: AnyCable integration for Rails (w/o RPC dependencies)
161
161
  test_files: []