ably 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +14 -0
  3. data/.travis.yml +4 -4
  4. data/CHANGELOG.md +26 -3
  5. data/Rakefile +32 -0
  6. data/SPEC.md +920 -565
  7. data/ably.gemspec +9 -4
  8. data/lib/ably/auth.rb +28 -2
  9. data/lib/ably/exceptions.rb +8 -2
  10. data/lib/ably/models/channel_state_change.rb +1 -1
  11. data/lib/ably/models/connection_state_change.rb +1 -1
  12. data/lib/ably/models/device_details.rb +87 -0
  13. data/lib/ably/models/device_push_details.rb +86 -0
  14. data/lib/ably/models/error_info.rb +23 -2
  15. data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
  16. data/lib/ably/models/protocol_message.rb +32 -2
  17. data/lib/ably/models/push_channel_subscription.rb +89 -0
  18. data/lib/ably/modules/conversions.rb +1 -1
  19. data/lib/ably/modules/encodeable.rb +1 -1
  20. data/lib/ably/modules/exception_codes.rb +128 -0
  21. data/lib/ably/modules/model_common.rb +15 -2
  22. data/lib/ably/modules/state_machine.rb +1 -1
  23. data/lib/ably/realtime.rb +1 -0
  24. data/lib/ably/realtime/auth.rb +1 -1
  25. data/lib/ably/realtime/channel.rb +24 -102
  26. data/lib/ably/realtime/channel/channel_manager.rb +2 -6
  27. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
  28. data/lib/ably/realtime/channel/publisher.rb +74 -0
  29. data/lib/ably/realtime/channel/push_channel.rb +62 -0
  30. data/lib/ably/realtime/client.rb +87 -0
  31. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
  32. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  33. data/lib/ably/realtime/connection.rb +8 -5
  34. data/lib/ably/realtime/connection/connection_manager.rb +7 -7
  35. data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
  36. data/lib/ably/realtime/presence.rb +4 -4
  37. data/lib/ably/realtime/presence/members_map.rb +3 -3
  38. data/lib/ably/realtime/push.rb +40 -0
  39. data/lib/ably/realtime/push/admin.rb +61 -0
  40. data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  41. data/lib/ably/realtime/push/device_registrations.rb +105 -0
  42. data/lib/ably/rest.rb +1 -0
  43. data/lib/ably/rest/channel.rb +33 -5
  44. data/lib/ably/rest/channel/push_channel.rb +62 -0
  45. data/lib/ably/rest/client.rb +137 -28
  46. data/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
  47. data/lib/ably/rest/presence.rb +1 -0
  48. data/lib/ably/rest/push.rb +42 -0
  49. data/lib/ably/rest/push/admin.rb +54 -0
  50. data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  51. data/lib/ably/rest/push/device_registrations.rb +103 -0
  52. data/lib/ably/version.rb +7 -2
  53. data/spec/acceptance/realtime/auth_spec.rb +6 -8
  54. data/spec/acceptance/realtime/channel_spec.rb +166 -51
  55. data/spec/acceptance/realtime/client_spec.rb +149 -0
  56. data/spec/acceptance/realtime/connection_failures_spec.rb +1 -1
  57. data/spec/acceptance/realtime/connection_spec.rb +4 -4
  58. data/spec/acceptance/realtime/message_spec.rb +19 -17
  59. data/spec/acceptance/realtime/presence_spec.rb +5 -5
  60. data/spec/acceptance/realtime/push_admin_spec.rb +696 -0
  61. data/spec/acceptance/realtime/push_spec.rb +27 -0
  62. data/spec/acceptance/rest/auth_spec.rb +4 -3
  63. data/spec/acceptance/rest/base_spec.rb +2 -2
  64. data/spec/acceptance/rest/client_spec.rb +129 -10
  65. data/spec/acceptance/rest/message_spec.rb +175 -4
  66. data/spec/acceptance/rest/push_admin_spec.rb +896 -0
  67. data/spec/acceptance/rest/push_spec.rb +25 -0
  68. data/spec/acceptance/rest/time_spec.rb +1 -1
  69. data/spec/run_parallel_tests +33 -0
  70. data/spec/unit/logger_spec.rb +10 -3
  71. data/spec/unit/models/device_details_spec.rb +102 -0
  72. data/spec/unit/models/device_push_details_spec.rb +101 -0
  73. data/spec/unit/models/error_info_spec.rb +51 -3
  74. data/spec/unit/models/message_spec.rb +17 -2
  75. data/spec/unit/models/presence_message_spec.rb +1 -1
  76. data/spec/unit/models/push_channel_subscription_spec.rb +86 -0
  77. data/spec/unit/realtime/client_spec.rb +12 -0
  78. data/spec/unit/realtime/push_channel_spec.rb +36 -0
  79. data/spec/unit/rest/channel_spec.rb +8 -1
  80. data/spec/unit/rest/client_spec.rb +30 -0
  81. data/spec/unit/rest/push_channel_spec.rb +36 -0
  82. metadata +71 -8
