Class: Parse::LiveQuery::Subscription
- Inherits:
-
Object
- Object
- Parse::LiveQuery::Subscription
- Defined in:
- lib/parse/live_query/subscription.rb
Overview
Represents an active subscription to a LiveQuery. Manages event callbacks and subscription lifecycle.
Instance Attribute Summary collapse
-
#class_name ⇒ String
readonly
Parse class name being subscribed to.
-
#client ⇒ Parse::LiveQuery::Client
readonly
The LiveQuery client.
-
#fields ⇒ Array<String>
readonly
Fields to watch for changes (nil = all fields).
-
#query ⇒ Hash
readonly
The query constraints (where clause).
-
#request_id ⇒ Integer
readonly
Unique request ID for this subscription.
-
#session_token ⇒ String?
readonly
Session token for ACL-aware subscriptions.
Instance Method Summary collapse
-
#confirm! ⇒ Object
private
Mark subscription as confirmed by server.
-
#error? ⇒ Boolean
True if in error state.
-
#fail!(error) ⇒ Object
private
Mark subscription as failed with error.
-
#handle_event(event) ⇒ Object
private
Handle an incoming event from the server.
-
#initialize(client:, class_name:, query: {}, fields: nil, session_token: nil, use_master_key: false) ⇒ Subscription
constructor
Create a new subscription.
-
#inspect ⇒ String
Redacting inspect — the default
inspectwould expose@session_token(and, via@client, the client's master/REST keys) in any log line, backtrace, error page, or error reporter that renders the subscription. -
#on(event_type) {|object, original| ... } ⇒ self
Register a callback for a specific event type.
-
#on_create {|Parse::Object| ... } ⇒ self
Register callback for create events.
-
#on_delete {|Parse::Object| ... } ⇒ self
Register callback for delete events.
-
#on_enter {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for enter events (object now matches query).
-
#on_error {|Exception| ... } ⇒ self
Register callback for errors.
-
#on_leave {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for leave events (object no longer matches query).
-
#on_subscribe { ... } ⇒ self
Register callback for successful subscription.
-
#on_unsubscribe { ... } ⇒ self
Register callback for unsubscription.
-
#on_update {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for update events.
-
#pending? ⇒ Boolean
True if pending subscription confirmation.
-
#state ⇒ Symbol
Current subscription state.
-
#subscribed? ⇒ Boolean
True if currently subscribed.
-
#to_h ⇒ Hash
Subscription info as hash.
-
#to_subscribe_message ⇒ Hash
Build the subscription message to send to the server.
-
#to_unsubscribe_message ⇒ Hash
Build the unsubscribe message.
-
#unsubscribe ⇒ Boolean
Unsubscribe from this subscription.
-
#unsubscribed? ⇒ Boolean
True if unsubscribed.
-
#use_master_key? ⇒ Boolean
Whether this subscription opted into per-subscription master-key auth via
use_master_key: true.
Constructor Details
#initialize(client:, class_name:, query: {}, fields: nil, session_token: nil, use_master_key: false) ⇒ Subscription
Create a new subscription
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/parse/live_query/subscription.rb', line 88 def initialize(client:, class_name:, query: {}, fields: nil, session_token: nil, use_master_key: false) @monitor = Monitor.new @client = client @class_name = class_name @query = query @fields = fields @session_token = session_token @use_master_key = use_master_key == true @request_id = generate_request_id @state = :pending @callbacks = Hash.new { |h, k| h[k] = [] } Logging.debug("Subscription created", request_id: @request_id, class_name: @class_name, query_keys: @query.keys) end |
Instance Attribute Details
#class_name ⇒ String (readonly)
Returns Parse class name being subscribed to.
57 58 59 |
# File 'lib/parse/live_query/subscription.rb', line 57 def class_name @class_name end |
#client ⇒ Parse::LiveQuery::Client (readonly)
Returns the LiveQuery client.
63 64 65 |
# File 'lib/parse/live_query/subscription.rb', line 63 def client @client end |
#fields ⇒ Array<String> (readonly)
Returns fields to watch for changes (nil = all fields).
66 67 68 |
# File 'lib/parse/live_query/subscription.rb', line 66 def fields @fields end |
#query ⇒ Hash (readonly)
Returns the query constraints (where clause).
60 61 62 |
# File 'lib/parse/live_query/subscription.rb', line 60 def query @query end |
#request_id ⇒ Integer (readonly)
Returns unique request ID for this subscription.
54 55 56 |
# File 'lib/parse/live_query/subscription.rb', line 54 def request_id @request_id end |
#session_token ⇒ String? (readonly)
Returns session token for ACL-aware subscriptions.
69 70 71 |
# File 'lib/parse/live_query/subscription.rb', line 69 def session_token @session_token end |
Instance Method Details
#confirm! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Mark subscription as confirmed by server
285 286 287 288 289 290 291 |
# File 'lib/parse/live_query/subscription.rb', line 285 def confirm! @monitor.synchronize { @state = :subscribed } Logging.info("Subscription confirmed", request_id: @request_id, class_name: @class_name) emit(:subscribe) end |
#error? ⇒ Boolean
Returns true if in error state.
226 227 228 |
# File 'lib/parse/live_query/subscription.rb', line 226 def error? state == :error end |
#fail!(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Mark subscription as failed with error
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/parse/live_query/subscription.rb', line 296 def fail!(error) @monitor.synchronize { @state = :error } # Promote String errors (which come back from the LiveQuery # server with messages like "Permission denied (code: 101)") # to typed SubscriptionError instances carrying the request_id # and class_name as structured context. The resulting # `e.message` reads `request_id=<n> class=<X> <server message>`, # so a single-line log captures the operational context the # raw server string lacks. if error.is_a?(String) error = SubscriptionError.new(error, request_id: @request_id, class_name: @class_name) end Logging.error("Subscription failed", request_id: @request_id, class_name: @class_name, error: error) emit(:error, error) end |
#handle_event(event) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Handle an incoming event from the server
276 277 278 279 280 281 |
# File 'lib/parse/live_query/subscription.rb', line 276 def handle_event(event) Logging.debug("Handling event", request_id: @request_id, event_type: event.type) emit(event.type, event.object, event.original) end |
#inspect ⇒ String
Redacting inspect — the default inspect would expose
@session_token (and, via @client, the client's master/REST
keys) in any log line, backtrace, error page, or error reporter
that renders the subscription. Reads @state directly rather
than through the monitor so a diagnostic inspect never blocks on
the lock.
120 121 122 123 124 125 |
# File 'lib/parse/live_query/subscription.rb', line 120 def inspect token = @session_token.nil? || @session_token.empty? ? "nil" : "[REDACTED]" "#<#{self.class.name} request_id=#{@request_id.inspect} " \ "class_name=#{@class_name.inspect} state=#{@state.inspect} " \ "use_master_key=#{@use_master_key} session_token=#{token}>" end |
#on(event_type) {|object, original| ... } ⇒ self
Register a callback for a specific event type
131 132 133 134 135 136 137 138 |
# File 'lib/parse/live_query/subscription.rb', line 131 def on(event_type, &block) return self unless block_given? @monitor.synchronize do @callbacks[event_type.to_sym] << block end self end |
#on_create {|Parse::Object| ... } ⇒ self
Register callback for create events
143 144 145 |
# File 'lib/parse/live_query/subscription.rb', line 143 def on_create(&block) on(:create, &block) end |
#on_delete {|Parse::Object| ... } ⇒ self
Register callback for delete events
157 158 159 |
# File 'lib/parse/live_query/subscription.rb', line 157 def on_delete(&block) on(:delete, &block) end |
#on_enter {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for enter events (object now matches query)
164 165 166 |
# File 'lib/parse/live_query/subscription.rb', line 164 def on_enter(&block) on(:enter, &block) end |
#on_error {|Exception| ... } ⇒ self
Register callback for errors
178 179 180 |
# File 'lib/parse/live_query/subscription.rb', line 178 def on_error(&block) on(:error, &block) end |
#on_leave {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for leave events (object no longer matches query)
171 172 173 |
# File 'lib/parse/live_query/subscription.rb', line 171 def on_leave(&block) on(:leave, &block) end |
#on_subscribe { ... } ⇒ self
Register callback for successful subscription
185 186 187 |
# File 'lib/parse/live_query/subscription.rb', line 185 def on_subscribe(&block) on(:subscribe, &block) end |
#on_unsubscribe { ... } ⇒ self
Register callback for unsubscription
192 193 194 |
# File 'lib/parse/live_query/subscription.rb', line 192 def on_unsubscribe(&block) on(:unsubscribe, &block) end |
#on_update {|Parse::Object, Parse::Object| ... } ⇒ self
Register callback for update events
150 151 152 |
# File 'lib/parse/live_query/subscription.rb', line 150 def on_update(&block) on(:update, &block) end |
#pending? ⇒ Boolean
Returns true if pending subscription confirmation.
216 217 218 |
# File 'lib/parse/live_query/subscription.rb', line 216 def pending? state == :pending end |
#state ⇒ Symbol
Current subscription state
109 110 111 |
# File 'lib/parse/live_query/subscription.rb', line 109 def state @monitor.synchronize { @state } end |
#subscribed? ⇒ Boolean
Returns true if currently subscribed.
211 212 213 |
# File 'lib/parse/live_query/subscription.rb', line 211 def subscribed? state == :subscribed end |
#to_h ⇒ Hash
Returns subscription info as hash.
316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/parse/live_query/subscription.rb', line 316 def to_h @monitor.synchronize do { request_id: request_id, class_name: class_name, query: query, state: @state, fields: fields, } end end |
#to_subscribe_message ⇒ Hash
Build the subscription message to send to the server
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/parse/live_query/subscription.rb', line 232 def msg = { op: "subscribe", requestId: request_id, query: { className: class_name, where: query, }, } msg[:query][:fields] = fields if fields&.any? msg[:sessionToken] = session_token if session_token # The subscribe frame deliberately NEVER carries `masterKey`. # Parse Server's `_handleSubscribe` does not read it — master-key # (ACL-bypass) authorization is resolved once, per connection, in # `_handleConnect` (`client.hasMasterKey`). Emitting it here put a # privileged credential on the wire for ZERO server-side effect. # `use_master_key: true` at the subscription level is an intent # assertion validated by the client (which warns when it cannot # be honored on a non-admin connection); the actual elevation is # the admin connection's connect frame. See # {Parse::LiveQuery::Client#use_master_key}. msg end |
#to_unsubscribe_message ⇒ Hash
Build the unsubscribe message
266 267 268 269 270 271 |
# File 'lib/parse/live_query/subscription.rb', line 266 def { op: "unsubscribe", requestId: request_id, } end |
#unsubscribe ⇒ Boolean
Unsubscribe from this subscription
198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/parse/live_query/subscription.rb', line 198 def unsubscribe @monitor.synchronize do return false if @state == :unsubscribed @state = :unsubscribed end Logging.debug("Unsubscribing", request_id: @request_id) client.unsubscribe(self) emit(:unsubscribe) true end |
#unsubscribed? ⇒ Boolean
Returns true if unsubscribed.
221 222 223 |
# File 'lib/parse/live_query/subscription.rb', line 221 def unsubscribed? state == :unsubscribed end |
#use_master_key? ⇒ Boolean
Returns whether this subscription opted into
per-subscription master-key auth via use_master_key: true.
260 261 262 |
# File 'lib/parse/live_query/subscription.rb', line 260 def use_master_key? @use_master_key == true end |