ably-pubsub-core 0.0.1.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ably/agent.rb +8 -0
  3. data/lib/ably/auth.rb +791 -0
  4. data/lib/ably/exceptions.rb +169 -0
  5. data/lib/ably/logger.rb +119 -0
  6. data/lib/ably/models/auth_details.rb +45 -0
  7. data/lib/ably/models/channel_details.rb +69 -0
  8. data/lib/ably/models/channel_metrics.rb +107 -0
  9. data/lib/ably/models/channel_occupancy.rb +50 -0
  10. data/lib/ably/models/channel_options.rb +120 -0
  11. data/lib/ably/models/channel_state_change.rb +84 -0
  12. data/lib/ably/models/channel_status.rb +63 -0
  13. data/lib/ably/models/cipher_params.rb +137 -0
  14. data/lib/ably/models/connection_details.rb +149 -0
  15. data/lib/ably/models/connection_state_change.rb +83 -0
  16. data/lib/ably/models/delta_extras.rb +28 -0
  17. data/lib/ably/models/device_details.rb +126 -0
  18. data/lib/ably/models/device_push_details.rb +94 -0
  19. data/lib/ably/models/error_info.rb +104 -0
  20. data/lib/ably/models/http_paginated_response.rb +112 -0
  21. data/lib/ably/models/idiomatic_ruby_wrapper.rb +235 -0
  22. data/lib/ably/models/message.rb +223 -0
  23. data/lib/ably/models/message_encoders/base.rb +135 -0
  24. data/lib/ably/models/message_encoders/base64.rb +40 -0
  25. data/lib/ably/models/message_encoders/cipher.rb +84 -0
  26. data/lib/ably/models/message_encoders/json.rb +34 -0
  27. data/lib/ably/models/message_encoders/utf8.rb +26 -0
  28. data/lib/ably/models/nil_logger.rb +20 -0
  29. data/lib/ably/models/paginated_result.rb +201 -0
  30. data/lib/ably/models/presence_message.rb +244 -0
  31. data/lib/ably/models/protocol_message.rb +288 -0
  32. data/lib/ably/models/push_channel_subscription.rb +114 -0
  33. data/lib/ably/models/stats.rb +242 -0
  34. data/lib/ably/models/stats_types.rb +107 -0
  35. data/lib/ably/models/token_details.rb +148 -0
  36. data/lib/ably/models/token_request.rb +180 -0
  37. data/lib/ably/modules/ably.rb +26 -0
  38. data/lib/ably/modules/async_wrapper.rb +69 -0
  39. data/lib/ably/modules/channels_collection.rb +105 -0
  40. data/lib/ably/modules/conversions.rb +153 -0
  41. data/lib/ably/modules/encodeable.rb +111 -0
  42. data/lib/ably/modules/enum.rb +230 -0
  43. data/lib/ably/modules/event_emitter.rb +200 -0
  44. data/lib/ably/modules/event_machine_helpers.rb +26 -0
  45. data/lib/ably/modules/exception_codes.rb +128 -0
  46. data/lib/ably/modules/http_helpers.rb +41 -0
  47. data/lib/ably/modules/message_emitter.rb +78 -0
  48. data/lib/ably/modules/message_pack.rb +14 -0
  49. data/lib/ably/modules/model_common.rb +84 -0
  50. data/lib/ably/modules/safe_deferrable.rb +83 -0
  51. data/lib/ably/modules/safe_yield.rb +41 -0
  52. data/lib/ably/modules/state_emitter.rb +181 -0
  53. data/lib/ably/modules/state_machine.rb +59 -0
  54. data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  55. data/lib/ably/modules/uses_state_machine.rb +111 -0
  56. data/lib/ably/realtime/auth.rb +283 -0
  57. data/lib/ably/realtime/channel/channel_manager.rb +272 -0
  58. data/lib/ably/realtime/channel/channel_properties.rb +40 -0
  59. data/lib/ably/realtime/channel/channel_state_machine.rb +104 -0
  60. data/lib/ably/realtime/channel/publisher.rb +82 -0
  61. data/lib/ably/realtime/channel/push_channel.rb +69 -0
  62. data/lib/ably/realtime/channel.rb +440 -0
  63. data/lib/ably/realtime/channels.rb +71 -0
  64. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +225 -0
  65. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +87 -0
  66. data/lib/ably/realtime/client.rb +363 -0
  67. data/lib/ably/realtime/connection/connection_manager.rb +594 -0
  68. data/lib/ably/realtime/connection/connection_state_machine.rb +144 -0
  69. data/lib/ably/realtime/connection/websocket_transport.rb +287 -0
  70. data/lib/ably/realtime/connection.rb +738 -0
  71. data/lib/ably/realtime/models/nil_channel.rb +30 -0
  72. data/lib/ably/realtime/presence/members_map.rb +395 -0
  73. data/lib/ably/realtime/presence/presence_manager.rb +78 -0
  74. data/lib/ably/realtime/presence/presence_state_machine.rb +57 -0
  75. data/lib/ably/realtime/presence.rb +502 -0
  76. data/lib/ably/realtime/push/admin.rb +75 -0
  77. data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  78. data/lib/ably/realtime/push/device_registrations.rb +105 -0
  79. data/lib/ably/realtime/push.rb +25 -0
  80. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  81. data/lib/ably/realtime.rb +60 -0
  82. data/lib/ably/rest/channel/push_channel.rb +59 -0
  83. data/lib/ably/rest/channel.rb +194 -0
  84. data/lib/ably/rest/channels.rb +47 -0
  85. data/lib/ably/rest/client.rb +727 -0
  86. data/lib/ably/rest/middleware/encoder.rb +49 -0
  87. data/lib/ably/rest/middleware/exceptions.rb +53 -0
  88. data/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  89. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +22 -0
  90. data/lib/ably/rest/middleware/logger.rb +58 -0
  91. data/lib/ably/rest/middleware/parse_json.rb +27 -0
  92. data/lib/ably/rest/middleware/parse_message_pack.rb +43 -0
  93. data/lib/ably/rest/presence.rb +113 -0
  94. data/lib/ably/rest/push/admin.rb +58 -0
  95. data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  96. data/lib/ably/rest/push/device_registrations.rb +114 -0
  97. data/lib/ably/rest/push.rb +25 -0
  98. data/lib/ably/rest.rb +40 -0
  99. data/lib/ably/util/ably_extensions.rb +29 -0
  100. data/lib/ably/util/crypto.rb +134 -0
  101. data/lib/ably/util/pub_sub.rb +45 -0
  102. data/lib/ably/util/safe_deferrable.rb +44 -0
  103. data/lib/ably/version.rb +7 -0
  104. data/lib/ably.rb +16 -0
  105. metadata +497 -0