@@ -113,7 +113,7 @@ module Ably::Modules
113
113
  payload.kind_of?(Array) ||
114
114
  payload.nil?
115
115
 
116
- raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400, 40011)
116
+ raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400, Ably::Exceptions::Codes::INVALID_MESSAGE_DATA_OR_ENCODING)
117
117
  end
118
118
  end
119
119
  end
@@ -27,7 +27,7 @@ module Ably::Modules
27
27
  end
28
28
 
29
29
  # Return an Array of Message or Presence objects from the encoded Array of JSON-like objects, using the optional channel options
30
- # @param message_objects [Array<Hash>] Array of JSON-like objects with encoded messages
30
+ # @param message_object_array [Array<Hash>] Array of JSON-like objects with encoded messages
31
31
  # @param channel_options [Hash] Channel options, currently reserved for Encryption options
32
32
  # @return [Array<Message,Presence>]
33
33
  def from_encoded_array(message_object_array, channel_options = {})
@@ -0,0 +1,128 @@
1
+ # This file is generated by running `rake :generate_error_codes`
2
+ # Do not manually modify this file
3
+ # Generated at: 2018-09-18 18:28:58 UTC
4
+ #
5
+ module Ably
6
+ module Exceptions
7
+ module Codes
8
+ NO_ERROR = 10000
9
+ BAD_REQUEST = 40000
10
+ INVALID_REQUEST_BODY = 40001
11
+ INVALID_PARAMETER_NAME = 40002
12
+ INVALID_PARAMETER_VALUE = 40003
13
+ INVALID_HEADER = 40004
14
+ INVALID_CREDENTIAL = 40005
15
+ INVALID_CONNECTION_ID = 40006
16
+ INVALID_MESSAGE_ID = 40007
17
+ INVALID_CONTENT_LENGTH = 40008
18
+ MAXIMUM_MESSAGE_LENGTH_EXCEEDED = 40009
19
+ INVALID_CHANNEL_NAME = 40010
20
+ STALE_RING_STATE = 40011
21
+ INVALID_CLIENT_ID = 40012
22
+ INVALID_MESSAGE_DATA_OR_ENCODING = 40013
23
+ RESOURCE_DISPOSED = 40014
24
+ INVALID_DEVICE_ID = 40015
25
+ BATCH_ERROR = 40020
26
+ INVALID_PUBLISH_REQUEST_UNSPECIFIED = 40030
27
+ INVALID_PUBLISH_REQUEST_INVALID_CLIENTSPECIFIED_ID = 40031
28
+ UNAUTHORIZED = 40100
29
+ INVALID_CREDENTIALS = 40101
30
+ INCOMPATIBLE_CREDENTIALS = 40102
31
+ INVALID_USE_OF_BASIC_AUTH_OVER_NONTLS_TRANSPORT = 40103
32
+ TIMESTAMP_NOT_CURRENT = 40104
33
+ NONCE_VALUE_REPLAYED = 40105
34
+ UNABLE_TO_OBTAIN_CREDENTIALS_FROM_GIVEN_PARAMETERS = 40106
35
+ ACCOUNT_DISABLED = 40110
36
+ ACCOUNT_RESTRICTED_CONNECTION_LIMITS_EXCEEDED = 40111
37
+ ACCOUNT_BLOCKED_MESSAGE_LIMITS_EXCEEDED = 40112
38
+ ACCOUNT_BLOCKED = 40113
39
+ ACCOUNT_RESTRICTED_CHANNEL_LIMITS_EXCEEDED = 40114
40
+ APPLICATION_DISABLED = 40120
41
+ KEY_ERROR_UNSPECIFIED = 40130
42
+ KEY_REVOKED = 40131
43
+ KEY_EXPIRED = 40132
44
+ KEY_DISABLED = 40133
45
+ TOKEN_ERROR_UNSPECIFIED = 40140
46
+ TOKEN_REVOKED = 40141
47
+ TOKEN_EXPIRED = 40142
48
+ TOKEN_UNRECOGNISED = 40143
49
+ INVALID_JWT_FORMAT = 40144
50
+ INVALID_TOKEN_FORMAT = 40145
51
+ CONNECTION_BLOCKED_LIMITS_EXCEEDED = 40150
52
+ OPERATION_NOT_PERMITTED_WITH_PROVIDED_CAPABILITY = 40160
53
+ ERROR_FROM_CLIENT_TOKEN_CALLBACK = 40170
54
+ FORBIDDEN = 40300
55
+ ACCOUNT_DOES_NOT_PERMIT_TLS_CONNECTION = 40310
56
+ OPERATION_REQUIRES_TLS_CONNECTION = 40311
57
+ APPLICATION_REQUIRES_AUTHENTICATION = 40320
58
+ UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_UNSPECIFIED = 40330
59
+ UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_INCOMPATIBLE_ENVIRONMENT = 40331
60
+ UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_INCOMPATIBLE_SITE = 40332
61
+ NOT_FOUND = 40400
62
+ METHOD_NOT_ALLOWED = 40500
63
+ RATE_LIMIT_EXCEEDED_NONFATAL_REQUEST_REJECTED_UNSPECIFIED = 42910
64
+ MAX_PERCONNECTION_PUBLISH_RATE_LIMIT_EXCEEDED_NONFATAL_UNABLE_TO_PUBLISH_MESSAGE = 42911
65
+ RATE_LIMIT_EXCEEDED_FATAL = 42920
66
+ MAX_PERCONNECTION_PUBLISH_RATE_LIMIT_EXCEEDED_FATAL_CLOSING_CONNECTION = 42921
67
+ INTERNAL_ERROR = 50000
68
+ INTERNAL_CHANNEL_ERROR = 50001
69
+ INTERNAL_CONNECTION_ERROR = 50002
70
+ TIMEOUT_ERROR = 50003
71
+ REQUEST_FAILED_DUE_TO_OVERLOADED_INSTANCE = 50004
72
+ REACTOR_OPERATION_FAILED = 70000
73
+ REACTOR_OPERATION_FAILED_POST_OPERATION_FAILED = 70001
74
+ REACTOR_OPERATION_FAILED_POST_OPERATION_RETURNED_UNEXPECTED_CODE = 70002
75
+ REACTOR_OPERATION_FAILED_MAXIMUM_NUMBER_OF_CONCURRENT_INFLIGHT_REQUESTS_EXCEEDED = 70003
76
+ EXCHANGE_ERROR_UNSPECIFIED = 71000
77
+ FORCED_REATTACHMENT_DUE_TO_PERMISSIONS_CHANGE = 71001
78
+ EXCHANGE_PUBLISHER_ERROR_UNSPECIFIED = 71100
79
+ NO_SUCH_PUBLISHER = 71101
80
+ PUBLISHER_NOT_ENABLED_AS_AN_EXCHANGE_PUBLISHER = 71102
81
+ EXCHANGE_PRODUCT_ERROR_UNSPECIFIED = 71200
82
+ NO_SUCH_PRODUCT = 71201
83
+ PRODUCT_DISABLED = 71202
84
+ NO_SUCH_CHANNEL_IN_THIS_PRODUCT = 71203
85
+ EXCHANGE_SUBSCRIPTION_ERROR_UNSPECIFIED = 71300
86
+ SUBSCRIPTION_DISABLED = 71301
87
+ REQUESTER_HAS_NO_SUBSCRIPTION_TO_THIS_PRODUCT = 71302
88
+ CONNECTION_FAILED = 80000
89
+ CONNECTION_FAILED_NO_COMPATIBLE_TRANSPORT = 80001
90
+ CONNECTION_SUSPENDED = 80002
91
+ DISCONNECTED = 80003
92
+ ALREADY_CONNECTED = 80004
93
+ INVALID_CONNECTION_ID_REMOTE_NOT_FOUND = 80005
94
+ UNABLE_TO_RECOVER_CONNECTION_MESSAGES_EXPIRED = 80006
95
+ UNABLE_TO_RECOVER_CONNECTION_MESSAGE_LIMIT_EXCEEDED = 80007
96
+ UNABLE_TO_RECOVER_CONNECTION_CONNECTION_EXPIRED = 80008
97
+ CONNECTION_NOT_ESTABLISHED_NO_TRANSPORT_HANDLE = 80009
98
+ INVALID_OPERATION_INVALID_TRANSPORT_HANDLE = 80010
99
+ UNABLE_TO_RECOVER_CONNECTION_INCOMPATIBLE_AUTH_PARAMS = 80011
100
+ UNABLE_TO_RECOVER_CONNECTION_INVALID_OR_UNSPECIFIED_CONNECTION_SERIAL = 80012
101
+ PROTOCOL_ERROR = 80013
102
+ CONNECTION_TIMED_OUT = 80014
103
+ INCOMPATIBLE_CONNECTION_PARAMETERS = 80015
104
+ OPERATION_ON_SUPERSEDED_TRANSPORT = 80016
105
+ CONNECTION_CLOSED = 80017
106
+ INVALID_CONNECTION_ID_INVALID_FORMAT = 80018
107
+ CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED = 80019
108
+ CONTINUITY_LOSS_DUE_TO_MAXIMUM_SUBSCRIBE_MESSAGE_RATE_EXCEEDED = 80020
109
+ CLIENT_RESTRICTION_NOT_SATISFIED = 80030
110
+ CHANNEL_OPERATION_FAILED = 90000
111
+ CHANNEL_OPERATION_FAILED_INVALID_CHANNEL_STATE = 90001
112
+ CHANNEL_OPERATION_FAILED_EPOCH_EXPIRED_OR_NEVER_EXISTED = 90002
113
+ UNABLE_TO_RECOVER_CHANNEL_MESSAGES_EXPIRED = 90003
114
+ UNABLE_TO_RECOVER_CHANNEL_MESSAGE_LIMIT_EXCEEDED = 90004
115
+ UNABLE_TO_RECOVER_CHANNEL_NO_MATCHING_EPOCH = 90005
116
+ UNABLE_TO_RECOVER_CHANNEL_UNBOUNDED_REQUEST = 90006
117
+ CHANNEL_OPERATION_FAILED_NO_RESPONSE_FROM_SERVER = 90007
118
+ MAXIMUM_NUMBER_OF_CHANNELS_PER_CONNECTION_EXCEEDED = 90010
119
+ UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID = 91000
120
+ UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE = 91001
121
+ UNABLE_TO_LEAVE_PRESENCE_CHANNEL_THAT_IS_NOT_ENTERED = 91002
122
+ UNABLE_TO_ENTER_PRESENCE_CHANNEL_MAXIMUM_MEMBER_LIMIT_EXCEEDED = 91003
123
+ UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL = 91004
124
+ PRESENCE_STATE_IS_OUT_OF_SYNC = 91005
125
+ MEMBER_IMPLICITLY_LEFT_PRESENCE_CHANNEL_CONNECTION_CLOSED = 91100
126
+ end
127
+ end
128
+ end
@@ -42,10 +42,23 @@ module Ably::Modules
42
42
  attributes.hash
43
43
  end
44
44
 
45
+ def to_s
46
+ representation = attributes.map do |key, val|
47
+ if val.nil?
48
+ nil
49
+ else
50
+ val_str = val.to_s
51
+ val_str = "#{val_str[0...80]}..." if val_str.length > 80
52
+ "#{key}=#{val_str}"
53
+ end
54
+ end
55
+ "<#{self.class.name}: #{representation.compact.join(', ')}>"
56
+ end
57
+
45
58
  module ClassMethods
46
59
  # Return a new instance of this object using the provided JSON-like object or JSON string
47
- # @param [Hash, String] JSON-like object or JSON string
48
- # @return a new instance o this object
60
+ # @param json_like_object [Hash, String] JSON-like object or JSON string
61
+ # @return a new instance to this object
49
62
  def from_json(json_like_object)
50
63
  if json_like_object.kind_of?(String)
51
64
  new(JSON.parse(json_like_object))
@@ -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'
@@ -239,7 +239,7 @@ module Ably
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
@@ -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,13 +155,13 @@ 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
 
@@ -164,7 +173,12 @@ module Ably
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
@@ -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'
@@ -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
@@ -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