dexiecable 2.0.0.alpha1 → 2.0.0.alpha2

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: 5262c05d144bc7c002152fd8da1918e87421f4ec81a060100b71c57237c152be
4
- data.tar.gz: 339cf7b68cd9923b0b20b4a74c0caf563699be7ff8fbaf32ace71728a87fc787
3
+ metadata.gz: 714562cd7c933eb48e81e9159acd326d77b6133a807cdd541000f350281c1c94
4
+ data.tar.gz: d3bcacdc18d5f9c7a8be970f9ede859be19e282e8ca35aa4d27c81e581310eb3
5
5
  SHA512:
6
- metadata.gz: e315b48c4d222dd5c4fb04056dded3f61d9d76584dfc7ee02d1645b6d28521120130b945cda897ca6682b7d6483232a3f6b92a3220bc417dc9fb6d8718169416
7
- data.tar.gz: a5c155688bd21d6970842b86f28d2f9e4d901561fb5e786a59ed3447ae7b96db083d5b63e1d724b7fc8c5b7c2428661d713b00a5dc41a5c5b0f2a0f62ca568cc
6
+ metadata.gz: ed0dbe4fdfade70f3300d9c2a61882f6a00320c384fe74ad76b6ba11ef0733a26b86f6949606117b4847efdd5221709bf1a091088a510a0155d6ff9f48a87774
7
+ data.tar.gz: d5cef46c7417c0e34ff4e08c08e0df846ff653f19ae0eeacbffe9de433a362c9ae9af60b32f669a6daa301b64a05d3844f227587cf20af4da23ecf149b39cfb9
data/README.md CHANGED
@@ -85,7 +85,7 @@ For an ActiveRecord model it signs the record's GlobalID:
85
85
 
86
86
  ```ruby
87
87
  DexieChannel.stream_token_for(current_user)
88
- # => "eyJkYXRhIjoiZGV4aWVfY2FibGU6ZGV4aWVfY2hhbm5lbDpnaWQ6Ly9hcHAvVXNlci8xIn0=--signature"
88
+ # => "signed token for gid://app/User/1"
89
89
  ```
90
90
 
91
91
  Send that token to the client (render it in a view, return it from an endpoint, etc.) and add it to the subscription:
@@ -107,6 +107,24 @@ subscription.removeStream(userStream);
107
107
  subscription.removeAllStreams();
108
108
  ```
109
109
 
110
+ #### Initial data on subscribe
111
+
112
+ To push a snapshot when a stream is added, set `DexieChannel.on_subscribe`. It receives the channel and the subscribed record (resolved from the signed GlobalID), so you can dispatch on the record type:
113
+
114
+ ```ruby
115
+ # config/initializers/dexiecable.rb
116
+ DexieChannel.on_subscribe = ->(channel, record) do
117
+ case record
118
+ when User
119
+ channel.table("notifications").bulkAdd(record.notifications.map(&:as_json_for_dexie))
120
+ when Conversation
121
+ channel.table("messages").bulkAdd(record.messages.map(&:as_json_for_dexie))
122
+ end
123
+ end
124
+ ```
125
+
126
+ The callback runs after the stream is opened, and `channel.table(...)` transmits to just this subscriber — so the snapshot arrives before any live mutation.
127
+
110
128
  #### Public streams
111
129
 
112
130
  For data that's public (a global feed, announcements, etc.), skip the signature. Use a string target — it's namespaced under `public:` automatically:
@@ -13,9 +13,23 @@ module DexieCable
13
13
  # # public (no signature, namespaced under "public:")
14
14
  # subscription.addPublicStream("feed")
15
15
  #
16
+ # When a private stream is added, +on_subscribe+ is invoked with the
17
+ # channel and the subscribed record, so initial data can be pushed:
18
+ #
19
+ # DexieChannel.on_subscribe = ->(channel, record) do
20
+ # case record
21
+ # when User
22
+ # channel.table("notifications").bulkAdd(record.notifications.map(&:as_json_for_dexie))
23
+ # when Conversation
24
+ # channel.table("messages").bulkAdd(record.messages.map(&:as_json_for_dexie))
25
+ # end
26
+ # end
27
+ #
16
28
  class DexieChannel < ActionCable::Channel::Base
17
29
  PUBLIC_STREAM_PREFIX = "public:"
18
30
 
31
+ class_attribute :on_subscribe, instance_accessor: false, default: nil
32
+
19
33
  public :transmit
20
34
 
21
35
  # Open a scoped channel for broadcasting to a specific recipient.
@@ -40,11 +54,11 @@ module DexieCable
40
54
  Query.new(self, name)
41
55
  end
42
56
 
43
- # Returns a signed token for the stream identifier of +target+ (private
44
- # record-based streams). Send it to the client, which passes it to
57
+ # Returns a signed token for +target+ (a record or other private
58
+ # target). Send it to the client, which passes it to
45
59
  # +subscription.addStream+.
46
60
  def self.stream_token_for(target)
47
- verifier.generate(broadcasting_for(target))
61
+ verifier.generate(target.respond_to?(:to_gid_param) ? target.to_gid_param : target.to_s)
48
62
  end
49
63
 
50
64
  def self.verifier
@@ -56,13 +70,18 @@ module DexieCable
56
70
  end
57
71
 
58
72
  def add_stream(data)
59
- stream = verified_stream(data["stream"])
60
- stream_from stream if stream
73
+ target = verified_target(data["stream"])
74
+ return unless target
75
+
76
+ stream_for target
77
+ self.class.on_subscribe&.call(self, resolve_subscribe_target(target))
61
78
  end
62
79
 
63
80
  def remove_stream(data)
64
- stream = verified_stream(data["stream"])
65
- stop_stream_from stream if stream
81
+ target = verified_target(data["stream"])
82
+ return unless target
83
+
84
+ stop_stream_from self.class.broadcasting_for(target)
66
85
  end
67
86
 
68
87
  def remove_all_streams(_data)
@@ -85,12 +104,16 @@ module DexieCable
85
104
  self.class.broadcasting_for("#{PUBLIC_STREAM_PREFIX}#{name}")
86
105
  end
87
106
 
88
- def verified_stream(token)
107
+ def verified_target(token)
89
108
  return unless token.present?
90
109
 
91
110
  self.class.verifier.verify(token)
92
111
  rescue ActiveSupport::MessageVerifier::InvalidSignature
93
112
  nil
94
113
  end
114
+
115
+ def resolve_subscribe_target(target)
116
+ target.start_with?("gid://") ? GlobalID::Locator.locate(target) : target
117
+ end
95
118
  end
96
119
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DexieCable
4
- VERSION = "2.0.0.alpha1"
4
+ VERSION = "2.0.0.alpha2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dexiecable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha1
4
+ version: 2.0.0.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Buhrmester