@@ -0,0 +1,49 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Ably
5
+ module Rest
6
+ module Middleware
7
+ # Encode the body of the message according to the mime type
8
+ class Encoder < Faraday::Middleware
9
+ CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
10
+
11
+ def call(env)
12
+ encode env if env.body
13
+ @app.call env
14
+ end
15
+
16
+ private
17
+ def encode(env)
18
+ env.body = case request_type(env)
19
+ when 'application/x-msgpack'
20
+ to_msgpack(env.body)
21
+ when 'application/json', '', nil
22
+ env.request_headers[CONTENT_TYPE] = 'application/json'
23
+ to_json(env.body)
24
+ else
25
+ env.body
26
+ end
27
+ end
28
+
29
+ def to_msgpack(body)
30
+ body.to_msgpack
31
+ end
32
+
33
+ def to_json(body)
34
+ if body.kind_of?(String)
35
+ body
36
+ else
37
+ body.to_json
38
+ end
39
+ end
40
+
41
+ def request_type(env)
42
+ type = env.request_headers[CONTENT_TYPE].to_s
43
+ type = type.split(';', 2).first if type.index(';')
44
+ type
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,53 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Ably
5
+ module Rest
6
+ module Middleware
7
+ # HTTP exceptions raised by Ably due to an error status code
8
+ # Ably returns JSON/Msgpack error codes and messages so include this if possible in the exception messages
9
+ class Exceptions < Faraday::Middleware
10
+ def on_complete(env)
11
+ if env.status >= 400
12
+ error_status_code = env.status
13
+ error_code = nil
14
+
15
+ if env.body.kind_of?(Hash)
16
+ error = env.body.fetch('error', {})
17
+ error_status_code = error['statusCode'].to_i if error['statusCode']
18
+ error_code = error['code'].to_i if error['code']
19
+
20
+ if error
21
+ message = "#{error['message']} (status: #{error_status_code}, code: #{error_code})"
22
+ else
23
+ message = env.body
24
+ end
25
+ else
26
+ message = env.body
27
+ end
28
+
29
+ message = 'Unknown server error' if message.to_s.strip == ''
30
+ request_id = env.request.context[:request_id] if env.request.context
31
+ exception_args = [message, error_status_code, error_code, nil, { request_id: request_id }]
32
+
33
+ if env.status >= 500
34
+ raise Ably::Exceptions::ServerError.new(*exception_args)
35
+ elsif env.status == 401
36
+ if Ably::Exceptions::TOKEN_EXPIRED_CODE.include?(error_code)
37
+ raise Ably::Exceptions::TokenExpired.new(*exception_args)
38
+ else
39
+ raise Ably::Exceptions::UnauthorizedRequest.new(*exception_args)
40
+ end
41
+ elsif env.status == 403
42
+ raise Ably::Exceptions::ForbiddenRequest.new(*exception_args)
43
+ elsif env.status == 404
44
+ raise Ably::Exceptions::ResourceMissing.new(*exception_args)
45
+ else
46
+ raise Ably::Exceptions::InvalidRequest.new(*exception_args)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,24 @@
1
+ require 'faraday'
2
+
3
+ module Ably
4
+ module Rest
5
+ module Middleware
6
+ # HTTP exceptions raised due to a status code error on a 3rd party site
7
+ # Used by auth calls
8
+ class ExternalExceptions < Faraday::Middleware
9
+ def on_complete(env)
10
+ if env.status >= 400
11
+ error_status_code = env.status
12
+ message = "Error #{error_status_code}: #{(env.body || '')[0...200]}"
13
+
14
+ if error_status_code >= 500
15
+ raise Ably::Exceptions::ServerError, message
16
+ else
17
+ raise Ably::Exceptions::InvalidRequest, message
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Ably
5
+ module Rest
6
+ module Middleware
7
+ class FailIfUnsupportedMimeType < Faraday::Middleware
8
+ def on_complete(env)
9
+ unless env.response_headers['Ably-Middleware-Parsed'] == true
10
+ # Ignore empty body with success status code for no body response
11
+ return if env.body.to_s.empty? && env.status == 204
12
+
13
+ unless (500..599).include?(env.status)
14
+ raise Ably::Exceptions::InvalidResponseBody,
15
+ "Content Type #{env.response_headers['Content-Type']} is not supported by this client library"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ require 'faraday'
2
+
3
+ module Ably
4
+ module Rest
5
+ module Middleware
6
+ class Logger < Faraday::Middleware
7
+ extend Forwardable
8
+
9
+ def initialize(app, logger = nil)
10
+ super(app)
11
+ @logger = logger || begin
12
+ require 'logger'
13
+ ::Logger.new(STDOUT)
14
+ end
15
+ end
16
+
17
+ def_delegators :@logger, :debug, :info, :warn, :error, :fatal
18
+
19
+ def call(env)
20
+ debug { "=> URL: #{env.method} #{env.url}, Headers: #{dump_headers env.request_headers}" }
21
+ debug { "=> Body: #{body_for(env)}" }
22
+ super
23
+ end
24
+
25
+ def on_complete(env)
26
+ debug "<= Status: #{env.status}, Headers: #{dump_headers env.response_headers}"
27
+ debug "<= Body: #{body_for(env)}"
28
+ end
29
+
30
+ private
31
+ def dump_headers(headers)
32
+ headers.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
33
+ end
34
+
35
+ def body_for(env)
36
+ return '' if !env.body || env.body.empty?
37
+
38
+ if env.request_headers['Content-Type'] == 'application/x-msgpack'
39
+ MessagePack.unpack(env.body)
40
+ else
41
+ env.body
42
+ end
43
+
44
+ rescue StandardError
45
+ readable_body(env.body)
46
+ end
47
+
48
+ def readable_body(body)
49
+ if body.respond_to?(:encoding) && body.encoding == Encoding::ASCII_8BIT
50
+ body.unpack('H*')
51
+ else
52
+ body
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Ably
5
+ module Rest
6
+ module Middleware
7
+ class ParseJson < Faraday::Middleware
8
+ def on_complete(env)
9
+ if env.response_headers['Content-Type'] == 'application/json'
10
+ env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
11
+ env.response_headers['Ably-Middleware-Parsed'] = true
12
+ end
13
+ end
14
+
15
+ def parse(body)
16
+ if body.length > 0
17
+ JSON.parse(body)
18
+ else
19
+ body
20
+ end
21
+ rescue JSON::ParserError => e
22
+ raise Ably::Exceptions::InvalidResponseBody, "Expected JSON response: #{e.message}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ require 'faraday'
2
+ require 'msgpack'
3
+
4
+ module Ably
5
+ module Rest
6
+ module Middleware
7
+ class ParseMessagePack < Faraday::Middleware
8
+ def on_complete(env)
9
+ if env.response_headers['Content-Type'] == 'application/x-msgpack'
10
+ env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
11
+ env.response_headers['Ably-Middleware-Parsed'] = true
12
+ end
13
+ rescue Ably::Exceptions::InvalidResponseBody => e
14
+ debug_info = {
15
+ method: env.method,
16
+ url: env.url,
17
+ base64_body: base64_body(env.body),
18
+ response_headers: env.response_headers
19
+ }
20
+ raise Ably::Exceptions::InvalidResponseBody, "#{e.message}\nRequest env: #{debug_info}"
21
+ end
22
+
23
+ def parse(body)
24
+ if body.length > 0
25
+ MessagePack.unpack(body)
26
+ else
27
+ body
28
+ end
29
+ rescue MessagePack::UnknownExtTypeError => e
30
+ raise Ably::Exceptions::InvalidResponseBody, "MessagePack::UnknownExtTypeError body could not be decoded: #{e.message}. Got Base64:\n#{base64_body(body)}"
31
+ rescue MessagePack::MalformedFormatError => e
32
+ raise Ably::Exceptions::InvalidResponseBody, "MessagePack::MalformedFormatError body could not be decoded: #{e.message}. Got Base64:\n#{base64_body(body)}"
33
+ end
34
+
35
+ def base64_body(body)
36
+ Base64.encode64(body)
37
+ rescue => err
38
+ "[#{err.message}! Could not base64 encode body: '#{body}']"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,113 @@
1
+ module Ably
2
+ module Rest
3
+ # Enables the retrieval of the current and historic presence set for a channel.
4
+ #
5
+ class Presence
6
+ include Ably::Modules::Conversions
7
+
8
+ # {Ably::Rest::Client} for this Presence object
9
+ #
10
+ # @return {Ably::Rest::Client}
11
+ #
12
+ # @private
13
+ attr_reader :client
14
+
15
+ # {Ably::Rest::Channel} this Presence object is associated with
16
+ #
17
+ # @return [Ably::Rest::Channel]
18
+ #
19
+ attr_reader :channel
20
+
21
+ # Initialize a new Presence object
22
+ #
23
+ # @param client [Ably::Rest::Client]
24
+ # @param channel [Channel] The channel object
25
+ #
26
+ def initialize(client, channel)
27
+ @client = client
28
+ @channel = channel
29
+ end
30
+
31
+ # Retrieves the current members present on the channel and the metadata for each member, such as their
32
+ # {Ably::Models::PresenceMessage::ACTION} and ID. Returns a {Ably::Models::PaginatedResult} object,
33
+ # containing an array of {Ably::Models::PresenceMessage} objects.
34
+ #
35
+ # @spec RSPa, RSP3a, RSP3a2, RSP3a3
36
+ #
37
+ # @param [Hash] options the options for the set of members present
38
+ # @option options [Integer] :limit An upper limit on the number of messages returned. The default is 100, and the maximum is 1000. (RSP3a)
39
+ # @option options [String] :client_id Filters the list of returned presence members by a specific client using its ID. (RSP3a2)
40
+ # @option options [String] :connection_id Filters the list of returned presence members by a specific connection using its ID. (RSP3a3)
41
+ #
42
+ # @return [Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>] A {Ably::Models::PaginatedResult} object containing an array of {Ably::Models::PresenceMessage} objects.
43
+ #
44
+ def get(options = {})
45
+ options = options = {
46
+ :limit => 100
47
+ }.merge(options)
48
+
49
+ paginated_options = {
50
+ coerce_into: 'Ably::Models::PresenceMessage',
51
+ async_blocking_operations: options.delete(:async_blocking_operations),
52
+ }
53
+
54
+ response = client.get(base_path, options)
55
+
56
+ Ably::Models::PaginatedResult.new(response, base_path, client, paginated_options) do |presence_message|
57
+ presence_message.tap do |message|
58
+ decode_message message
59
+ end
60
+ end
61
+ end
62
+
63
+ # Retrieves a {Ably::Models::PaginatedResult} object, containing an array of historical {Ably::Models::PresenceMessage}
64
+ # objects for the channel. If the channel is configured to persist messages, then presence messages can be retrieved
65
+ # from history for up to 72 hours in the past. If not, presence messages can only be retrieved from history for up to two minutes in the past.
66
+ #
67
+ # @spec RSP4a
68
+ #
69
+ # @param [Hash] options the options for the message history request
70
+ # @option options [Integer,Time] :start The time from which messages are retrieved, specified as milliseconds since the Unix epoch. (RSP4b1)
71
+ # @option options [Integer,Time] :end The time until messages are retrieved, specified as milliseconds since the Unix epoch. (RSP4b1)
72
+ # @option options [Symbol] :direction The order for which messages are returned in. Valid values are backwards which orders messages from most recent to oldest, or forwards which orders messages from oldest to most recent. The default is backwards. (RSP4b2)
73
+ # @option options [Integer] :limit An upper limit on the number of messages returned. The default is 100, and the maximum is 1000. (RSP4b3)
74
+ #
75
+ # @return [Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>] A {Ably::Models::PaginatedResult} object containing an array of {Ably::Models::PresenceMessage} objects.
76
+ #
77
+ def history(options = {})
78
+ url = "#{base_path}/history"
79
+ options = options = {
80
+ :direction => :backwards,
81
+ :limit => 100
82
+ }.merge(options)
83
+
84
+ [:start, :end].each { |option| options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
85
+ raise ArgumentError, ":end must be equal to or after :start" if options[:start] && options[:end] && (options[:start] > options[:end])
86
+
87
+ paginated_options = {
88
+ coerce_into: 'Ably::Models::PresenceMessage',
89
+ async_blocking_operations: options.delete(:async_blocking_operations),
90
+ }
91
+
92
+ response = client.get(url, options)
93
+
94
+ Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |presence_message|
95
+ presence_message.tap do |message|
96
+ decode_message message
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+ def base_path
103
+ "/channels/#{URI.encode_www_form_component(channel.name)}/presence"
104
+ end
105
+
106
+ def decode_message(presence_message)
107
+ presence_message.decode client.encoders, channel.options
108
+ rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
109
+ client.logger.error { "Decoding Error on presence channel '#{channel.name}', presence message client_id '#{presence_message.client_id}'. #{e.class.name}: #{e.message}" }
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,58 @@
1
+ require 'ably/rest/push/device_registrations'
2
+ require 'ably/rest/push/channel_subscriptions'
3
+
4
+ module Ably::Rest
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::Conversions
10
+
11
+ # @api private
12
+ attr_reader :client
13
+
14
+ # @api private
15
+ attr_reader :push
16
+
17
+ def initialize(push)
18
+ @push = push
19
+ @client = push.client
20
+ end
21
+
22
+ # Publish a push message directly to a single recipient
23
+ #
24
+ # @param recipient [Hash] A recipient device, client_id or raw APNS/FCM/web target. Refer to push documentation
25
+ # @param data [Hash] The notification payload data and fields. Refer to push documentation
26
+ #
27
+ # @return [void]
28
+ #
29
+ def publish(recipient, data)
30
+ raise ArgumentError, "Expecting a Hash object for recipient, got #{recipient.class}" unless recipient.kind_of?(Hash)
31
+ raise ArgumentError, "Recipient data is empty. You must provide recipient details" if recipient.empty?
32
+ raise ArgumentError, "Expecting a Hash object for data, got #{data.class}" unless data.kind_of?(Hash)
33
+ raise ArgumentError, "Push data field is empty. You must provide attributes for the push notification" if data.empty?
34
+
35
+ publish_data = data.merge(recipient: IdiomaticRubyWrapper(recipient))
36
+ # Co-erce to camelCase for notitication fields which are always camelCase
37
+ publish_data[:notification] = IdiomaticRubyWrapper(data[:notification]) if publish_data[:notification].kind_of?(Hash)
38
+ client.post('/push/publish', publish_data)
39
+ end
40
+
41
+ # Manage device registrations
42
+ #
43
+ # @return [Ably::Rest::Push::DeviceRegistrations]
44
+ #
45
+ def device_registrations
46
+ @device_registrations ||= DeviceRegistrations.new(self)
47
+ end
48
+
49
+ # Manage channel subscriptions for devices or clients
50
+ #
51
+ # @return [Ably::Rest::Push::ChannelSubscriptions]
52
+ #
53
+ def channel_subscriptions
54
+ @channel_subscriptions ||= ChannelSubscriptions.new(self)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,121 @@
1
+ module Ably::Rest
2
+ class Push
3
+ # Manage push notification channel subscriptions for devices or client identifiers
4
+ class ChannelSubscriptions
5
+ include Ably::Modules::Conversions
6
+
7
+ # @api private
8
+ attr_reader :client
9
+
10
+ # @api private
11
+ attr_reader :admin
12
+
13
+ def initialize(admin)
14
+ @admin = admin
15
+ @client = admin.client
16
+ end
17
+
18
+ # List channel subscriptions filtered by optional params
19
+ #
20
+ # @param [Hash] params the filter options for the list channel subscription request. At least one of channel, client_id or device_id is required
21
+ # @option params [String] :channel filter by realtime pub/sub channel name
22
+ # @option params [String] :client_id filter by devices registered to a client identifier. If provided with device_id param, a concat operation is used so that any device with this client_id or provided device_id is returned.
23
+ # @option params [String] :device_id filter by unique device ID. If provided with client_id param, a concat operation is used so that any device with this device_id or provided client_id is returned.
24
+ # @option params [Integer] :limit maximum number of subscriptions to retrieve up to 1,000, defaults to 100
25
+ #
26
+ # @return [Ably::Models::PaginatedResult<Ably::Models::PushChannelSubscription>] Paginated list of matching {Ably::Models::PushChannelSubscription}
27
+ #
28
+ def list(params)
29
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
30
+
31
+ if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
32
+ raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
33
+ end
34
+
35
+ params = params.clone
36
+
37
+ paginated_options = {
38
+ coerce_into: 'Ably::Models::PushChannelSubscription',
39
+ async_blocking_operations: params.delete(:async_blocking_operations),
40
+ }
41
+
42
+ response = client.get('/push/channelSubscriptions', IdiomaticRubyWrapper(params).as_json)
43
+
44
+ Ably::Models::PaginatedResult.new(response, '', client, paginated_options)
45
+ end
46
+
47
+ # List channels with at least one subscribed device
48
+ #
49
+ # @param [Hash] params the options for the list channels request
50
+ # @option params [Integer] :limit maximum number of channels to retrieve up to 1,000, defaults to 100
51
+ #
52
+ # @return [Ably::Models::PaginatedResult<String>] Paginated list of matching {Ably::Models::PushChannelSubscription}
53
+ #
54
+ def list_channels(params = {})
55
+ params = {} if params.nil?
56
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
57
+
58
+ params = params.clone
59
+
60
+ paginated_options = {
61
+ coerce_into: 'String',
62
+ async_blocking_operations: params.delete(:async_blocking_operations),
63
+ }
64
+
65
+ response = client.get('/push/channels', IdiomaticRubyWrapper(params).as_json)
66
+
67
+ Ably::Models::PaginatedResult.new(response, '', client, paginated_options)
68
+ end
69
+
70
+ # Save push channel subscription for a device or client ID
71
+ #
72
+ # @param [Ably::Models::PushChannelSubscription,Hash] push_channel_subscription the push channel subscription details to save
73
+ #
74
+ # @return [void]
75
+ #
76
+ def save(push_channel_subscription)
77
+ push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
78
+ raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
79
+
80
+ client.post("/push/channelSubscriptions", push_channel_subscription_object.as_json)
81
+ end
82
+
83
+ # Remove a push channel subscription
84
+ #
85
+ # @param [Ably::Models::PushChannelSubscription,Hash] push_channel_subscription the push channel subscription details to remove
86
+ #
87
+ # @return [void]
88
+ #
89
+ def remove(push_channel_subscription)
90
+ push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
91
+ raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
92
+ if push_channel_subscription_object.client_id.to_s.empty? && push_channel_subscription_object.device_id.to_s.empty?
93
+ raise ArgumentError, "Either client_id or device_id must be present"
94
+ end
95
+
96
+ client.delete("/push/channelSubscriptions", push_channel_subscription_object.as_json)
97
+ end
98
+
99
+ # Remove all matching push channel subscriptions
100
+ #
101
+ # @param [Hash] params the filter options for the list channel subscription request. At least one of channel, client_id or device_id is required
102
+ # @option params [String] :channel filter by realtime pub/sub channel name
103
+ # @option params [String] :client_id filter by devices registered to a client identifier. If provided with device_id param, a concat operation is used so that any device with this client_id or provided device_id is returned.
104
+ # @option params [String] :device_id filter by unique device ID. If provided with client_id param, a concat operation is used so that any device with this device_id or provided client_id is returned.
105
+ #
106
+ # @return [void]
107
+ #
108
+ def remove_where(params)
109
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
110
+
111
+ if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
112
+ raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
113
+ end
114
+
115
+ params = params.clone
116
+
117
+ client.delete("/push/channelSubscriptions", IdiomaticRubyWrapper(params).as_json)
118
+ end
119
+ end
120
+ end
121
+ end