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

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 395f76c02adbd3f4878b55bb21bf4bd00969e4394e824fb7a23f086d8b221b1c
4
- data.tar.gz: b300f5b2ab64aa893d462a22045587f65531bbaea8dce3a920c1fb1df67b211e
3
+ metadata.gz: 2fa2800d673ee7d03d6faee822368319e1930f4f31336127a09c10ac536048d3
4
+ data.tar.gz: 19b10b1b47fee99b344e40371e6f3159627d18118768d50812a07cc22324fe43
5
5
  SHA512:
6
- metadata.gz: f0a2f228649539c86b8e3f1a96f0c456b6ed0f933552fb93c90ef2d4a5c49261fdbdf9f3e7b650cd69b00ca38bddcf202bb6f1d730aa92ad07ec3f8504128904
7
- data.tar.gz: dfce4029440d91a5a7f07abccca089b6b0bb759d152aa2fadad9ccb12ca0533a5d10cba6e200f398ce58c54c76c5b0fa5903c48aeacba2354dc8b5f9ad37d10f
6
+ metadata.gz: c7ed672ed4817e197bc43a2839642556a432be2dd41916841cbfc065135afa3009ca4592f84159c58c804e5e1050e27db3b767e0856493ece3690427c7675a33
7
+ data.tar.gz: 5ddc58e66b3f7d49eda206fbba61b993789ab92ba4adb382276a550a3492b571d53722f0f9bbfdee13a61d2df6874a7859e793446d3f2951fe441a4f4d94585a
data/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Change log
2
2
 
3
- ## master
3
+ ## main
4
+
5
+ ## 1.6.0.rc.2 (2025-02-10)
6
+
7
+ - Add Presence API. ([@palkan][])
4
8
 
5
9
  ## 1.5.5 (2024-12-12)
6
10
 
@@ -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
@@ -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.2"
6
6
  end
7
7
  end
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.2
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-11 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: []