ably 1.0.6 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.travis.yml +10 -8
- data/CHANGELOG.md +75 -3
- data/LICENSE +1 -3
- data/README.md +12 -7
- data/Rakefile +32 -0
- data/SPEC.md +1277 -835
- data/ably.gemspec +14 -9
- data/lib/ably/auth.rb +30 -4
- data/lib/ably/exceptions.rb +10 -4
- data/lib/ably/logger.rb +7 -1
- data/lib/ably/models/channel_state_change.rb +1 -1
- data/lib/ably/models/connection_state_change.rb +1 -1
- data/lib/ably/models/device_details.rb +87 -0
- data/lib/ably/models/device_push_details.rb +86 -0
- data/lib/ably/models/error_info.rb +23 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
- data/lib/ably/models/protocol_message.rb +32 -2
- data/lib/ably/models/push_channel_subscription.rb +89 -0
- data/lib/ably/modules/conversions.rb +1 -1
- data/lib/ably/modules/encodeable.rb +1 -1
- data/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/ably/modules/model_common.rb +15 -2
- data/lib/ably/modules/state_machine.rb +2 -2
- data/lib/ably/realtime.rb +1 -0
- data/lib/ably/realtime/auth.rb +1 -1
- data/lib/ably/realtime/channel.rb +24 -102
- data/lib/ably/realtime/channel/channel_manager.rb +2 -6
- data/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
- data/lib/ably/realtime/channel/publisher.rb +74 -0
- data/lib/ably/realtime/channel/push_channel.rb +62 -0
- data/lib/ably/realtime/client.rb +91 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +34 -20
- data/lib/ably/realtime/connection/connection_manager.rb +25 -9
- data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
- data/lib/ably/realtime/presence.rb +4 -4
- data/lib/ably/realtime/presence/members_map.rb +3 -3
- data/lib/ably/realtime/push.rb +40 -0
- data/lib/ably/realtime/push/admin.rb +61 -0
- data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/ably/rest.rb +1 -0
- data/lib/ably/rest/channel.rb +53 -17
- data/lib/ably/rest/channel/push_channel.rb +62 -0
- data/lib/ably/rest/client.rb +154 -32
- data/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
- data/lib/ably/rest/presence.rb +1 -0
- data/lib/ably/rest/push.rb +42 -0
- data/lib/ably/rest/push/admin.rb +54 -0
- data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/ably/rest/push/device_registrations.rb +103 -0
- data/lib/ably/version.rb +7 -2
- data/spec/acceptance/realtime/auth_spec.rb +245 -17
- data/spec/acceptance/realtime/channel_history_spec.rb +26 -20
- data/spec/acceptance/realtime/channel_spec.rb +177 -59
- data/spec/acceptance/realtime/client_spec.rb +153 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +72 -6
- data/spec/acceptance/realtime/connection_spec.rb +129 -18
- data/spec/acceptance/realtime/message_spec.rb +36 -34
- data/spec/acceptance/realtime/presence_spec.rb +201 -167
- data/spec/acceptance/realtime/push_admin_spec.rb +736 -0
- data/spec/acceptance/realtime/push_spec.rb +27 -0
- data/spec/acceptance/rest/auth_spec.rb +41 -3
- data/spec/acceptance/rest/base_spec.rb +2 -2
- data/spec/acceptance/rest/channel_spec.rb +79 -4
- data/spec/acceptance/rest/channels_spec.rb +6 -0
- data/spec/acceptance/rest/client_spec.rb +129 -10
- data/spec/acceptance/rest/message_spec.rb +158 -6
- data/spec/acceptance/rest/push_admin_spec.rb +952 -0
- data/spec/acceptance/rest/push_spec.rb +25 -0
- data/spec/acceptance/rest/time_spec.rb +1 -1
- data/spec/run_parallel_tests +33 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/debug_failure_helper.rb +9 -5
- data/spec/support/test_app.rb +2 -2
- data/spec/unit/logger_spec.rb +10 -3
- data/spec/unit/models/device_details_spec.rb +102 -0
- data/spec/unit/models/device_push_details_spec.rb +101 -0
- data/spec/unit/models/error_info_spec.rb +51 -3
- data/spec/unit/models/message_spec.rb +17 -2
- data/spec/unit/models/presence_message_spec.rb +1 -1
- data/spec/unit/models/push_channel_subscription_spec.rb +86 -0
- data/spec/unit/modules/enum_spec.rb +1 -1
- data/spec/unit/realtime/client_spec.rb +13 -1
- data/spec/unit/realtime/connection_spec.rb +1 -1
- data/spec/unit/realtime/push_channel_spec.rb +36 -0
- data/spec/unit/rest/channel_spec.rb +8 -1
- data/spec/unit/rest/client_spec.rb +30 -0
- data/spec/unit/rest/push_channel_spec.rb +36 -0
- metadata +95 -26
@@ -198,12 +198,42 @@ module Ably::Models
|
|
198
198
|
|
199
199
|
# @api private
|
200
200
|
def has_backlog_flag?
|
201
|
-
flags & 2 == 2
|
201
|
+
flags & 2 == 2 # 2^1
|
202
202
|
end
|
203
203
|
|
204
204
|
# @api private
|
205
205
|
def has_channel_resumed_flag?
|
206
|
-
flags & 4 == 4
|
206
|
+
flags & 4 == 4 # 2^2
|
207
|
+
end
|
208
|
+
|
209
|
+
# @api private
|
210
|
+
def has_local_presence_flag?
|
211
|
+
flags & 8 == 8 # 2^3
|
212
|
+
end
|
213
|
+
|
214
|
+
# @api private
|
215
|
+
def has_transient_flag?
|
216
|
+
flags & 16 == 16 # 2^4
|
217
|
+
end
|
218
|
+
|
219
|
+
# @api private
|
220
|
+
def has_attach_presence_flag?
|
221
|
+
flags & 65536 == 65536 # 2^16
|
222
|
+
end
|
223
|
+
|
224
|
+
# @api private
|
225
|
+
def has_attach_publish_flag?
|
226
|
+
flags & 131072 == 131072 # 2^17
|
227
|
+
end
|
228
|
+
|
229
|
+
# @api private
|
230
|
+
def has_attach_subscribe_flag?
|
231
|
+
flags & 262144 == 262144 # 2^18
|
232
|
+
end
|
233
|
+
|
234
|
+
# @api private
|
235
|
+
def has_attach_presence_subscribe_flag?
|
236
|
+
flags & 524288 == 524288 # 2^19
|
207
237
|
end
|
208
238
|
|
209
239
|
def connection_details
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
module Conversions
|
3
|
+
private
|
4
|
+
# Convert push_channel_subscription argument to a {Ably::Models::PushChannelSubscription} object
|
5
|
+
#
|
6
|
+
# @param push_channel_subscription [Ably::Models::PushChannelSubscription,Hash,nil] A device details object
|
7
|
+
#
|
8
|
+
# @return [Ably::Models::PushChannelSubscription]
|
9
|
+
def PushChannelSubscription(push_channel_subscription)
|
10
|
+
case push_channel_subscription
|
11
|
+
when Ably::Models::PushChannelSubscription
|
12
|
+
push_channel_subscription
|
13
|
+
else
|
14
|
+
Ably::Models::PushChannelSubscription.new(push_channel_subscription)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Ably::Models
|
21
|
+
# An object representing a devices details, used currently for push notifications
|
22
|
+
#
|
23
|
+
# @!attribute [r] channel
|
24
|
+
# @return [String] The realtime pub/sub channel this subscription is registered to
|
25
|
+
# @!attribute [r] client_id
|
26
|
+
# @return [String] Client ID that is assigned to one or more registered push devices
|
27
|
+
# @!attribute [r] device_id
|
28
|
+
# @return [String] Unique device identifier assigned to the push device
|
29
|
+
#
|
30
|
+
class PushChannelSubscription < Ably::Exceptions::BaseAblyException
|
31
|
+
include Ably::Modules::ModelCommon
|
32
|
+
|
33
|
+
# @param hash_object [Hash,nil] Device detail attributes
|
34
|
+
#a
|
35
|
+
def initialize(hash_object = {})
|
36
|
+
@raw_hash_object = hash_object || {}
|
37
|
+
@hash_object = IdiomaticRubyWrapper(hash_object)
|
38
|
+
|
39
|
+
if !attributes[:client_id] && !attributes[:device_id]
|
40
|
+
raise ArgumentError, 'Either client_id or device_id must be provided'
|
41
|
+
end
|
42
|
+
if attributes[:client_id] && attributes[:device_id]
|
43
|
+
raise ArgumentError, 'client_id and device_id cannot both be provided, they are mutually exclusive'
|
44
|
+
end
|
45
|
+
if !attributes[:channel]
|
46
|
+
raise ArgumentError, 'channel is required'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Constructor for channel subscription by device ID
|
51
|
+
#
|
52
|
+
# @param channel [String] the realtime pub/sub channel this subscription is registered to
|
53
|
+
# @param device_id [String] Unique device identifier assigned to the push device
|
54
|
+
#
|
55
|
+
# @return [PushChannelSubscription]
|
56
|
+
#
|
57
|
+
def self.for_device(channel, device_id)
|
58
|
+
PushChannelSubscription.new(channel: channel, device_id: device_id)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Constructor for channel subscription by client ID
|
62
|
+
#
|
63
|
+
# @param channel [String] the realtime pub/sub channel this subscription is registered to
|
64
|
+
# @param client_id [String] Client ID that is assigned to one or more registered push devices
|
65
|
+
#
|
66
|
+
# @return [PushChannelSubscription]
|
67
|
+
#
|
68
|
+
def self.for_client_id(channel, client_id)
|
69
|
+
PushChannelSubscription.new(channel: channel, client_id: client_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
%w(channel client_id device_id).each do |attribute|
|
73
|
+
define_method attribute do
|
74
|
+
attributes[attribute.to_sym]
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method "#{attribute}=" do |val|
|
78
|
+
unless val.nil? || val.kind_of?(String)
|
79
|
+
raise ArgumentError, "#{attribute} must be nil or a string value"
|
80
|
+
end
|
81
|
+
attributes[attribute.to_sym] = val
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def attributes
|
86
|
+
@hash_object
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -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,
|
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
|
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]
|
48
|
-
# @return a new instance
|
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))
|
@@ -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,
|
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
|
data/lib/ably/realtime.rb
CHANGED
data/lib/ably/realtime/auth.rb
CHANGED
@@ -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,
|
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
|
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
|
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
|
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
|
-
|
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'
|