ably-rest 1.0.5 → 1.1.3

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 (118) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +6 -3
  3. data/CHANGELOG.md +1 -1
  4. data/LICENSE +1 -1
  5. data/README.md +26 -7
  6. data/SPEC.md +2003 -1605
  7. data/ably-rest.gemspec +4 -2
  8. data/lib/submodules/ably-ruby/.editorconfig +14 -0
  9. data/lib/submodules/ably-ruby/.travis.yml +10 -8
  10. data/lib/submodules/ably-ruby/CHANGELOG.md +97 -1
  11. data/lib/submodules/ably-ruby/LICENSE +1 -3
  12. data/lib/submodules/ably-ruby/README.md +12 -7
  13. data/lib/submodules/ably-ruby/Rakefile +32 -0
  14. data/lib/submodules/ably-ruby/SPEC.md +1277 -835
  15. data/lib/submodules/ably-ruby/ably.gemspec +17 -11
  16. data/lib/submodules/ably-ruby/lib/ably/auth.rb +34 -8
  17. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +10 -4
  18. data/lib/submodules/ably-ruby/lib/ably/logger.rb +8 -2
  19. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +1 -1
  20. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +1 -1
  21. data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +87 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/device_push_details.rb +86 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +23 -2
  24. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +12 -12
  25. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +6 -4
  26. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +6 -4
  27. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +32 -2
  28. data/lib/submodules/ably-ruby/lib/ably/models/push_channel_subscription.rb +89 -0
  29. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +2 -2
  30. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +2 -2
  31. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +2 -2
  32. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +2 -2
  33. data/lib/submodules/ably-ruby/lib/ably/modules/exception_codes.rb +128 -0
  34. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +15 -2
  35. data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +1 -1
  36. data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +1 -1
  37. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +5 -5
  38. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
  39. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +2 -2
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +27 -105
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +4 -8
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +74 -0
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/push_channel.rb +62 -0
  46. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +91 -3
  47. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +9 -4
  48. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  49. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +45 -26
  50. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +25 -9
  51. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +2 -2
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +7 -7
  53. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +9 -9
  54. data/lib/submodules/ably-ruby/lib/ably/realtime/push.rb +40 -0
  55. data/lib/submodules/ably-ruby/lib/ably/realtime/push/admin.rb +61 -0
  56. data/lib/submodules/ably-ruby/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  57. data/lib/submodules/ably-ruby/lib/ably/realtime/push/device_registrations.rb +105 -0
  58. data/lib/submodules/ably-ruby/lib/ably/rest.rb +1 -0
  59. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +54 -18
  60. data/lib/submodules/ably-ruby/lib/ably/rest/channel/push_channel.rb +62 -0
  61. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +171 -41
  62. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
  63. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
  64. data/lib/submodules/ably-ruby/lib/ably/rest/push.rb +42 -0
  65. data/lib/submodules/ably-ruby/lib/ably/rest/push/admin.rb +54 -0
  66. data/lib/submodules/ably-ruby/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  67. data/lib/submodules/ably-ruby/lib/ably/rest/push/device_registrations.rb +103 -0
  68. data/lib/submodules/ably-ruby/lib/ably/version.rb +7 -2
  69. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +253 -49
  70. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +33 -21
  71. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +180 -62
  72. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +155 -2
  73. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +293 -13
  74. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +142 -39
  75. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +38 -36
  76. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +12 -3
  77. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +207 -173
  78. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +736 -0
  79. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_spec.rb +27 -0
  80. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +62 -51
  81. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +2 -2
  82. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +79 -4
  83. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +6 -0
  84. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +318 -74
  85. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +158 -6
  86. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +952 -0
  87. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_spec.rb +25 -0
  88. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
  89. data/lib/submodules/ably-ruby/spec/run_parallel_tests +33 -0
  90. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +1 -9
  91. data/lib/submodules/ably-ruby/spec/spec_helper.rb +3 -1
  92. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +9 -5
  93. data/lib/submodules/ably-ruby/spec/support/event_emitter_helper.rb +31 -0
  94. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
  95. data/lib/submodules/ably-ruby/spec/support/test_app.rb +2 -2
  96. data/lib/submodules/ably-ruby/spec/support/test_logger_helper.rb +42 -0
  97. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +11 -12
  98. data/lib/submodules/ably-ruby/spec/unit/models/device_details_spec.rb +102 -0
  99. data/lib/submodules/ably-ruby/spec/unit/models/device_push_details_spec.rb +101 -0
  100. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +51 -3
  101. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +17 -2
  102. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
  103. data/lib/submodules/ably-ruby/spec/unit/models/push_channel_subscription_spec.rb +86 -0
  104. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -2
  105. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +1 -1
  106. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +3 -3
  107. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +10 -10
  108. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +1 -1
  109. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +13 -1
  110. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +2 -2
  111. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +1 -1
  112. data/lib/submodules/ably-ruby/spec/unit/realtime/push_channel_spec.rb +36 -0
  113. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +30 -1
  114. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +30 -0
  115. data/lib/submodules/ably-ruby/spec/unit/rest/push_channel_spec.rb +36 -0
  116. data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +3 -3
  117. data/spec/spec_helper.rb +1 -0
  118. metadata +51 -10
