ably-rest 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -14
- data/lib/submodules/ably-ruby/.editorconfig +14 -0
- data/lib/submodules/ably-ruby/.travis.yml +4 -4
- data/lib/submodules/ably-ruby/CHANGELOG.md +43 -2
- data/lib/submodules/ably-ruby/README.md +3 -2
- data/lib/submodules/ably-ruby/Rakefile +32 -0
- data/lib/submodules/ably-ruby/SPEC.md +1277 -835
- data/lib/submodules/ably-ruby/ably.gemspec +9 -4
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +30 -4
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +87 -0
- data/lib/submodules/ably-ruby/lib/ably/models/device_push_details.rb +86 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +23 -2
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +32 -2
- data/lib/submodules/ably-ruby/lib/ably/models/push_channel_subscription.rb +89 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +15 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -102
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +2 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/push_channel.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +87 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +8 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +7 -7
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +3 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/push.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/push/admin.rb +61 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +33 -5
- data/lib/submodules/ably-ruby/lib/ably/rest/channel/push_channel.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +138 -28
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/push.rb +42 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/push/admin.rb +54 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/push/device_registrations.rb +103 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +7 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +233 -8
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +166 -51
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +149 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +19 -17
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +5 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +696 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +41 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +129 -10
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +175 -4
- data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +896 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/push_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/run_parallel_tests +33 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +10 -3
- data/lib/submodules/ably-ruby/spec/unit/models/device_details_spec.rb +102 -0
- data/lib/submodules/ably-ruby/spec/unit/models/device_push_details_spec.rb +101 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +51 -3
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +17 -2
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/push_channel_subscription_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +12 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/push_channel_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +8 -1
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/push_channel_spec.rb +36 -0
- metadata +29 -4
@@ -157,7 +157,7 @@ module Ably::Realtime
|
|
157
157
|
logger.debug { "WebsocketTransport: Prot msg recv <=: #{action_name} - #{event_data}" }
|
158
158
|
|
159
159
|
if protocol_message.invalid?
|
160
|
-
error = Ably::Exceptions::ProtocolError.new("Invalid Protocol Message received: #{event_data}\nConnection moving to the failed state as the protocol is invalid and unsupported", 400,
|
160
|
+
error = Ably::Exceptions::ProtocolError.new("Invalid Protocol Message received: #{event_data}\nConnection moving to the failed state as the protocol is invalid and unsupported", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
161
161
|
logger.fatal { "WebsocketTransport: #{error.message}" }
|
162
162
|
failed_protocol_message = Ably::Models::ProtocolMessage.new(
|
163
163
|
action: Ably::Models::ProtocolMessage::ACTION.Error,
|
@@ -233,7 +233,7 @@ module Ably::Realtime
|
|
233
233
|
deferrable.fail Ably::Exceptions::InvalidState.new(
|
234
234
|
'Presence state is out of sync as channel is SUSPENDED. Presence#get on a SUSPENDED channel is only supported with option wait_for_sync: false',
|
235
235
|
nil,
|
236
|
-
|
236
|
+
Ably::Exceptions::Codes::PRESENCE_STATE_IS_OUT_OF_SYNC
|
237
237
|
)
|
238
238
|
end
|
239
239
|
return deferrable
|
@@ -330,7 +330,7 @@ module Ably::Realtime
|
|
330
330
|
def send_presence_protocol_message(presence_action, client_id, data)
|
331
331
|
presence_message = create_presence_message(presence_action, client_id, data)
|
332
332
|
unless presence_message.client_id
|
333
|
-
raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400,
|
333
|
+
raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID)
|
334
334
|
end
|
335
335
|
|
336
336
|
protocol_message = {
|
@@ -437,13 +437,13 @@ module Ably::Realtime
|
|
437
437
|
|
438
438
|
def attach_channel_then(deferrable)
|
439
439
|
if channel.detached? || channel.failed?
|
440
|
-
deferrable.fail Ably::Exceptions::InvalidState.new("Operation is not allowed when channel is in #{channel.state}", 400,
|
440
|
+
deferrable.fail Ably::Exceptions::InvalidState.new("Operation is not allowed when channel is in #{channel.state}", 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE)
|
441
441
|
else
|
442
442
|
channel.unsafe_once(:attached, :detached, :failed) do |channel_state_change|
|
443
443
|
if channel_state_change.current == :attached
|
444
444
|
yield
|
445
445
|
else
|
446
|
-
deferrable.fail Ably::Exceptions::InvalidState.new("Operation failed as channel transitioned to #{channel_state_change.current}", 400,
|
446
|
+
deferrable.fail Ably::Exceptions::InvalidState.new("Operation failed as channel transitioned to #{channel_state_change.current}", 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE)
|
447
447
|
end
|
448
448
|
end
|
449
449
|
channel.attach
|
@@ -275,7 +275,7 @@ module Ably::Realtime
|
|
275
275
|
presence_message_client_id = presence_message.client_id || client.auth.client_id
|
276
276
|
re_enter_error = Ably::Models::ErrorInfo.new(
|
277
277
|
message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'",
|
278
|
-
code:
|
278
|
+
code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL
|
279
279
|
)
|
280
280
|
channel.emit :update, Ably::Models::ChannelStateChange.new(
|
281
281
|
current: channel.state,
|
@@ -312,14 +312,14 @@ module Ably::Realtime
|
|
312
312
|
when Ably::Models::PresenceMessage::ACTION.Leave
|
313
313
|
remove_presence_member presence_message
|
314
314
|
else
|
315
|
-
Ably::Exceptions::ProtocolError.new("Protocol error, unknown presence action #{presence_message.action}", 400,
|
315
|
+
Ably::Exceptions::ProtocolError.new("Protocol error, unknown presence action #{presence_message.action}", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
316
316
|
end
|
317
317
|
end
|
318
318
|
|
319
319
|
def ensure_presence_message_is_valid(presence_message)
|
320
320
|
return true if presence_message.connection_id
|
321
321
|
|
322
|
-
error = Ably::Exceptions::ProtocolError.new("Protocol error, presence message is missing connectionId", 400,
|
322
|
+
error = Ably::Exceptions::ProtocolError.new("Protocol error, presence message is missing connectionId", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
323
323
|
logger.error { "PresenceMap: On channel '#{channel.name}' error: #{error}" }
|
324
324
|
end
|
325
325
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'ably/realtime/push/admin'
|
2
|
+
|
3
|
+
module Ably
|
4
|
+
module Realtime
|
5
|
+
# Class providing push notification functionality
|
6
|
+
class Push
|
7
|
+
# @private
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
end
|
13
|
+
|
14
|
+
# Admin features for push notifications like managing devices and channel subscriptions
|
15
|
+
# @return [Ably::Realtime::Push::Admin]
|
16
|
+
def admin
|
17
|
+
@admin ||= Admin.new(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Activate this device for push notifications by registering with the push transport such as GCM/APNS
|
21
|
+
#
|
22
|
+
# @note This is unsupported in the Ruby library
|
23
|
+
def activate(*arg)
|
24
|
+
raise_unsupported
|
25
|
+
end
|
26
|
+
|
27
|
+
# Deactivate this device for push notifications by removing the registration with the push transport such as GCM/APNS
|
28
|
+
#
|
29
|
+
# @note This is unsupported in the Ruby library
|
30
|
+
def deactivate(*arg)
|
31
|
+
raise_unsupported
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def raise_unsupported
|
36
|
+
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ably/realtime/push/device_registrations'
|
2
|
+
require 'ably/realtime/push/channel_subscriptions'
|
3
|
+
|
4
|
+
module Ably::Realtime
|
5
|
+
class Push
|
6
|
+
# Class providing push notification administrative functionality
|
7
|
+
# for registering devices and attaching to channels etc.
|
8
|
+
class Admin
|
9
|
+
include Ably::Modules::AsyncWrapper
|
10
|
+
include Ably::Modules::Conversions
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
attr_reader :client
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
attr_reader :push
|
17
|
+
|
18
|
+
def initialize(push)
|
19
|
+
@push = push
|
20
|
+
@client = push.client
|
21
|
+
end
|
22
|
+
|
23
|
+
# (see Ably::Rest::Push#publish)
|
24
|
+
#
|
25
|
+
# @yield Block is invoked upon successful publish of the message
|
26
|
+
# @return [Ably::Util::SafeDeferrable]
|
27
|
+
#
|
28
|
+
def publish(recipient, data, &callback)
|
29
|
+
raise ArgumentError, "Expecting a Hash object for recipient, got #{recipient.class}" unless recipient.kind_of?(Hash)
|
30
|
+
raise ArgumentError, "Recipient data is empty. You must provide recipient details" if recipient.empty?
|
31
|
+
raise ArgumentError, "Expecting a Hash object for data, got #{data.class}" unless data.kind_of?(Hash)
|
32
|
+
raise ArgumentError, "Push data field is empty. You must provide attributes for the push notification" if data.empty?
|
33
|
+
|
34
|
+
async_wrap(callback) do
|
35
|
+
rest_push_admin.publish(recipient, data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Manage device registrations
|
40
|
+
# @return [Ably::Realtime::Push::DeviceRegistrations]
|
41
|
+
def device_registrations
|
42
|
+
@device_registrations ||= DeviceRegistrations.new(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Manage channel subscriptions for devices or clients
|
46
|
+
# @return [Ably::Realtime::Push::ChannelSubscriptions]
|
47
|
+
def channel_subscriptions
|
48
|
+
@channel_subscriptions ||= ChannelSubscriptions.new(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def rest_push_admin
|
53
|
+
client.rest_client.push.admin
|
54
|
+
end
|
55
|
+
|
56
|
+
def logger
|
57
|
+
client.logger
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Ably::Realtime
|
2
|
+
class Push
|
3
|
+
# Manage push notification channel subscriptions for devices or clients
|
4
|
+
class ChannelSubscriptions
|
5
|
+
include Ably::Modules::Conversions
|
6
|
+
include Ably::Modules::AsyncWrapper
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
attr_reader :client
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
attr_reader :admin
|
13
|
+
|
14
|
+
def initialize(admin)
|
15
|
+
@admin = admin
|
16
|
+
@client = admin.client
|
17
|
+
end
|
18
|
+
|
19
|
+
# (see Ably::Rest::Push::ChannelSubscriptions#list)
|
20
|
+
#
|
21
|
+
# @yield Block is invoked when request succeeds
|
22
|
+
# @return [Ably::Util::SafeDeferrable]
|
23
|
+
#
|
24
|
+
def list(params, &callback)
|
25
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
26
|
+
|
27
|
+
if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
|
28
|
+
raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
|
29
|
+
end
|
30
|
+
|
31
|
+
async_wrap(callback) do
|
32
|
+
rest_channel_subscriptions.list(params.merge(async_blocking_operations: true))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# (see Ably::Rest::Push::ChannelSubscriptions#list_channels)
|
37
|
+
#
|
38
|
+
# @yield Block is invoked when request succeeds
|
39
|
+
# @return [Ably::Util::SafeDeferrable]
|
40
|
+
#
|
41
|
+
def list_channels(params = {}, &callback)
|
42
|
+
params = {} if params.nil?
|
43
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
44
|
+
|
45
|
+
async_wrap(callback) do
|
46
|
+
rest_channel_subscriptions.list_channels(params.merge(async_blocking_operations: true))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# (see Ably::Rest::Push::ChannelSubscriptions#save)
|
51
|
+
#
|
52
|
+
# @yield Block is invoked when request succeeds
|
53
|
+
# @return [Ably::Util::SafeDeferrable]
|
54
|
+
#
|
55
|
+
def save(push_channel_subscription, &callback)
|
56
|
+
push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
|
57
|
+
raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
|
58
|
+
|
59
|
+
async_wrap(callback) do
|
60
|
+
rest_channel_subscriptions.save(push_channel_subscription)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# (see Ably::Rest::Push::ChannelSubscriptions#remove)
|
65
|
+
#
|
66
|
+
# @yield Block is invoked when request succeeds
|
67
|
+
# @return [Ably::Util::SafeDeferrable]
|
68
|
+
#
|
69
|
+
def remove(push_channel_subscription, &callback)
|
70
|
+
push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
|
71
|
+
raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
|
72
|
+
if push_channel_subscription_object.client_id.to_s.empty? && push_channel_subscription_object.device_id.to_s.empty?
|
73
|
+
raise ArgumentError, "Either client_id or device_id must be present"
|
74
|
+
end
|
75
|
+
|
76
|
+
async_wrap(callback) do
|
77
|
+
rest_channel_subscriptions.remove(push_channel_subscription)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# (see Ably::Rest::Push::ChannelSubscriptions#remove_where)
|
82
|
+
#
|
83
|
+
# @yield Block is invoked when request succeeds
|
84
|
+
# @return [Ably::Util::SafeDeferrable]
|
85
|
+
#
|
86
|
+
def remove_where(params, &callback)
|
87
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
88
|
+
|
89
|
+
if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
|
90
|
+
raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
|
91
|
+
end
|
92
|
+
|
93
|
+
async_wrap(callback) do
|
94
|
+
rest_channel_subscriptions.remove_where(params)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def rest_channel_subscriptions
|
100
|
+
client.rest_client.push.admin.channel_subscriptions
|
101
|
+
end
|
102
|
+
|
103
|
+
def logger
|
104
|
+
client.logger
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Ably::Realtime
|
2
|
+
class Push
|
3
|
+
# Manage device registrations for push notifications
|
4
|
+
class DeviceRegistrations
|
5
|
+
include Ably::Modules::Conversions
|
6
|
+
include Ably::Modules::AsyncWrapper
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
attr_reader :client
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
attr_reader :admin
|
13
|
+
|
14
|
+
def initialize(admin)
|
15
|
+
@admin = admin
|
16
|
+
@client = admin.client
|
17
|
+
end
|
18
|
+
|
19
|
+
# (see Ably::Rest::Push::DeviceRegistrations#get)
|
20
|
+
#
|
21
|
+
# @yield Block is invoked when request succeeds
|
22
|
+
# @return [Ably::Util::SafeDeferrable]
|
23
|
+
#
|
24
|
+
def get(device_id, &callback)
|
25
|
+
device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
|
26
|
+
raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
|
27
|
+
|
28
|
+
async_wrap(callback) do
|
29
|
+
rest_device_registrations.get(device_id)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# (see Ably::Rest::Push::DeviceRegistrations#list)
|
34
|
+
#
|
35
|
+
# @yield Block is invoked when request succeeds
|
36
|
+
# @return [Ably::Util::SafeDeferrable]
|
37
|
+
#
|
38
|
+
def list(params = {}, &callback)
|
39
|
+
params = {} if params.nil?
|
40
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
41
|
+
raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
|
42
|
+
|
43
|
+
async_wrap(callback) do
|
44
|
+
rest_device_registrations.list(params.merge(async_blocking_operations: true))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# (see Ably::Rest::Push::DeviceRegistrations#save)
|
49
|
+
#
|
50
|
+
# @yield Block is invoked when request succeeds
|
51
|
+
# @return [Ably::Util::SafeDeferrable]
|
52
|
+
#
|
53
|
+
def save(device, &callback)
|
54
|
+
device_details = DeviceDetails(device)
|
55
|
+
raise ArgumentError, "Device ID is required yet is empty" if device_details.id.nil? || device_details == ''
|
56
|
+
|
57
|
+
async_wrap(callback) do
|
58
|
+
rest_device_registrations.save(device_details)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# (see Ably::Rest::Push::DeviceRegistrations#remove)
|
63
|
+
#
|
64
|
+
# @yield Block is invoked when request succeeds
|
65
|
+
# @return [Ably::Util::SafeDeferrable]
|
66
|
+
#
|
67
|
+
def remove(device_id, &callback)
|
68
|
+
device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
|
69
|
+
raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
|
70
|
+
|
71
|
+
async_wrap(callback) do
|
72
|
+
rest_device_registrations.remove(device_id)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# (see Ably::Rest::Push::DeviceRegistrations#remove_where)
|
77
|
+
#
|
78
|
+
# @yield Block is invoked when request succeeds
|
79
|
+
# @return [Ably::Util::SafeDeferrable]
|
80
|
+
#
|
81
|
+
def remove_where(params = {}, &callback)
|
82
|
+
filter = if params.kind_of?(Ably::Models::DeviceDetails)
|
83
|
+
{ 'deviceId' => params.id }
|
84
|
+
else
|
85
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
86
|
+
raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
|
87
|
+
IdiomaticRubyWrapper(params).as_json
|
88
|
+
end
|
89
|
+
|
90
|
+
async_wrap(callback) do
|
91
|
+
rest_device_registrations.remove_where(filter)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
def rest_device_registrations
|
97
|
+
client.rest_client.push.admin.device_registrations
|
98
|
+
end
|
99
|
+
|
100
|
+
def logger
|
101
|
+
client.logger
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -3,8 +3,6 @@ module Ably
|
|
3
3
|
# The Ably Realtime service organises the traffic within any application into named channels.
|
4
4
|
# Channels are the "unit" of message distribution; clients attach to channels to subscribe to messages, and every message broadcast by the service is associated with a unique channel.
|
5
5
|
#
|
6
|
-
# @!attribute [r] client
|
7
|
-
# @return {Ably::Realtime::Client} Ably client associated with this channel
|
8
6
|
# @!attribute [r] name
|
9
7
|
# @return {String} channel name
|
10
8
|
# @!attribute [r] options
|
@@ -12,7 +10,19 @@ module Ably
|
|
12
10
|
class Channel
|
13
11
|
include Ably::Modules::Conversions
|
14
12
|
|
15
|
-
|
13
|
+
# Ably client associated with this channel
|
14
|
+
# @return [Ably::Realtime::Client]
|
15
|
+
# @api private
|
16
|
+
attr_reader :client
|
17
|
+
|
18
|
+
attr_reader :name, :options
|
19
|
+
|
20
|
+
# Push channel used for push notification (client-side)
|
21
|
+
# @return [Ably::Rest::Channel::PushChannel]
|
22
|
+
# @api private
|
23
|
+
attr_reader :push
|
24
|
+
|
25
|
+
IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH = 9 # See spec RSL1k1
|
16
26
|
|
17
27
|
# Initialize a new Channel object
|
18
28
|
#
|
@@ -27,13 +37,14 @@ module Ably
|
|
27
37
|
update_options channel_options
|
28
38
|
@client = client
|
29
39
|
@name = name
|
40
|
+
@push = PushChannel.new(self)
|
30
41
|
end
|
31
42
|
|
32
43
|
# Publish one or more messages to the channel.
|
33
44
|
#
|
34
45
|
# @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
|
35
46
|
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
36
|
-
# @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
|
47
|
+
# @param attributes [Hash, nil] Optional additional message attributes such as :extras, :id, :client_id or :connection_id, applied when name attribute is nil or a string
|
37
48
|
# @return [Boolean] true if the message was published, otherwise false
|
38
49
|
#
|
39
50
|
# @example
|
@@ -58,12 +69,16 @@ module Ably
|
|
58
69
|
messages = if name.kind_of?(Enumerable)
|
59
70
|
name
|
60
71
|
else
|
72
|
+
if name.kind_of?(Ably::Models::Message)
|
73
|
+
raise ArgumentError, "name argument does not support single Message objects, only arrays of Message objects"
|
74
|
+
end
|
75
|
+
|
61
76
|
name = ensure_utf_8(:name, name, allow_nil: true)
|
62
77
|
ensure_supported_payload data
|
63
78
|
[{ name: name, data: data }.merge(attributes)]
|
64
79
|
end
|
65
80
|
|
66
|
-
payload = messages.map do |message|
|
81
|
+
payload = messages.each_with_index.map do |message, index|
|
67
82
|
Ably::Models::Message(message.dup).tap do |msg|
|
68
83
|
msg.encode client.encoders, options
|
69
84
|
|
@@ -75,6 +90,17 @@ module Ably
|
|
75
90
|
raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{msg.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'")
|
76
91
|
end
|
77
92
|
end.as_json
|
93
|
+
end.tap do |payload|
|
94
|
+
if client.idempotent_rest_publishing
|
95
|
+
# We cannot mutate for idempotent publishing if one or more messages already has an ID
|
96
|
+
if payload.all? { |msg| !msg['id'] }
|
97
|
+
# Mutate the JSON to support idempotent publishing where a Message.id does not exist
|
98
|
+
idempotent_publish_id = SecureRandom.base64(IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH)
|
99
|
+
payload.each_with_index do |msg, idx|
|
100
|
+
msg['id'] = "#{idempotent_publish_id}:#{idx}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
78
104
|
end
|
79
105
|
|
80
106
|
response = client.post("#{base_path}/publish", payload.length == 1 ? payload.first : payload)
|
@@ -141,3 +167,5 @@ module Ably
|
|
141
167
|
end
|
142
168
|
end
|
143
169
|
end
|
170
|
+
|
171
|
+
require 'ably/rest/channel/push_channel'
|