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.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ably/agent.rb +8 -0
  3. data/lib/ably/auth.rb +791 -0
  4. data/lib/ably/exceptions.rb +169 -0
  5. data/lib/ably/logger.rb +119 -0
  6. data/lib/ably/models/auth_details.rb +45 -0
  7. data/lib/ably/models/channel_details.rb +69 -0
  8. data/lib/ably/models/channel_metrics.rb +107 -0
  9. data/lib/ably/models/channel_occupancy.rb +50 -0
  10. data/lib/ably/models/channel_options.rb +120 -0
  11. data/lib/ably/models/channel_state_change.rb +84 -0
  12. data/lib/ably/models/channel_status.rb +63 -0
  13. data/lib/ably/models/cipher_params.rb +137 -0
  14. data/lib/ably/models/connection_details.rb +149 -0
  15. data/lib/ably/models/connection_state_change.rb +83 -0
  16. data/lib/ably/models/delta_extras.rb +28 -0
  17. data/lib/ably/models/device_details.rb +126 -0
  18. data/lib/ably/models/device_push_details.rb +94 -0
  19. data/lib/ably/models/error_info.rb +104 -0
  20. data/lib/ably/models/http_paginated_response.rb +112 -0
  21. data/lib/ably/models/idiomatic_ruby_wrapper.rb +235 -0
  22. data/lib/ably/models/message.rb +223 -0
  23. data/lib/ably/models/message_encoders/base.rb +135 -0
  24. data/lib/ably/models/message_encoders/base64.rb +40 -0
  25. data/lib/ably/models/message_encoders/cipher.rb +84 -0
  26. data/lib/ably/models/message_encoders/json.rb +34 -0
  27. data/lib/ably/models/message_encoders/utf8.rb +26 -0
  28. data/lib/ably/models/nil_logger.rb +20 -0
  29. data/lib/ably/models/paginated_result.rb +201 -0
  30. data/lib/ably/models/presence_message.rb +244 -0
  31. data/lib/ably/models/protocol_message.rb +288 -0
  32. data/lib/ably/models/push_channel_subscription.rb +114 -0
  33. data/lib/ably/models/stats.rb +242 -0
  34. data/lib/ably/models/stats_types.rb +107 -0
  35. data/lib/ably/models/token_details.rb +148 -0
  36. data/lib/ably/models/token_request.rb +180 -0
  37. data/lib/ably/modules/ably.rb +26 -0
  38. data/lib/ably/modules/async_wrapper.rb +69 -0
  39. data/lib/ably/modules/channels_collection.rb +105 -0
  40. data/lib/ably/modules/conversions.rb +153 -0
  41. data/lib/ably/modules/encodeable.rb +111 -0
  42. data/lib/ably/modules/enum.rb +230 -0
  43. data/lib/ably/modules/event_emitter.rb +200 -0
  44. data/lib/ably/modules/event_machine_helpers.rb +26 -0
  45. data/lib/ably/modules/exception_codes.rb +128 -0
  46. data/lib/ably/modules/http_helpers.rb +41 -0
  47. data/lib/ably/modules/message_emitter.rb +78 -0
  48. data/lib/ably/modules/message_pack.rb +14 -0
  49. data/lib/ably/modules/model_common.rb +84 -0
  50. data/lib/ably/modules/safe_deferrable.rb +83 -0
  51. data/lib/ably/modules/safe_yield.rb +41 -0
  52. data/lib/ably/modules/state_emitter.rb +181 -0
  53. data/lib/ably/modules/state_machine.rb +59 -0
  54. data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  55. data/lib/ably/modules/uses_state_machine.rb +111 -0
  56. data/lib/ably/realtime/auth.rb +283 -0
  57. data/lib/ably/realtime/channel/channel_manager.rb +272 -0
  58. data/lib/ably/realtime/channel/channel_properties.rb +40 -0
  59. data/lib/ably/realtime/channel/channel_state_machine.rb +104 -0
  60. data/lib/ably/realtime/channel/publisher.rb +82 -0
  61. data/lib/ably/realtime/channel/push_channel.rb +69 -0
  62. data/lib/ably/realtime/channel.rb +440 -0
  63. data/lib/ably/realtime/channels.rb +71 -0
  64. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +225 -0
  65. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +87 -0
  66. data/lib/ably/realtime/client.rb +363 -0
  67. data/lib/ably/realtime/connection/connection_manager.rb +594 -0
  68. data/lib/ably/realtime/connection/connection_state_machine.rb +144 -0
  69. data/lib/ably/realtime/connection/websocket_transport.rb +287 -0
  70. data/lib/ably/realtime/connection.rb +738 -0
  71. data/lib/ably/realtime/models/nil_channel.rb +30 -0
  72. data/lib/ably/realtime/presence/members_map.rb +395 -0
  73. data/lib/ably/realtime/presence/presence_manager.rb +78 -0
  74. data/lib/ably/realtime/presence/presence_state_machine.rb +57 -0
  75. data/lib/ably/realtime/presence.rb +502 -0
  76. data/lib/ably/realtime/push/admin.rb +75 -0
  77. data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  78. data/lib/ably/realtime/push/device_registrations.rb +105 -0
  79. data/lib/ably/realtime/push.rb +25 -0
  80. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  81. data/lib/ably/realtime.rb +60 -0
  82. data/lib/ably/rest/channel/push_channel.rb +59 -0
  83. data/lib/ably/rest/channel.rb +194 -0
  84. data/lib/ably/rest/channels.rb +47 -0
  85. data/lib/ably/rest/client.rb +727 -0
  86. data/lib/ably/rest/middleware/encoder.rb +49 -0
  87. data/lib/ably/rest/middleware/exceptions.rb +53 -0
  88. data/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  89. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +22 -0
  90. data/lib/ably/rest/middleware/logger.rb +58 -0
  91. data/lib/ably/rest/middleware/parse_json.rb +27 -0
  92. data/lib/ably/rest/middleware/parse_message_pack.rb +43 -0
  93. data/lib/ably/rest/presence.rb +113 -0
  94. data/lib/ably/rest/push/admin.rb +58 -0
  95. data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  96. data/lib/ably/rest/push/device_registrations.rb +114 -0
  97. data/lib/ably/rest/push.rb +25 -0
  98. data/lib/ably/rest.rb +40 -0
  99. data/lib/ably/util/ably_extensions.rb +29 -0
  100. data/lib/ably/util/crypto.rb +134 -0
  101. data/lib/ably/util/pub_sub.rb +45 -0
  102. data/lib/ably/util/safe_deferrable.rb +44 -0
  103. data/lib/ably/version.rb +7 -0
  104. data/lib/ably.rb +16 -0
  105. 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