@@ -71,7 +71,7 @@ module Ably::Modules
71
71
 
72
72
  def fallback_logger
73
73
  @fallback_logger ||= ::Logger.new(STDOUT).tap do |logger|
74
- logger.formatter = proc do |severity, datetime, progname, msg|
74
+ logger.formatter = lambda do |severity, datetime, progname, msg|
75
75
  [
76
76
  "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")} #{::Logger::SEV_LABEL[severity]} #{msg}",
77
77
  "Warning: SafeDeferrable expects the method #logger to be defined in the class it is included in, the method was not found in #{self.class}"
@@ -29,7 +29,7 @@ module Ably::Modules
29
29
 
30
30
  def fallback_logger
31
31
  @fallback_logger ||= ::Logger.new(STDOUT).tap do |logger|
32
- logger.formatter = proc do |severity, datetime, progname, msg|
32
+ logger.formatter = lambda do |severity, datetime, progname, msg|
33
33
  [
34
34
  "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")} #{::Logger::SEV_LABEL[severity]} #{msg}",
35
35
  "Warning: SafeYield expects the method #logger to be defined in the class it is included in, the method was not found in #{self.class}"
@@ -81,13 +81,13 @@ module Ably::Modules
81
81
  failure_block = options.fetch(:else, nil)
82
82
  failure_wrapper = nil
83
83
 
84
- success_wrapper = Proc.new do
84
+ success_wrapper = lambda do |*args|
85
85
  yield
86
86
  off(&success_wrapper)
87
87
  off(&failure_wrapper) if failure_wrapper
88
88
  end
89
89
 
90
- failure_wrapper = proc do |*args|
90
+ failure_wrapper = lambda do |*args|
91
91
  failure_block.call(*args)
92
92
  off(&success_wrapper)
93
93
  off(&failure_wrapper)
@@ -119,7 +119,7 @@ module Ably::Modules
119
119
  def once_state_changed(options = {}, &block)
120
120
  raise ArgumentError, 'Block required' unless block_given?
121
121
 
122
- once_block = proc do |*args|
122
+ once_block = lambda do |*args|
123
123
  off(*self.class::STATE.map, &once_block)
124
124
  yield(*args)
125
125
  end
@@ -142,7 +142,7 @@ module Ably::Modules
142
142
  #
143
143
  def deferrable_for_state_change_to(target_state)
144
144
  Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
145
- fail_proc = Proc.new do |state_change|
145
+ fail_proc = lambda do |state_change|
146
146
  deferrable.fail state_change.reason
147
147
  end
148
148
  once_or_if(target_state, else: fail_proc) do
@@ -153,7 +153,7 @@ module Ably::Modules
153
153
  end
154
154
 
155
155
  def self.included(klass)
