ably-pubsub-core 0.0.1.pre
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 +7 -0
- data/lib/ably/agent.rb +8 -0
- data/lib/ably/auth.rb +791 -0
- data/lib/ably/exceptions.rb +169 -0
- data/lib/ably/logger.rb +119 -0
- data/lib/ably/models/auth_details.rb +45 -0
- data/lib/ably/models/channel_details.rb +69 -0
- data/lib/ably/models/channel_metrics.rb +107 -0
- data/lib/ably/models/channel_occupancy.rb +50 -0
- data/lib/ably/models/channel_options.rb +120 -0
- data/lib/ably/models/channel_state_change.rb +84 -0
- data/lib/ably/models/channel_status.rb +63 -0
- data/lib/ably/models/cipher_params.rb +137 -0
- data/lib/ably/models/connection_details.rb +149 -0
- data/lib/ably/models/connection_state_change.rb +83 -0
- data/lib/ably/models/delta_extras.rb +28 -0
- data/lib/ably/models/device_details.rb +126 -0
- data/lib/ably/models/device_push_details.rb +94 -0
- data/lib/ably/models/error_info.rb +104 -0
- data/lib/ably/models/http_paginated_response.rb +112 -0
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +235 -0
- data/lib/ably/models/message.rb +223 -0
- data/lib/ably/models/message_encoders/base.rb +135 -0
- data/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/ably/models/message_encoders/cipher.rb +84 -0
- data/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_result.rb +201 -0
- data/lib/ably/models/presence_message.rb +244 -0
- data/lib/ably/models/protocol_message.rb +288 -0
- data/lib/ably/models/push_channel_subscription.rb +114 -0
- data/lib/ably/models/stats.rb +242 -0
- data/lib/ably/models/stats_types.rb +107 -0
- data/lib/ably/models/token_details.rb +148 -0
- data/lib/ably/models/token_request.rb +180 -0
- data/lib/ably/modules/ably.rb +26 -0
- data/lib/ably/modules/async_wrapper.rb +69 -0
- data/lib/ably/modules/channels_collection.rb +105 -0
- data/lib/ably/modules/conversions.rb +153 -0
- data/lib/ably/modules/encodeable.rb +111 -0
- data/lib/ably/modules/enum.rb +230 -0
- data/lib/ably/modules/event_emitter.rb +200 -0
- data/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/ably/modules/message_emitter.rb +78 -0
- data/lib/ably/modules/message_pack.rb +14 -0
- data/lib/ably/modules/model_common.rb +84 -0
- data/lib/ably/modules/safe_deferrable.rb +83 -0
- data/lib/ably/modules/safe_yield.rb +41 -0
- data/lib/ably/modules/state_emitter.rb +181 -0
- data/lib/ably/modules/state_machine.rb +59 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +111 -0
- data/lib/ably/realtime/auth.rb +283 -0
- data/lib/ably/realtime/channel/channel_manager.rb +272 -0
- data/lib/ably/realtime/channel/channel_properties.rb +40 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +104 -0
- data/lib/ably/realtime/channel/publisher.rb +82 -0
- data/lib/ably/realtime/channel/push_channel.rb +69 -0
- data/lib/ably/realtime/channel.rb +440 -0
- data/lib/ably/realtime/channels.rb +71 -0
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +225 -0
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +87 -0
- data/lib/ably/realtime/client.rb +363 -0
- data/lib/ably/realtime/connection/connection_manager.rb +594 -0
- data/lib/ably/realtime/connection/connection_state_machine.rb +144 -0
- data/lib/ably/realtime/connection/websocket_transport.rb +287 -0
- data/lib/ably/realtime/connection.rb +738 -0
- data/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/ably/realtime/presence/members_map.rb +395 -0
- data/lib/ably/realtime/presence/presence_manager.rb +78 -0
- data/lib/ably/realtime/presence/presence_state_machine.rb +57 -0
- data/lib/ably/realtime/presence.rb +502 -0
- data/lib/ably/realtime/push/admin.rb +75 -0
- data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/ably/realtime/push.rb +25 -0
- data/lib/ably/realtime/recovery_key_context.rb +36 -0
- data/lib/ably/realtime.rb +60 -0
- data/lib/ably/rest/channel/push_channel.rb +59 -0
- data/lib/ably/rest/channel.rb +194 -0
- data/lib/ably/rest/channels.rb +47 -0
- data/lib/ably/rest/client.rb +727 -0
- data/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/ably/rest/middleware/exceptions.rb +53 -0
- data/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +22 -0
- data/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/ably/rest/middleware/parse_message_pack.rb +43 -0
- data/lib/ably/rest/presence.rb +113 -0
- data/lib/ably/rest/push/admin.rb +58 -0
- data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/ably/rest/push/device_registrations.rb +114 -0
- data/lib/ably/rest/push.rb +25 -0
- data/lib/ably/rest.rb +40 -0
- data/lib/ably/util/ably_extensions.rb +29 -0
- data/lib/ably/util/crypto.rb +134 -0
- data/lib/ably/util/pub_sub.rb +45 -0
- data/lib/ably/util/safe_deferrable.rb +44 -0
- data/lib/ably/version.rb +7 -0
- data/lib/ably.rb +16 -0
- metadata +497 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
# Contains a page of results for message or presence history, stats, or REST presence requests.
|
|
3
|
+
# A PaginatedResult response from a REST API paginated query is also accompanied by metadata
|
|
4
|
+
# that indicates the relative queries available to the PaginatedResult object.
|
|
5
|
+
#
|
|
6
|
+
class PaginatedResult
|
|
7
|
+
include Ably::Modules::AsyncWrapper if defined?(Ably::Realtime)
|
|
8
|
+
|
|
9
|
+
# Contains the current page of results; for example, an array of {Ably::Models::Message} or {Ably::Models::PresenceMessage} objects
|
|
10
|
+
# for a channel history request.
|
|
11
|
+
#
|
|
12
|
+
# @spec TG3
|
|
13
|
+
#
|
|
14
|
+
# @return [Array]
|
|
15
|
+
#
|
|
16
|
+
attr_reader :items
|
|
17
|
+
|
|
18
|
+
# @param [Faraday::Response] http_response Initial HTTP response from an Ably request to a paged resource
|
|
19
|
+
# @param [String] base_url Base URL for request that generated the http_response so that subsequent paged requests can be made
|
|
20
|
+
# @param [Client] client {Ably::Client} used to make the request to Ably
|
|
21
|
+
# @param [Hash] options Options for this paged resource
|
|
22
|
+
# @option options [Symbol,String] :coerce_into symbol or string representing class that should be used to create each item in the PaginatedResult
|
|
23
|
+
#
|
|
24
|
+
# @yield [Object] block will be called for each resource object for the current page. This is a useful way to apply a transformation to any page resources after they are retrieved
|
|
25
|
+
#
|
|
26
|
+
# @return [PaginatedResult]
|
|
27
|
+
#
|
|
28
|
+
def initialize(http_response, base_url, client, options = {}, &each_block)
|
|
29
|
+
@http_response = http_response
|
|
30
|
+
@client = client
|
|
31
|
+
@base_url = "#{base_url.gsub(%r{/[^/]*$}, '')}/"
|
|
32
|
+
@coerce_into = options[:coerce_into]
|
|
33
|
+
@raw_body = http_response.body
|
|
34
|
+
@each_block = each_block
|
|
35
|
+
@make_async = options.fetch(:async_blocking_operations, false)
|
|
36
|
+
|
|
37
|
+
@items = http_response.body
|
|
38
|
+
if @items.nil? || @items.to_s.strip.empty?
|
|
39
|
+
@items = []
|
|
40
|
+
end
|
|
41
|
+
@items = [@items] if @items.kind_of?(Hash)
|
|
42
|
+
|
|
43
|
+
@items = coerce_items_into(items, @coerce_into) if @coerce_into
|
|
44
|
+
@items = items.map { |item| yield item } if block_given?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns a new PaginatedResult for the first page of results.
|
|
48
|
+
#
|
|
49
|
+
# @spec TG5
|
|
50
|
+
#
|
|
51
|
+
# @return [PaginatedResult, Ably::Util::SafeDeferrable]
|
|
52
|
+
#
|
|
53
|
+
def first(&success_callback)
|
|
54
|
+
async_wrap_if_realtime(success_callback) do
|
|
55
|
+
return nil unless supports_pagination?
|
|
56
|
+
PaginatedResult.new(client.get(pagination_url('first')), base_url, client, pagination_options, &each_block)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Retrieve the next page of results.
|
|
61
|
+
#
|
|
62
|
+
# When used as part of the {Ably::Realtime} library, it will return a {Ably::Util::SafeDeferrable} object,
|
|
63
|
+
# and allows an optional success callback block to be provided.
|
|
64
|
+
#
|
|
65
|
+
# @spec TG4
|
|
66
|
+
#
|
|
67
|
+
# @return [PaginatedResult,Ably::Util::SafeDeferrable]
|
|
68
|
+
#
|
|
69
|
+
def next(&success_callback)
|
|
70
|
+
async_wrap_if_realtime(success_callback) do
|
|
71
|
+
return nil unless has_next?
|
|
72
|
+
PaginatedResult.new(client.get(pagination_url('next')), base_url, client, pagination_options, &each_block)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Returns true if this page is the last page and returns false if there are more pages available by calling next available.
|
|
77
|
+
#
|
|
78
|
+
# @spec TG7
|
|
79
|
+
#
|
|
80
|
+
# @return [Boolean]
|
|
81
|
+
#
|
|
82
|
+
def last?
|
|
83
|
+
!supports_pagination? ||
|
|
84
|
+
pagination_header('next').nil?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns true if there are more pages available by calling next and returns false if this page is the last page available.
|
|
88
|
+
#
|
|
89
|
+
# @spec TG6
|
|
90
|
+
#
|
|
91
|
+
# @return [Boolean]
|
|
92
|
+
#
|
|
93
|
+
def has_next?
|
|
94
|
+
supports_pagination? && !last?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# True if the HTTP response supports paging with the expected LINK HTTP headers
|
|
98
|
+
#
|
|
99
|
+
# @return [Boolean]
|
|
100
|
+
#
|
|
101
|
+
def supports_pagination?
|
|
102
|
+
!pagination_headers.empty?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def inspect
|
|
106
|
+
<<-EOF.gsub(/^ /, '')
|
|
107
|
+
#<#{self.class.name}:#{self.object_id}
|
|
108
|
+
@base_url="#{base_url}",
|
|
109
|
+
@last?=#{!!last?},
|
|
110
|
+
@has_next?=#{!!has_next?},
|
|
111
|
+
@items=
|
|
112
|
+
#{items.map { |item| item.inspect }.join(",\n ") }
|
|
113
|
+
>
|
|
114
|
+
EOF
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
def http_response
|
|
119
|
+
@http_response
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def base_url
|
|
123
|
+
@base_url
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def client
|
|
127
|
+
@client
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def coerce_into
|
|
131
|
+
@coerce_into
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def raw_body
|
|
135
|
+
@raw_body
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def each_block
|
|
139
|
+
@each_block
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def make_async
|
|
143
|
+
@make_async
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def coerce_items_into(items, type_string)
|
|
147
|
+
items.map do |item|
|
|
148
|
+
@coerce_into.split('::').inject(Kernel) do |base, klass_name|
|
|
149
|
+
base.public_send(:const_get, klass_name)
|
|
150
|
+
end.new(item)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def pagination_headers
|
|
155
|
+
link_regex = %r{<(?<url>[^>]+)>; rel="(?<rel>[^"]+)"}
|
|
156
|
+
@pagination_headers ||= begin
|
|
157
|
+
# All `Link:` headers are concatenated by Faraday into a comma separated list
|
|
158
|
+
# Finding matching `<url>; rel="rel"` pairs
|
|
159
|
+
link_headers = http_response.headers['link'] || ''
|
|
160
|
+
link_headers.scan(link_regex).each_with_object({}) do |val_array, hash|
|
|
161
|
+
url, rel = val_array
|
|
162
|
+
hash[rel] = url
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def pagination_header(id)
|
|
168
|
+
pagination_headers[id]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def pagination_url(id)
|
|
172
|
+
raise Ably::Exceptions::PageMissing, "Paging header link #{id} does not exist" unless pagination_header(id)
|
|
173
|
+
|
|
174
|
+
if pagination_header(id).match(%r{^\./})
|
|
175
|
+
"#{base_url}#{pagination_header(id)[2..-1]}"
|
|
176
|
+
else
|
|
177
|
+
pagination_header[id]
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def pagination_options
|
|
182
|
+
{
|
|
183
|
+
coerce_into: coerce_into,
|
|
184
|
+
async_blocking_operations: make_async
|
|
185
|
+
}
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def async_wrap_if_realtime(success_callback, &operation)
|
|
189
|
+
if make_async
|
|
190
|
+
raise 'EventMachine is required for asynchronous operations' unless defined?(EventMachine)
|
|
191
|
+
async_wrap success_callback, &operation
|
|
192
|
+
else
|
|
193
|
+
yield
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def logger
|
|
198
|
+
client.logger
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
# Convert presence_messsage argument to a {PresenceMessage} object and associate with a protocol message if provided
|
|
3
|
+
#
|
|
4
|
+
# @param presence_message [PresenceMessage,Hash] A presence message object or Hash of presence message properties
|
|
5
|
+
# @param [Hash] options (see PresenceMessage#initialize)
|
|
6
|
+
#
|
|
7
|
+
# @return [PresenceMessage]
|
|
8
|
+
#
|
|
9
|
+
def self.PresenceMessage(presence_message, options = {})
|
|
10
|
+
case presence_message
|
|
11
|
+
when PresenceMessage
|
|
12
|
+
presence_message.tap do
|
|
13
|
+
presence_message.assign_to_protocol_message options[:protocol_message] if options[:protocol_message]
|
|
14
|
+
end
|
|
15
|
+
else
|
|
16
|
+
PresenceMessage.new(presence_message, options)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# A class representing an individual presence message to be sent or received
|
|
21
|
+
# via the Ably Realtime service.
|
|
22
|
+
#
|
|
23
|
+
class PresenceMessage
|
|
24
|
+
include Ably::Modules::Conversions
|
|
25
|
+
include Ably::Modules::Encodeable
|
|
26
|
+
include Ably::Modules::ModelCommon
|
|
27
|
+
include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
|
|
28
|
+
extend Ably::Modules::Enum
|
|
29
|
+
|
|
30
|
+
# Describes the possible actions members in the presence set can emit.
|
|
31
|
+
#
|
|
32
|
+
# ABSENT TP2 A member is not present in the channel.
|
|
33
|
+
# PRESENT TP2 When subscribing to presence events on a channel that already has members present, this event is emitted for every member already present on the channel before the subscribe listener was registered.
|
|
34
|
+
# ENTER TP2 A new member has entered the channel.
|
|
35
|
+
# LEAVE TP2 A member who was present has now left the channel. This may be a result of an explicit request to leave or implicitly when detaching from the channel. Alternatively, if a member's connection is abruptly disconnected and they do not resume their connection within a minute, Ably treats this as a leave event as the client is no longer present.
|
|
36
|
+
# UPDATE TP2 An already present member has updated their member data. Being notified of member data updates can be very useful, for example, it can be used to update the status of a user when they are typing a message.
|
|
37
|
+
#
|
|
38
|
+
# @spec TP2
|
|
39
|
+
#
|
|
40
|
+
ACTION = ruby_enum('ACTION',
|
|
41
|
+
:absent,
|
|
42
|
+
:present,
|
|
43
|
+
:enter,
|
|
44
|
+
:leave,
|
|
45
|
+
:update
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Statically register a default set of encoders for this class
|
|
49
|
+
Ably::Models::MessageEncoders.register_default_encoders self
|
|
50
|
+
|
|
51
|
+
# {PresenceMessage} initializer
|
|
52
|
+
#
|
|
53
|
+
# @param attributes [Hash] object with the underlying presence message key value attributes
|
|
54
|
+
# @param [Hash] options an options Hash for this initializer
|
|
55
|
+
# @option options [ProtocolMessage] :protocol_message An optional protocol message to assocate the presence message with
|
|
56
|
+
# @option options [Logger] :logger An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
|
|
57
|
+
#
|
|
58
|
+
def initialize(attributes, options = {})
|
|
59
|
+
@logger = options[:logger] # Logger expected for SafeDeferrable
|
|
60
|
+
@protocol_message = options[:protocol_message]
|
|
61
|
+
@raw_hash_object = attributes
|
|
62
|
+
|
|
63
|
+
set_attributes_object attributes
|
|
64
|
+
|
|
65
|
+
self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
|
|
66
|
+
self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
|
|
67
|
+
self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding
|
|
68
|
+
|
|
69
|
+
self.attributes.freeze
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The ID of the client that published the PresenceMessage.
|
|
73
|
+
#
|
|
74
|
+
# @spec TP3c
|
|
75
|
+
#
|
|
76
|
+
# @return [String]
|
|
77
|
+
#
|
|
78
|
+
def client_id
|
|
79
|
+
attributes[:client_id]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The payload of the {Ably::Models::PresenceMessage}.
|
|
83
|
+
#
|
|
84
|
+
# @spec TP3e
|
|
85
|
+
#
|
|
86
|
+
# @return [Hash, nil]
|
|
87
|
+
#
|
|
88
|
+
def data
|
|
89
|
+
attributes[:data]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# This will typically be empty as all presence messages received from Ably are automatically decoded client-side
|
|
93
|
+
# using this value. However, if the message encoding cannot be processed, this attribute will contain the remaining
|
|
94
|
+
# transformations not applied to the data payload.
|
|
95
|
+
#
|
|
96
|
+
# @spec TP3f
|
|
97
|
+
#
|
|
98
|
+
# @return [String]
|
|
99
|
+
#
|
|
100
|
+
def encoding
|
|
101
|
+
attributes[:encoding]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# A unique ID assigned to each {Ably::Models::PresenceMessage} by Ably.
|
|
105
|
+
#
|
|
106
|
+
# @spec TP3a
|
|
107
|
+
#
|
|
108
|
+
# @return [String]
|
|
109
|
+
#
|
|
110
|
+
def id
|
|
111
|
+
attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# The ID of the connection associated with the client that published the {Ably::Models::PresenceMessage}.
|
|
115
|
+
#
|
|
116
|
+
# @spec TP3d
|
|
117
|
+
#
|
|
118
|
+
# @return [String]
|
|
119
|
+
#
|
|
120
|
+
def connection_id
|
|
121
|
+
attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Combines clientId and connectionId to ensure that multiple connected clients with an identical clientId are uniquely
|
|
125
|
+
# identifiable. A string function that returns the combined clientId and connectionId.
|
|
126
|
+
#
|
|
127
|
+
# @spec TP3h
|
|
128
|
+
#
|
|
129
|
+
# @return [String]
|
|
130
|
+
#
|
|
131
|
+
def member_key
|
|
132
|
+
"#{connection_id}:#{client_id}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# The time the {Ably::Models::PresenceMessage} was received by Ably, as milliseconds since the Unix epoch.
|
|
136
|
+
#
|
|
137
|
+
# @spec TP3g
|
|
138
|
+
#
|
|
139
|
+
# @return [Integer]
|
|
140
|
+
#
|
|
141
|
+
def timestamp
|
|
142
|
+
if attributes[:timestamp]
|
|
143
|
+
as_time_from_epoch(attributes[:timestamp])
|
|
144
|
+
else
|
|
145
|
+
protocol_message.timestamp
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# The type of {Ably::Models::PresenceMessage::ACTION} the PresenceMessage is for.
|
|
150
|
+
#
|
|
151
|
+
# @spec TP3b
|
|
152
|
+
#
|
|
153
|
+
# @return [Ably::Models::PresenceMessage::ACTION]
|
|
154
|
+
#
|
|
155
|
+
def action
|
|
156
|
+
ACTION(attributes[:action])
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def attributes
|
|
160
|
+
@attributes
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
|
|
164
|
+
def as_json(*args)
|
|
165
|
+
attributes.dup.tap do |presence_message|
|
|
166
|
+
presence_message['action'] = action.to_i
|
|
167
|
+
end.as_json.reject { |key, val| val.nil? }
|
|
168
|
+
rescue KeyError
|
|
169
|
+
raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def to_json(*args)
|
|
173
|
+
as_json(*args).tap do |presence_message|
|
|
174
|
+
decode_binary_data_before_to_json presence_message
|
|
175
|
+
end.to_json
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# The size is the sum over data and clientId in bytes (TO3l8a)
|
|
179
|
+
#
|
|
180
|
+
def size
|
|
181
|
+
%w(data client_id).map do |attr|
|
|
182
|
+
if (value = attributes[attr.to_sym]).is_a?(String)
|
|
183
|
+
value.bytesize
|
|
184
|
+
elsif value.nil?
|
|
185
|
+
0
|
|
186
|
+
else
|
|
187
|
+
value.to_json.bytesize
|
|
188
|
+
end
|
|
189
|
+
end.sum
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Assign this presence message to a ProtocolMessage before delivery to the Ably system
|
|
193
|
+
# @api private
|
|
194
|
+
def assign_to_protocol_message(protocol_message)
|
|
195
|
+
@protocol_message = protocol_message
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
|
|
199
|
+
# @return [Boolean]
|
|
200
|
+
# @api private
|
|
201
|
+
def assigned_to_protocol_message?
|
|
202
|
+
!!@protocol_message
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# The optional ProtocolMessage this presence message is assigned to. If ProtocolMessage is nil, an error will be raised.
|
|
206
|
+
# @return [Ably::Models::ProtocolMessage]
|
|
207
|
+
# @api private
|
|
208
|
+
def protocol_message
|
|
209
|
+
raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
|
|
210
|
+
@protocol_message
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Create a static shallow clone of this object with the optional attributes to overide existing values
|
|
214
|
+
# Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
|
|
215
|
+
# Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
|
|
216
|
+
def shallow_clone(new_attributes = {})
|
|
217
|
+
new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])
|
|
218
|
+
|
|
219
|
+
self.class.new(attributes.to_hash.merge(
|
|
220
|
+
id: new_attributes[:id] || id,
|
|
221
|
+
connection_id: new_attributes[:connection_id] || connection_id,
|
|
222
|
+
timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
|
|
223
|
+
).merge(new_attributes.to_hash))
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
private
|
|
227
|
+
def raw_hash_object
|
|
228
|
+
@raw_hash_object
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def protocol_message_index
|
|
232
|
+
protocol_message.presence.index(self)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def set_attributes_object(new_attributes)
|
|
236
|
+
@attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def logger
|
|
240
|
+
return @logger if @logger
|
|
241
|
+
protocol_message.logger if protocol_message
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|