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,440 @@
|
|
|
1
|
+
require 'ably/realtime/channel/publisher'
|
|
2
|
+
|
|
3
|
+
module Ably
|
|
4
|
+
module Realtime
|
|
5
|
+
# Enables messages to be published and subscribed to. Also enables historic messages to be retrieved and provides
|
|
6
|
+
# access to the {Ably::Realtime::Channel} object of a channel.
|
|
7
|
+
#
|
|
8
|
+
# Channels will always be in one of the following states:
|
|
9
|
+
#
|
|
10
|
+
# initialized: 0
|
|
11
|
+
# attaching: 1
|
|
12
|
+
# attached: 2
|
|
13
|
+
# detaching: 3
|
|
14
|
+
# detached: 4
|
|
15
|
+
# failed: 5
|
|
16
|
+
#
|
|
17
|
+
# Note that the states are available as Enum-like constants:
|
|
18
|
+
#
|
|
19
|
+
# Channel::STATE.Initialized The channel has been initialized but no attach has yet been attempted.
|
|
20
|
+
# Channel::STATE.Attaching An attach has been initiated by sending a request to Ably.
|
|
21
|
+
# This is a transient state, followed either by a transition to ATTACHED, SUSPENDED, or FAILED.
|
|
22
|
+
# Channel::STATE.Attached The attach has succeeded. In the ATTACHED state a client may publish and subscribe to messages, or be present on the channel.
|
|
23
|
+
# Channel::STATE.Detaching A detach has been initiated on an ATTACHED channel by sending a request to Ably.
|
|
24
|
+
# This is a transient state, followed either by a transition to DETACHED or FAILED.
|
|
25
|
+
# Channel::STATE.Detached The channel, having previously been ATTACHED, has been detached by the user.
|
|
26
|
+
# Channel::STATE.Suspended The channel, having previously been ATTACHED, has lost continuity, usually due to
|
|
27
|
+
# the client being disconnected from Ably for longer than two minutes. It will automatically attempt to reattach as soon as connectivity is restored.
|
|
28
|
+
# Channel::STATE.Failed An indefinite failure condition. This state is entered if a channel error
|
|
29
|
+
# has been received from the Ably service, such as an attempt to attach without the necessary access rights.
|
|
30
|
+
#
|
|
31
|
+
class Channel
|
|
32
|
+
include Ably::Modules::Conversions
|
|
33
|
+
include Ably::Modules::EventEmitter
|
|
34
|
+
include Ably::Modules::EventMachineHelpers
|
|
35
|
+
include Ably::Modules::AsyncWrapper
|
|
36
|
+
include Ably::Modules::MessageEmitter
|
|
37
|
+
include Ably::Realtime::Channel::Publisher
|
|
38
|
+
extend Ably::Modules::Enum
|
|
39
|
+
extend Forwardable
|
|
40
|
+
|
|
41
|
+
# The current {Abbly::Realtime::Channel::STATE} of the channel.
|
|
42
|
+
#
|
|
43
|
+
# @spec RTL2b
|
|
44
|
+
#
|
|
45
|
+
# The permitted states for this channel
|
|
46
|
+
STATE = ruby_enum('STATE',
|
|
47
|
+
:initialized,
|
|
48
|
+
:attaching,
|
|
49
|
+
:attached,
|
|
50
|
+
:detaching,
|
|
51
|
+
:detached,
|
|
52
|
+
:suspended,
|
|
53
|
+
:failed
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Describes the events emitted by a {Ably::Rest::Channel} or {Ably::Realtime::Channel} object.
|
|
57
|
+
# An event is either an UPDATE or a {Ably::Rest::Channel::STATE}.
|
|
58
|
+
#
|
|
59
|
+
# The permitted channel events that are emitted for this channel
|
|
60
|
+
#
|
|
61
|
+
# @spec RTL2g
|
|
62
|
+
#
|
|
63
|
+
EVENT = ruby_enum('EVENT',
|
|
64
|
+
STATE.to_sym_arr + [:update]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
include Ably::Modules::StateEmitter
|
|
68
|
+
include Ably::Modules::UsesStateMachine
|
|
69
|
+
ensure_state_machine_emits 'Ably::Models::ChannelStateChange'
|
|
70
|
+
|
|
71
|
+
# Max number of messages to bundle in a single ProtocolMessage
|
|
72
|
+
MAX_PROTOCOL_MESSAGE_BATCH_SIZE = 50
|
|
73
|
+
|
|
74
|
+
# {Ably::Realtime::Client} associated with this channel
|
|
75
|
+
#
|
|
76
|
+
# @return [Ably::Realtime::Client]
|
|
77
|
+
#
|
|
78
|
+
# @api private
|
|
79
|
+
attr_reader :client
|
|
80
|
+
|
|
81
|
+
# The channel name.
|
|
82
|
+
# @return [String]
|
|
83
|
+
attr_reader :name
|
|
84
|
+
|
|
85
|
+
# A {Ably::Realtime::Channel::PushChannel} object.
|
|
86
|
+
#
|
|
87
|
+
# @return [Ably::Realtime::Channel::PushChannel]
|
|
88
|
+
attr_reader :push
|
|
89
|
+
|
|
90
|
+
# Channel options configured for this channel, see {#initialize} for channel_options
|
|
91
|
+
# @return [Hash]
|
|
92
|
+
attr_reader :options
|
|
93
|
+
|
|
94
|
+
# A {Ably::Realtime::Channel::ChannelProperties} object.
|
|
95
|
+
#
|
|
96
|
+
# @spec CP1, RTL15
|
|
97
|
+
#
|
|
98
|
+
# @return [{Ably::Realtime::Channel::ChannelProperties}]
|
|
99
|
+
attr_reader :properties
|
|
100
|
+
|
|
101
|
+
# An {Ably::Models::ErrorInfo} object describing the last error which occurred on the channel, if any.
|
|
102
|
+
# @spec RTL4e
|
|
103
|
+
# @return [Ably::Models::ErrorInfo,Ably::Exceptions::BaseAblyException]
|
|
104
|
+
attr_reader :error_reason
|
|
105
|
+
|
|
106
|
+
# The Channel manager responsible for attaching, detaching and handling failures for this channel
|
|
107
|
+
# @return [Ably::Realtime::Channel::ChannelManager]
|
|
108
|
+
# @api private
|
|
109
|
+
attr_reader :manager
|
|
110
|
+
|
|
111
|
+
# Flag that specifies whether channel is resuming attachment(reattach) or is doing a 'clean attach' RTL4j1
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
# @api private
|
|
114
|
+
attr_reader :attach_resume
|
|
115
|
+
|
|
116
|
+
# Optional channel parameters that configure the behavior of the channel.
|
|
117
|
+
# @spec RTL4k1
|
|
118
|
+
# return [Hash]
|
|
119
|
+
def_delegators :options, :params
|
|
120
|
+
|
|
121
|
+
# Initialize a new Channel object
|
|
122
|
+
#
|
|
123
|
+
# @param client [Ably::Rest::Client]
|
|
124
|
+
# @param name [String] The name of the channel
|
|
125
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
126
|
+
#
|
|
127
|
+
def initialize(client, name, channel_options = {})
|
|
128
|
+
name = ensure_utf_8(:name, name)
|
|
129
|
+
|
|
130
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
131
|
+
@client = client
|
|
132
|
+
@name = name
|
|
133
|
+
@queue = []
|
|
134
|
+
|
|
135
|
+
@state_machine = ChannelStateMachine.new(self)
|
|
136
|
+
@state = STATE(state_machine.current_state)
|
|
137
|
+
@manager = ChannelManager.new(self, client.connection)
|
|
138
|
+
@push = PushChannel.new(self)
|
|
139
|
+
@properties = ChannelProperties.new(self)
|
|
140
|
+
@attach_resume = false
|
|
141
|
+
|
|
142
|
+
setup_event_handlers
|
|
143
|
+
setup_presence
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Publish a message to the channel. A callback may optionally be passed in to this call to be notified of success
|
|
147
|
+
# or failure of the operation. When publish is called with this client library, it won't attempt to implicitly
|
|
148
|
+
# attach to the channel.
|
|
149
|
+
#
|
|
150
|
+
# @spec RTL6i
|
|
151
|
+
#
|
|
152
|
+
# @param name [String, Array<Ably::Models::Message|Hash>, nil] The event name of the message to publish, or an Array of [Ably::Model::Message] objects or [Hash] objects with +:name+ and +:data+ pairs
|
|
153
|
+
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
|
154
|
+
# @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
|
|
155
|
+
#
|
|
156
|
+
# @yield [Ably::Models::Message,Array<Ably::Models::Message>] On success, will call the block with the {Ably::Models::Message} if a single message is published, or an Array of {Ably::Models::Message} when multiple messages are published
|
|
157
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
|
|
158
|
+
#
|
|
159
|
+
# @example
|
|
160
|
+
# # Publish a single message form
|
|
161
|
+
# channel.publish 'click', { x: 1, y: 2 }
|
|
162
|
+
#
|
|
163
|
+
# # Publish a single message with single Hash form
|
|
164
|
+
# message = { name: 'click', data: { x: 1, y: 2 } }
|
|
165
|
+
# channel.publish message
|
|
166
|
+
#
|
|
167
|
+
# # Publish an array of message Hashes form
|
|
168
|
+
# messages = [
|
|
169
|
+
# { name: 'click', data: { x: 1, y: 2 } },
|
|
170
|
+
# { name: 'click', data: { x: 2, y: 3 } }
|
|
171
|
+
# ]
|
|
172
|
+
# channel.publish messages
|
|
173
|
+
#
|
|
174
|
+
# # Publish an array of Ably::Models::Message objects form
|
|
175
|
+
# messages = [
|
|
176
|
+
# Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
177
|
+
# Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
|
|
178
|
+
# ]
|
|
179
|
+
# channel.publish messages
|
|
180
|
+
#
|
|
181
|
+
# # Publish an array of Ably::Models::Message objects form
|
|
182
|
+
# message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
183
|
+
# channel.publish message
|
|
184
|
+
#
|
|
185
|
+
# channel.publish('click', 'body') do |message|
|
|
186
|
+
# puts "#{message.name} event received with #{message.data}"
|
|
187
|
+
# end
|
|
188
|
+
#
|
|
189
|
+
# channel.publish('click', 'body').errback do |error, message|
|
|
190
|
+
# puts "#{message.name} was not received, error #{error.message}"
|
|
191
|
+
# end
|
|
192
|
+
#
|
|
193
|
+
def publish(name, data = nil, attributes = {}, &success_block)
|
|
194
|
+
if suspended? || failed?
|
|
195
|
+
error = Ably::Exceptions::ChannelInactive.new("Cannot publish messages on a channel in state #{state}")
|
|
196
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if !connection.can_publish_messages?
|
|
200
|
+
error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is not allowed to queue messages when connection is in state #{connection.state}")
|
|
201
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
|
205
|
+
|
|
206
|
+
if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
|
|
207
|
+
error = Ably::Exceptions::InvalidRequest.new("It is not possible to publish more than #{Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE} messages with a single publish request.")
|
|
208
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
enqueue_messages_on_connection(client, messages, channel_name, options).tap do |deferrable|
|
|
212
|
+
deferrable.callback(&success_block) if block_given?
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Registers a listener for messages on this channel. The caller supplies a listener function, which is called
|
|
217
|
+
# each time one or more messages arrives on the channel. A callback may optionally be passed in to this call
|
|
218
|
+
# to be notified of success or failure of the channel {Ably::Realtime::Channel#attach} operation.
|
|
219
|
+
#
|
|
220
|
+
# @spec RTL7a
|
|
221
|
+
#
|
|
222
|
+
# @param names [String] The event name of the message to subscribe to if provided. Defaults to all events.
|
|
223
|
+
# @yield [Ably::Models::Message] For each message received, the block is called
|
|
224
|
+
#
|
|
225
|
+
# @return [void]
|
|
226
|
+
#
|
|
227
|
+
def subscribe(*names, &callback)
|
|
228
|
+
attach unless attached? || attaching?
|
|
229
|
+
super
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Deregisters the given listener for the specified event name(s). This removes an earlier event-specific subscription.
|
|
233
|
+
#
|
|
234
|
+
# @spec RTL8a
|
|
235
|
+
#
|
|
236
|
+
# @param names [String] The event name of the message to subscribe to if provided. Defaults to all events.
|
|
237
|
+
#
|
|
238
|
+
# @return [void]
|
|
239
|
+
#
|
|
240
|
+
def unsubscribe(*names, &callback)
|
|
241
|
+
super
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Attach to this channel ensuring the channel is created in the Ably system and all messages published on
|
|
245
|
+
# the channel are received by any channel listeners registered using {Ably::Realtime::Channel#subscribe}.
|
|
246
|
+
# Any resulting channel state change will be emitted to any listeners registered using the {Ably::Modules::EventEmitter#on}
|
|
247
|
+
# or {Ably::Modules::EventEmitter#once} methods. A callback may optionally be passed in to this call to be notified
|
|
248
|
+
# of success or failure of the operation. As a convenience, attach() is called implicitly
|
|
249
|
+
# if {Ably::Realtime::Channel#subscribe} for the channel is called, or {Ably::Realtime::Presence#enter}
|
|
250
|
+
# or {Ably::Realtime::Presence#subscribe} are called on the {Ably::Realtime::Presence} object for this channel.
|
|
251
|
+
#
|
|
252
|
+
# @spec RTL4d
|
|
253
|
+
#
|
|
254
|
+
# @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Attached state
|
|
255
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callback
|
|
256
|
+
#
|
|
257
|
+
def attach(&success_block)
|
|
258
|
+
if connection.closing? || connection.closed? || connection.suspended? || connection.failed?
|
|
259
|
+
error = Ably::Exceptions::InvalidStateChange.new("Cannot ATTACH channel when the connection is in a closed, suspended or failed state. Connection state: #{connection.state}")
|
|
260
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
if !attached?
|
|
264
|
+
if detaching?
|
|
265
|
+
# Let the pending operation complete (#RTL4h)
|
|
266
|
+
once_state_changed { transition_state_machine :attaching if can_transition_to?(:attaching) }
|
|
267
|
+
else
|
|
268
|
+
transition_state_machine :attaching if can_transition_to?(:attaching)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
deferrable_for_state_change_to(STATE.Attached, &success_block)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Detach from this channel. Any resulting channel state change is emitted to any listeners registered using
|
|
276
|
+
# the {Ably::Modules::EventEmitter#on} or {Ably::Modules::EventEmitter#once} methods. A callback may optionally
|
|
277
|
+
# be passed in to this call to be notified of success or failure of the operation. Once all clients globally
|
|
278
|
+
# have detached from the channel, the channel will be released in the Ably service within two minutes.
|
|
279
|
+
#
|
|
280
|
+
# @spec RTL5e
|
|
281
|
+
#
|
|
282
|
+
# @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Detached or Failed state
|
|
283
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callback
|
|
284
|
+
#
|
|
285
|
+
def detach(&success_block)
|
|
286
|
+
if initialized?
|
|
287
|
+
success_block.call if block_given?
|
|
288
|
+
return Ably::Util::SafeDeferrable.new_and_succeed_immediately(logger)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if failed? || connection.closing? || connection.failed?
|
|
292
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, exception_for_state_change_to(:detaching))
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
if !detached?
|
|
296
|
+
if attaching?
|
|
297
|
+
# Let the pending operation complete (#RTL5i)
|
|
298
|
+
once_state_changed { transition_state_machine :detaching if can_transition_to?(:detaching) }
|
|
299
|
+
elsif can_transition_to?(:detaching)
|
|
300
|
+
transition_state_machine :detaching
|
|
301
|
+
else
|
|
302
|
+
transition_state_machine! :detached
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
deferrable_for_state_change_to(STATE.Detached, &success_block)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# A {Ably::Realtime::Presence} object.
|
|
310
|
+
#
|
|
311
|
+
# @spec RTL9
|
|
312
|
+
#
|
|
313
|
+
# @return {Ably::Realtime::Presence}
|
|
314
|
+
#
|
|
315
|
+
def presence
|
|
316
|
+
@presence
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Retrieves a {Ably::Models::PaginatedResult} object, containing an array of historical
|
|
320
|
+
# {Ably::Models::Message} objects for the channel. If the channel is configured to persist messages,
|
|
321
|
+
# then messages can be retrieved from history for up to 72 hours in the past. If not, messages can only
|
|
322
|
+
# be retrieved from history for up to two minutes in the past.
|
|
323
|
+
#
|
|
324
|
+
# @spec RSL2a
|
|
325
|
+
#
|
|
326
|
+
# @param (see {Ably::Rest::Channel#history})
|
|
327
|
+
# @option options (see {Ably::Rest::Channel#history})
|
|
328
|
+
# @option options [Boolean] :until_attach When true, the history request will be limited only to messages published before this channel was attached. Channel must be attached
|
|
329
|
+
#
|
|
330
|
+
# @yield [Ably::Models::PaginatedResult<Ably::Models::Message>] First {Ably::Models::PaginatedResult page} of {Ably::Models::Message} objects accessible with {Ably::Models::PaginatedResult#items #items}.
|
|
331
|
+
#
|
|
332
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
333
|
+
#
|
|
334
|
+
def history(options = {}, &callback)
|
|
335
|
+
# RTL10b
|
|
336
|
+
if options.delete(:until_attach)
|
|
337
|
+
unless attached?
|
|
338
|
+
error = Ably::Exceptions::InvalidRequest.new('option :until_attach is invalid as the channel is not attached' )
|
|
339
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
340
|
+
end
|
|
341
|
+
options[:from_serial] = properties.attach_serial
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
async_wrap(callback) do
|
|
345
|
+
rest_channel.history(options.merge(async_blocking_operations: true))
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# @return [Ably::Util::PubSub] Client library internal channel incoming message bus
|
|
350
|
+
#
|
|
351
|
+
# @api private
|
|
352
|
+
def __incoming_msgbus__
|
|
353
|
+
@__incoming_msgbus__ ||= Ably::Util::PubSub.new(
|
|
354
|
+
coerce_into: lambda { |event| Ably::Models::ProtocolMessage::ACTION(event) }
|
|
355
|
+
)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Sets the {Ably::Models::ChannelOptions} for the channel.
|
|
359
|
+
# An optional callback may be provided to notify of the success or failure of the operation.
|
|
360
|
+
#
|
|
361
|
+
# @spec RTL16
|
|
362
|
+
#
|
|
363
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
364
|
+
# @return [Ably::Models::ChannelOptions]
|
|
365
|
+
def set_options(channel_options)
|
|
366
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
367
|
+
# RTL4i
|
|
368
|
+
manager.request_reattach if (need_reattach? and connection.state?(:connected))
|
|
369
|
+
end
|
|
370
|
+
alias options= set_options
|
|
371
|
+
|
|
372
|
+
# @api private
|
|
373
|
+
def set_channel_error_reason(error)
|
|
374
|
+
@error_reason = error
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# @api private
|
|
378
|
+
def clear_error_reason
|
|
379
|
+
@error_reason = nil
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Used by {Ably::Modules::StateEmitter} to debug state changes
|
|
383
|
+
# @api private
|
|
384
|
+
def logger
|
|
385
|
+
client.logger
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# @api private
|
|
389
|
+
def attach_resume!
|
|
390
|
+
@attach_resume = true
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# @api private
|
|
394
|
+
def reset_attach_resume!
|
|
395
|
+
@attach_resume = false
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# As we are using a state machine, do not allow change_state to be used
|
|
399
|
+
# #transition_state_machine must be used instead
|
|
400
|
+
private :change_state
|
|
401
|
+
|
|
402
|
+
def need_reattach?
|
|
403
|
+
!!(attaching? || attached?) && !!(options.modes || options.params)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
private
|
|
407
|
+
|
|
408
|
+
def setup_event_handlers
|
|
409
|
+
__incoming_msgbus__.subscribe(:message) do |message|
|
|
410
|
+
message.decode(client.encoders, options) do |encode_error, error_message|
|
|
411
|
+
client.logger.error error_message
|
|
412
|
+
end
|
|
413
|
+
emit_message message.name, message
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def rest_channel
|
|
418
|
+
client.rest_client.channel(name)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def connection
|
|
422
|
+
client.connection
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def setup_presence
|
|
426
|
+
@presence ||= Presence.new(self)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Alias useful for methods with a name argument
|
|
430
|
+
def channel_name
|
|
431
|
+
name
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
require 'ably/realtime/channel/channel_manager'
|
|
438
|
+
require 'ably/realtime/channel/channel_state_machine'
|
|
439
|
+
require 'ably/realtime/channel/push_channel'
|
|
440
|
+
require 'ably/realtime/channel/channel_properties'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module Realtime
|
|
3
|
+
# Class that maintains a map of Channels ensuring Channels are reused
|
|
4
|
+
class Channels
|
|
5
|
+
include Ably::Modules::ChannelsCollection
|
|
6
|
+
|
|
7
|
+
# @return [Ably::Realtime::Channels]
|
|
8
|
+
#
|
|
9
|
+
def initialize(client)
|
|
10
|
+
super client, Ably::Realtime::Channel
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Return a {Ably::Realtime::Channel} for the given name
|
|
14
|
+
#
|
|
15
|
+
# @param name [String] The name of the channel
|
|
16
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
17
|
+
#
|
|
18
|
+
# @return [Ably::Realtime::Channel]
|
|
19
|
+
#
|
|
20
|
+
def get(*args)
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Return a {Ably::Realtime::Channel} for the given name if it exists, else the block will be called.
|
|
25
|
+
# This method is intentionally similar to {http://ruby-doc.org/core-2.1.3/Hash.html#method-i-fetch Hash#fetch} providing a simple way to check if a channel exists or not without creating one
|
|
26
|
+
#
|
|
27
|
+
# @param name [String] The name of the channel
|
|
28
|
+
# @yield [options] (optional) if a missing_block is passed to this method and no channel exists matching the name, this block is called
|
|
29
|
+
# @yieldparam [String] name of the missing channel
|
|
30
|
+
#
|
|
31
|
+
# @return [Ably::Realtime::Channel]
|
|
32
|
+
#
|
|
33
|
+
def fetch(*args)
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Detaches the {Ably::Realtime::Channel Realtime Channel} and releases all associated resources.
|
|
38
|
+
#
|
|
39
|
+
# Releasing a Realtime Channel is not typically necessary as a channel, once detached, consumes no resources other than
|
|
40
|
+
# the memory footprint of the {Ably::Realtime::Channel Realtime Channel object}. Release channels to free up resources if required
|
|
41
|
+
#
|
|
42
|
+
# @return [void]
|
|
43
|
+
#
|
|
44
|
+
def release(channel)
|
|
45
|
+
get(channel).detach do
|
|
46
|
+
@channels.delete(channel)
|
|
47
|
+
end if @channels.has_key?(channel)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Sets channel serial to each channel from given serials hashmap
|
|
51
|
+
# @param [Hash] serials - map of channel name to respective channel serial
|
|
52
|
+
# @api private
|
|
53
|
+
def set_channel_serials(serials)
|
|
54
|
+
serials.each do |channel_name, channel_serial|
|
|
55
|
+
get(channel_name).properties.channel_serial = channel_serial
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [Hash] serials - map of channel name to respective channel serial
|
|
60
|
+
# @api private
|
|
61
|
+
def get_channel_serials
|
|
62
|
+
channel_serials = {}
|
|
63
|
+
self.each do |channel|
|
|
64
|
+
channel_serials[channel.name] = channel.properties.channel_serial if channel.state == :attached
|
|
65
|
+
end
|
|
66
|
+
channel_serials
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|