156
- klass.configure_event_emitter coerce_into: Proc.new { |event|
156
+ klass.configure_event_emitter coerce_into: lambda { |event|
157
157
  # Special case allows EVENT instead of STATE to be emitted
158
158
  # Relies on the assumption that EVENT is a superset of STATE
159
159
  if klass.const_defined?(:EVENT)
@@ -23,7 +23,7 @@ module Ably::Modules
23
23
  def transition_state(state, *args)
24
24
  unless result = transition_to(state.to_sym, *args)
25
25
  exception = exception_for_state_change_to(state)
26
- logger.fatal { "#{self.class}: #{exception.message}" }
26
+ logger.fatal { "#{self.class}: #{exception.message}\n#{caller[0..20].join("\n")}" }
27
27
  end
28
28
  result
29
29
  end
@@ -41,7 +41,7 @@ module Ably::Modules
41
41
  # @return [Ably::Exceptions::InvalidStateChange]
42
42
  def exception_for_state_change_to(state)
43
43
  error_message = "#{self.class}: Unable to transition from #{current_state} => #{state}"
44
- Ably::Exceptions::InvalidStateChange.new(error_message, nil, 80020)
44
+ Ably::Exceptions::InvalidStateChange.new(error_message, nil, Ably::Exceptions::Codes::CHANNEL_OPERATION_FAILED_INVALID_CHANNEL_STATE)
45
45
  end
46
46
 
47
47
  module ClassMethods
@@ -9,6 +9,7 @@ require 'ably/realtime/channel'
9
9
  require 'ably/realtime/channels'
10
10
  require 'ably/realtime/client'
11
11
  require 'ably/realtime/connection'
12
+ require 'ably/realtime/push'
12
13
  require 'ably/realtime/presence'
13
14
 
14
15
  require 'ably/models/message_encoders/base'
@@ -233,13 +233,13 @@ module Ably
233
233
  # @yield [Hash] Auth params for a new Realtime connection
234
234
  #
235
235
  def auth_params(&success_callback)
236
- fail_callback = Proc.new do |error, deferrable|
236
+ fail_callback = lambda do |error, deferrable|
237
237
  logger.error { "Failed to authenticate: #{error}" }
238
238
  if error.kind_of?(Ably::Exceptions::BaseAblyException)
239
239
  # Use base exception if it exists carrying forward the status codes
240
240
  deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
241
241
  else
242
- deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, 80019)
242
+ deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
243
243
  end
244
244
  end
245
245
  async_wrap(success_callback, fail_callback) do
@@ -1,3 +1,5 @@
1
+ require 'ably/realtime/channel/publisher'
2
+
1
3
  module Ably
2
4
  module Realtime
3
5
  # The Channel class represents a Channel belonging to this application.
@@ -32,6 +34,7 @@ module Ably
32
34
  include Ably::Modules::EventMachineHelpers
33
35
  include Ably::Modules::AsyncWrapper
34
36
  include Ably::Modules::MessageEmitter
37
+ include Ably::Realtime::Channel::Publisher
35
38
  extend Ably::Modules::Enum
36
39
 
37
40
  # ChannelState
@@ -61,12 +64,17 @@ module Ably
61
64
 
62
65
  # {Ably::Realtime::Client} associated with this channel
63
66
  # @return [Ably::Realtime::Client]
67
+ # @api private
64
68
  attr_reader :client
65
69
 
66
70
  # Channel name
67
71
  # @return [String]
68
72
  attr_reader :name
69
73
 
74
+ # Push channel used for push notification
75
+ # @return [Ably::Realtime::Channel::PushChannel]
76
+ attr_reader :push
77
+
70
78
  # Channel options configured for this channel, see {#initialize} for channel_options
71
79
  # @return [Hash]
72
80
  attr_reader :options
@@ -93,7 +101,7 @@ module Ably
93
101
  # @option channel_options [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +:cipher+ options
94
102
  #
95
103
  def initialize(client, name, channel_options = {})
96
- ensure_utf_8 :name, name
104
+ name = ensure_utf_8(:name, name)
97
105
 
98
106
  update_options channel_options
99
107
  @client = client
@@ -103,6 +111,7 @@ module Ably
103
111
  @state_machine = ChannelStateMachine.new(self)
104
112
  @state = STATE(state_machine.current_state)
105
113
  @manager = ChannelManager.new(self, client.connection)
114
+ @push = PushChannel.new(self)
106
115
 
107
116
  setup_event_handlers
108
117
  setup_presence
@@ -116,7 +125,7 @@ module Ably
116
125
  # @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
117
126
  # @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
118
127
  #
119
- # @yield [Ably::Models::Message,Array<Ably::Models::Message>] On success, will call the block with the {Ably::Models::Message} if a single message is publishde, or an Array of {Ably::Models::Message} when multiple messages are published
128
+ # @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
120
129
  # @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
121
130
  #
122
131
  # @example
@@ -146,25 +155,30 @@ module Ably
146
155
  # end
147
156
  #
148
157
  def publish(name, data = nil, attributes = {}, &success_block)
149
- if detached? || detaching? || failed?
158
+ if suspended? || failed?
150
159
  error = Ably::Exceptions::ChannelInactive.new("Cannot publish messages on a channel in state #{state}")
151
160
  return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
152
161
  end
153
162
 
154
163
  if !connection.can_publish_messages?
155
- error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is configured to disallow queueing of messages and connection is currently #{connection.state}")
164
+ error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is not allowed to queue messages when connection is in state #{connection.state}")
156
165
  return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
157
166
  end
158
167
 
159
168
  messages = if name.kind_of?(Enumerable)
160
169
  name
161
170
  else
162
- ensure_utf_8 :name, name, allow_nil: true
171
+ name = ensure_utf_8(:name, name, allow_nil: true)
163
172
  ensure_supported_payload data
164
173
  [{ name: name, data: data }.merge(attributes)]
165
174
  end
166
175
 
167
- queue_messages(messages).tap do |deferrable|
176
+ if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
177
+ 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.")
178
+ return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
179
+ end
180
+
181
+ enqueue_messages_on_connection(client, messages, channel_name, options).tap do |deferrable|
168
182
  deferrable.callback(&success_block) if block_given?
169
183
  end
170
184
  end
@@ -291,7 +305,7 @@ module Ably
291
305
  # @api private
292
306
  def __incoming_msgbus__
293
307
  @__incoming_msgbus__ ||= Ably::Util::PubSub.new(
294
- coerce_into: Proc.new { |event| Ably::Models::ProtocolMessage::ACTION(event) }
308
+ coerce_into: lambda { |event| Ably::Models::ProtocolMessage::ACTION(event) }
295
309
  )
296
310
  end
297
311
 
@@ -321,12 +335,6 @@ module Ably
321
335
  client.logger
322
336
  end
323
337
 
324
- # Internal queue used for messages published that cannot yet be enqueued on the connection
325
- # @api private
326
- def __queue__
327
- @queue
328
- end
329
-
330
338
  # As we are using a state machine, do not allow change_state to be used
331
339
  # #transition_state_machine must be used instead
332
340
  private :change_state
@@ -339,98 +347,6 @@ module Ably
339
347
  end
340
348
  emit_message message.name, message
341
349
  end
342
-
343
- unsafe_on(STATE.Attached) do
344
- process_queue
345
- end
346
- end
347
-
348
- # Queue messages and process queue if channel is attached.
349
- # If channel is not yet attached, attempt to attach it before the message queue is processed.
350
- # @return [Ably::Util::SafeDeferrable]
351
- def queue_messages(raw_messages)
352
- messages = Array(raw_messages).map do |raw_msg|
353
- create_message(raw_msg).tap do |message|
354
- next if message.client_id.nil?
355
- if message.client_id == '*'
356
- raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
357
- end
358
- if message.client_id && !message.client_id.kind_of?(String)
359
- raise Ably::Exceptions::IncompatibleClientId.new('client_id must be a String when publishing messages')
360
- end
361
- unless client.auth.can_assume_client_id?(message.client_id)
362
- raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{message.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'")
363
- end
364
- end
365
- end
366
-
367
- __queue__.push(*messages)
368
-
369
- if attached?
370
- process_queue
371
- else
372
- attach
373
- end
374
-
375
- if messages.count == 1
376
- # A message is a Deferrable so, if publishing only one message, simply return that Deferrable
377
- messages.first
378
- else
379
- deferrable_for_multiple_messages(messages)
380
- end
381
- end
382
-
383
- # A deferrable object that calls the success callback once all messages are delivered
384
- # If any message fails, the errback is called immediately
385
- # Only one callback or errback is ever called i.e. if a group of messages all fail, only once
386
- # errback will be invoked
387
- def deferrable_for_multiple_messages(messages)
388
- expected_deliveries = messages.count
389
- actual_deliveries = 0
390
- failed = false
391
-
392
- Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
393
- messages.each do |message|
394
- message.callback do
395
- next if failed
396
- actual_deliveries += 1
397
- deferrable.succeed messages if actual_deliveries == expected_deliveries
398
- end
399
- message.errback do |error|
400
- next if failed
401
- failed = true
402
- deferrable.fail error, message
403
- end
404
- end
405
- end
406
- end
407
-
408
- def messages_in_queue?
409
- !__queue__.empty?
410
- end
411
-
412
- # Move messages from Channel Queue into Outgoing Connection Queue
413
- def process_queue
414
- condition = -> { attached? && messages_in_queue? }
415
- non_blocking_loop_while(condition) do
416
- send_messages_within_protocol_message __queue__.shift(MAX_PROTOCOL_MESSAGE_BATCH_SIZE)
417
- end
418
- end
419
-
420
- def send_messages_within_protocol_message(messages)
421
- connection.send_protocol_message(
422
- action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
423
- channel: name,
424
- messages: messages
425
- )
426
- end
427
-
428
- def create_message(message)
429
- Ably::Models::Message(message.dup).tap do |msg|
430
- msg.encode(client.encoders, options) do |encode_error, error_message|
431
- client.logger.error error_message
432
- end
433
- end
434
350
  end
435
351
 
436
352
  def rest_channel
@@ -444,9 +360,15 @@ module Ably
444
360
  def setup_presence
445
361
  @presence ||= Presence.new(self)
446
362
  end
363
+
364
+ # Alias useful for methods with a name argument
365
+ def channel_name
366
+ name
367
+ end
447
368
  end
448
369
  end
449
370
  end
450
371
 
451
372
  require 'ably/realtime/channel/channel_manager'
452
373
  require 'ably/realtime/channel/channel_state_machine'
374
+ require 'ably/realtime/channel/push_channel'
@@ -98,7 +98,7 @@ module Ably::Realtime
98
98
  def fail_messages_awaiting_ack(error, options = {})
99
99
  immediately = options[:immediately] || false
100
100
 
101
- fail_proc = Proc.new do
101
+ fail_proc = lambda do
102
102
  error = Ably::Exceptions::MessageDeliveryFailed.new("Continuity of connection was lost so published messages awaiting ACK have failed") unless error
103
103
  fail_messages_in_queue connection.__pending_message_ack_queue__, error
104
104
  end
@@ -111,16 +111,12 @@ module Ably::Realtime
111
111
  end
112
112
  end
113
113
 
114
- # When a channel becomes detached, suspended or failed,
114
+ # When a channel becomes suspended or failed,
115
115
  # all queued messages should be failed immediately as we don't queue in
116
116
  # any of those states
117
117
  def fail_queued_messages(error)
118
118
  error = Ably::Exceptions::MessageDeliveryFailed.new("Queued messages on channel '#{channel.name}' in state '#{channel.state}' will never be delivered") unless error
119
119
  fail_messages_in_queue connection.__outgoing_message_queue__, error
120
- channel.__queue__.each do |message|
121
- nack_message message, error
122
- end
123
- channel.__queue__.clear
124
120
  end
125
121
 
126
122
  def fail_messages_in_queue(queue, error)
@@ -214,7 +210,7 @@ module Ably::Realtime
214
210
  state_at_time_of_request = channel.state
215
211
  @pending_state_change_timer = EventMachine::Timer.new(realtime_request_timeout) do
216
212
  if channel.state == state_at_time_of_request
217
- error = Ably::Models::ErrorInfo.new(code: 90007, message: "Channel #{new_state} operation failed (timed out)")
213
+ error = Ably::Models::ErrorInfo.new(code: Ably::Exceptions::Codes::CHANNEL_OPERATION_FAILED_NO_RESPONSE_FROM_SERVER, message: "Channel #{new_state} operation failed (timed out)")
218
214
  channel.transition_state_machine state_if_failed, reason: error
219
215
  end
220
216
  end
@@ -224,7 +220,7 @@ module Ably::Realtime
224
220
  @pending_state_change_timer = nil
225
221
  end
226
222
 
227
- resend_if_disconnected_and_connected = Proc.new do
223
+ resend_if_disconnected_and_connected = lambda do
228
224
  connection.unsafe_once(:disconnected) do
229
225
  next unless pending_state_change_timer
230
226
  connection.unsafe_once(:connected) do
@@ -25,7 +25,7 @@ module Ably::Realtime
25
25
  transition :from => :attached, :to => [:attaching, :detaching, :detached, :failed, :suspended]
26
26
  transition :from => :detaching, :to => [:detached, :attaching, :attached, :failed, :suspended]
27
27
  transition :from => :detached, :to => [:attaching, :attached, :failed]
28
- transition :from => :suspended, :to => [:attaching, :detached, :failed]
28
+ transition :from => :suspended, :to => [:attaching, :attached, :detached, :failed]
29
29
  transition :from => :failed, :to => [:attaching]
30
30
 
31
31
  after_transition do |channel, transition|
@@ -47,7 +47,7 @@ module Ably::Realtime
47
47
 
48
48
  after_transition(to: [:detached, :failed, :suspended]) do |channel, current_transition|
49
49
  err = error_from_state_change(current_transition)
50
- channel.manager.fail_queued_messages err
50
+ channel.manager.fail_queued_messages(err) if channel.failed? or channel.suspended? #RTL11
51
51
  channel.manager.log_channel_error err if err
52
52
  end
53
53
 
@@ -0,0 +1,74 @@
1
+ module Ably::Realtime
2
+ class Channel
3
+ # Publisher module adds publishing capabilities to the current object
4
+ module Publisher
5
+ private
6
+
7
+ # Prepare and queue messages on the connection queue immediately
8
+ # @return [Ably::Util::SafeDeferrable]
9
+ def enqueue_messages_on_connection(client, raw_messages, channel_name, channel_options = {})
10
+ messages = Array(raw_messages).map do |raw_msg|
11
+ create_message(client, raw_msg, channel_options).tap do |message|
12
+ next if message.client_id.nil?
13
+ if message.client_id == '*'
14
+ raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
15
+ end
16
+ if message.client_id && !message.client_id.kind_of?(String)
17
+ raise Ably::Exceptions::IncompatibleClientId.new('client_id must be a String when publishing messages')
18
+ end
19
+ unless client.auth.can_assume_client_id?(message.client_id)
20
+ raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{message.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'")
21
+ end
22
+ end
23
+ end
24
+
25
+ connection.send_protocol_message(
26
+ action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
27
+ channel: channel_name,
28
+ messages: messages
29
+ )
30
+
31
+ if messages.count == 1
32
+ # A message is a Deferrable so, if publishing only one message, simply return that Deferrable
33
+ messages.first
34
+ else
35
+ deferrable_for_multiple_messages(messages)
36
+ end
37
+ end
38
+
39
+ # A deferrable object that calls the success callback once all messages are delivered
40
+ # If any message fails, the errback is called immediately
41
+ # Only one callback or errback is ever called i.e. if a group of messages all fail, only once
42
+ # errback will be invoked
43
+ def deferrable_for_multiple_messages(messages)
44
+ expected_deliveries = messages.count
45
+ actual_deliveries = 0
46
+ failed = false
47
+
48
+ Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
49
+ messages.each do |message|
50
+ message.callback do
51
+ next if failed
52
+ actual_deliveries += 1
53
+ deferrable.succeed messages if actual_deliveries == expected_deliveries
54
+ end
55
+ message.errback do |error|
56
+ next if failed
57
+ failed = true
58
+ deferrable.fail error, message
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def create_message(client, message, channel_options)
65
+ Ably::Models::Message(message.dup).tap do |msg|
66
+ msg.encode(client.encoders, channel_options) do |encode_error, error_message|
67
+ client.logger.error error_message
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+