ably-pubsub-core 0.0.1.pre → 2.0.0

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ably/auth.rb +5 -5
  3. data/lib/ably/exceptions.rb +5 -0
  4. data/lib/ably/internal.rb +115 -0
  5. data/lib/ably/logger.rb +3 -3
  6. data/lib/ably/models/channel_details.rb +1 -1
  7. data/lib/ably/models/channel_metrics.rb +1 -1
  8. data/lib/ably/models/channel_occupancy.rb +1 -1
  9. data/lib/ably/models/channel_state_change.rb +7 -7
  10. data/lib/ably/models/channel_status.rb +1 -1
  11. data/lib/ably/models/cipher_params.rb +1 -1
  12. data/lib/ably/models/connection_details.rb +2 -2
  13. data/lib/ably/models/connection_state_change.rb +6 -6
  14. data/lib/ably/models/http_paginated_response.rb +3 -3
  15. data/lib/ably/models/message.rb +69 -2
  16. data/lib/ably/models/message_operation.rb +53 -0
  17. data/lib/ably/models/paginated_result.rb +2 -2
  18. data/lib/ably/models/presence_message.rb +1 -1
  19. data/lib/ably/models/protocol_message.rb +14 -1
  20. data/lib/ably/models/publish_result.rb +32 -0
  21. data/lib/ably/models/stats.rb +41 -84
  22. data/lib/ably/models/update_delete_result.rb +32 -0
  23. data/lib/ably/modules/ably.rb +13 -12
  24. data/lib/ably/modules/channels_collection.rb +1 -1
  25. data/lib/ably/modules/http_helpers.rb +11 -11
  26. data/lib/ably/{rest → pubsub/http}/channel/push_channel.rb +3 -3
  27. data/lib/ably/pubsub/http/channel.rb +284 -0
  28. data/lib/ably/pubsub/http/channels.rb +49 -0
  29. data/lib/ably/pubsub/http/client.rb +738 -0
  30. data/lib/ably/pubsub/http/middleware/encoder.rb +51 -0
  31. data/lib/ably/pubsub/http/middleware/exceptions.rb +55 -0
  32. data/lib/ably/pubsub/http/middleware/external_exceptions.rb +26 -0
  33. data/lib/ably/pubsub/http/middleware/fail_if_unsupported_mime_type.rb +24 -0
  34. data/lib/ably/pubsub/http/middleware/logger.rb +60 -0
  35. data/lib/ably/pubsub/http/middleware/parse_json.rb +29 -0
  36. data/lib/ably/pubsub/http/middleware/parse_message_pack.rb +45 -0
  37. data/lib/ably/pubsub/http/presence.rb +117 -0
  38. data/lib/ably/{rest → pubsub/http}/push/admin.rb +5 -5
  39. data/lib/ably/{rest → pubsub/http}/push/channel_subscriptions.rb +1 -1
  40. data/lib/ably/{rest → pubsub/http}/push/device_registrations.rb +1 -1
  41. data/lib/ably/pubsub/http/push.rb +27 -0
  42. data/lib/ably/pubsub/http.rb +38 -0
  43. data/lib/ably/pubsub/realtime/auth.rb +285 -0
  44. data/lib/ably/{realtime → pubsub/realtime}/channel/channel_manager.rb +2 -2
  45. data/lib/ably/{realtime → pubsub/realtime}/channel/channel_properties.rb +5 -5
  46. data/lib/ably/{realtime → pubsub/realtime}/channel/channel_state_machine.rb +2 -2
  47. data/lib/ably/{realtime → pubsub/realtime}/channel/publisher.rb +9 -4
  48. data/lib/ably/{realtime → pubsub/realtime}/channel/push_channel.rb +2 -2
  49. data/lib/ably/pubsub/realtime/channel.rb +545 -0
  50. data/lib/ably/pubsub/realtime/channels.rb +92 -0
  51. data/lib/ably/{realtime → pubsub/realtime}/client/incoming_message_dispatcher.rb +43 -8
  52. data/lib/ably/{realtime → pubsub/realtime}/client/outgoing_message_dispatcher.rb +2 -2
  53. data/lib/ably/pubsub/realtime/client.rb +372 -0
  54. data/lib/ably/{realtime → pubsub/realtime}/connection/connection_manager.rb +6 -6
  55. data/lib/ably/{realtime → pubsub/realtime}/connection/connection_state_machine.rb +2 -2
  56. data/lib/ably/{realtime → pubsub/realtime}/connection/websocket_transport.rb +1 -1
  57. data/lib/ably/pubsub/realtime/connection.rb +724 -0
  58. data/lib/ably/{realtime → pubsub/realtime}/models/nil_channel.rb +3 -3
  59. data/lib/ably/{realtime → pubsub/realtime}/presence/members_map.rb +2 -2
  60. data/lib/ably/{realtime → pubsub/realtime}/presence/presence_manager.rb +3 -3
  61. data/lib/ably/{realtime → pubsub/realtime}/presence/presence_state_machine.rb +2 -2
  62. data/lib/ably/{realtime → pubsub/realtime}/presence.rb +23 -23
  63. data/lib/ably/{realtime → pubsub/realtime}/push/admin.rb +8 -8
  64. data/lib/ably/{realtime → pubsub/realtime}/push/channel_subscriptions.rb +6 -6
  65. data/lib/ably/{realtime → pubsub/realtime}/push/device_registrations.rb +6 -6
  66. data/lib/ably/pubsub/realtime/push.rb +27 -0
  67. data/lib/ably/pubsub/realtime/recovery_key_context.rb +38 -0
  68. data/lib/ably/pubsub/realtime.rb +58 -0
  69. data/lib/ably/pubsub.rb +11 -0
  70. data/lib/ably/version.rb +2 -2
  71. data/lib/ably.rb +6 -2
  72. metadata +50 -46
  73. data/lib/ably/models/stats_types.rb +0 -107
  74. data/lib/ably/realtime/auth.rb +0 -283
  75. data/lib/ably/realtime/channel.rb +0 -440
  76. data/lib/ably/realtime/channels.rb +0 -71
  77. data/lib/ably/realtime/client.rb +0 -363
  78. data/lib/ably/realtime/connection.rb +0 -738
  79. data/lib/ably/realtime/push.rb +0 -25
  80. data/lib/ably/realtime/recovery_key_context.rb +0 -36
  81. data/lib/ably/realtime.rb +0 -60
  82. data/lib/ably/rest/channel.rb +0 -194
  83. data/lib/ably/rest/channels.rb +0 -47
  84. data/lib/ably/rest/client.rb +0 -727
  85. data/lib/ably/rest/middleware/encoder.rb +0 -49
  86. data/lib/ably/rest/middleware/exceptions.rb +0 -53
  87. data/lib/ably/rest/middleware/external_exceptions.rb +0 -24
  88. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +0 -22
  89. data/lib/ably/rest/middleware/logger.rb +0 -58
  90. data/lib/ably/rest/middleware/parse_json.rb +0 -27
  91. data/lib/ably/rest/middleware/parse_message_pack.rb +0 -43
  92. data/lib/ably/rest/presence.rb +0 -113
  93. data/lib/ably/rest/push.rb +0 -25
  94. data/lib/ably/rest.rb +0 -40
@@ -0,0 +1,285 @@
1
+ require 'ably/auth'
2
+
3
+ module Ably
4
+ module PubSub
5
+ module Realtime
6
+ # Auth is responsible for authentication with {https://www.ably.com Ably} using basic or token authentication
7
+ # This {Ably::PubSub::Realtime::Auth Realtime::Auth} class wraps the {Ably::Auth Synchronous Ably::Auth} class in an EventMachine friendly way using Deferrables for all IO. See {Ably::Auth Ably::Auth} for more information
8
+ #
9
+ # Find out more about Ably authentication at: https://www.ably.com/docs/general/authentication/
10
+ #
11
+ # @!attribute [r] client_id
12
+ # (see Ably::Auth#client_id)
13
+ # @!attribute [r] current_token_details
14
+ # (see Ably::Auth#current_token_details)
15
+ # @!attribute [r] token
16
+ # (see Ably::Auth#token)
17
+ # @!attribute [r] key
18
+ # (see Ably::Auth#key)
19
+ # @!attribute [r] key_name
20
+ # (see Ably::Auth#key_name)
21
+ # @!attribute [r] key_secret
22
+ # (see Ably::Auth#key_secret)
23
+ # @!attribute [r] options
24
+ # (see Ably::Auth#options)
25
+ # @!attribute [r] token_params
26
+ # (see Ably::Auth#options)
27
+ # @!attribute [r] using_basic_auth?
28
+ # (see Ably::Auth#using_basic_auth?)
29
+ # @!attribute [r] using_token_auth?
30
+ # (see Ably::Auth#using_token_auth?)
31
+ # @!attribute [r] token_renewable?
32
+ # (see Ably::Auth#token_renewable?)
33
+ # @!attribute [r] authentication_security_requirements_met?
34
+ # (see Ably::Auth#authentication_security_requirements_met?)
35
+ #
36
+ class Auth
37
+ extend Forwardable
38
+ include Ably::Modules::AsyncWrapper
39
+
40
+ def_delegators :auth_sync, :client_id
41
+ def_delegators :auth_sync, :token_client_id_allowed?, :configure_client_id, :client_id_validated?
42
+ def_delegators :auth_sync, :can_assume_client_id?, :has_client_id?
43
+ def_delegators :auth_sync, :current_token_details, :token
44
+ def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
45
+ def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
46
+ def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
47
+ def_delegators :client, :logger
48
+ def_delegators :client, :connection
49
+
50
+ def initialize(client)
51
+ @client = client
52
+ @auth_sync = client.rest_client.auth
53
+ end
54
+
55
+ # For new connections, ensures valid auth credentials are present for the library instance. This may rely on an already-known and valid token, and will obtain a new token if necessary.
56
+ # If a connection is already established, the connection will be upgraded with a new token
57
+ #
58
+ # In the event that a new token request is made, the provided options are used
59
+ #
60
+ # @param (see Ably::Auth#authorize)
61
+ # @option (see Ably::Auth#authorize)
62
+ #
63
+ # @return [Ably::Util::SafeDeferrable]
64
+ # @yield [Ably::Models::TokenDetails]
65
+ #
66
+ # @example
67
+ # # will issue a simple token request using basic auth
68
+ # client = Ably::PubSub::Server.create_realtime_client(key: 'key.id:secret')
69
+ # client.auth.authorize do |token_details|
70
+ # token_details #=> Ably::Models::TokenDetails
71
+ # end
72
+ #
73
+ def authorize(token_params = nil, auth_options = nil, &success_callback)
74
+ Ably::Util::SafeDeferrable.new(logger).tap do |authorize_method_deferrable|
75
+ # Wrap the sync authorize method and wait for the result from the deferrable
76
+ async_wrap do
77
+ authorize_sync(token_params, auth_options)
78
+ end.tap do |auth_operation|
79
+ # Authorize operation succeeded and we have a new token, now let's perform inline authentication
80
+ auth_operation.callback do |token|
81
+ case connection.state.to_sym
82
+ when :initialized, :disconnected, :suspended, :closed, :closing, :failed
83
+ connection.connect
84
+ when :connected
85
+ perform_inline_auth token
86
+ when :connecting
87
+ # Fail all current connection attempts and try again with the new token, see #RTC8b
88
+ connection.manager.release_and_establish_new_transport
89
+ else
90
+ logger.fatal { "Auth#authorize: unsupported state #{connection.state}" }
91
+ authorize_method_deferrable.fail Ably::Exceptions::InvalidState.new("Unsupported state #{connection.state} for Auth#authorize")
92
+ next
93
+ end
94
+
95
+ # Indicate success or failure based on response from realtime, see #RTC8b1
96
+ auth_deferrable_resolved = false
97
+
98
+ connection.unsafe_once(:connected, :update) do
99
+ auth_deferrable_resolved = true
100
+ authorize_method_deferrable.succeed token
101
+ end
102
+ connection.unsafe_once(:suspended, :closed, :failed) do |state_change|
103
+ auth_deferrable_resolved = true
104
+ authorize_method_deferrable.fail state_change.reason
105
+ end
106
+ end
107
+
108
+ # Authorize failed, likely due to auth_url or auth_callback failing
109
+ auth_operation.errback do |error|
110
+ client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
111
+ authorize_method_deferrable.fail error
112
+ end
113
+ end
114
+
115
+ # Call the block provided to this method upon success of this deferrable
116
+ authorize_method_deferrable.callback do |token|
117
+ yield token if block_given?
118
+ end
119
+ end
120
+ end
121
+
122
+ # @deprecated Use {#authorize} instead
123
+ def authorise(*args, &block)
124
+ logger.warn { "Auth#authorise is deprecated and will be removed in 1.0. Please use Auth#authorize instead" }
125
+ authorize(*args, &block)
126
+ end
127
+
128
+ # Synchronous version of {#authorize}. See {Ably::Auth#authorize} for method definition
129
+ # Please note that authorize_sync will however not upgrade the current connection's token as this requires
130
+ # an synchronous operation to send the new authentication details to Ably over a realtime connection
131
+ #
132
+ # @param (see Ably::Auth#authorize)
133
+ # @option (see Ably::Auth#authorize)
134
+ # @return [Ably::Models::TokenDetails]
135
+ #
136
+ def authorize_sync(token_params = nil, auth_options = nil)
137
+ @authorization_in_flight = true
138
+ auth_sync.authorize(token_params, auth_options)
139
+ ensure
140
+ @authorization_in_flight = false
141
+ end
142
+
143
+ # @api private
144
+ def authorization_in_flight?
145
+ @authorization_in_flight
146
+ end
147
+
148
+ # @deprecated Use {#authorize_sync} instead
149
+ def authorise_sync(*args)
150
+ logger.warn { "Auth#authorise_sync is deprecated and will be removed in 1.0. Please use Auth#authorize_sync instead" }
151
+ authorize_sync(*args)
152
+ end
153
+
154
+ # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
155
+ #
156
+ # @param (see Ably::Auth#request_token)
157
+ # @option (see Ably::Auth#request_token)
158
+ #
159
+ # @return [Ably::Util::SafeDeferrable]
160
+ # @yield [Ably::Models::TokenDetails]
161
+ #
162
+ # @example
163
+ # # simple token request using basic auth
164
+ # client = Ably::PubSub::Server.create_realtime_client(key: 'key.id:secret')
165
+ # client.auth.request_token do |token_details|
166
+ # token_details #=> Ably::Models::TokenDetails
167
+ # end
168
+ #
169
+ def request_token(token_params = {}, auth_options = {}, &success_callback)
170
+ async_wrap(success_callback) do
171
+ request_token_sync(token_params, auth_options)
172
+ end
173
+ end
174
+
175
+ # Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
176
+ # @param (see Ably::Auth#authorize)
177
+ # @option (see Ably::Auth#authorize)
178
+ # @return [Ably::Models::TokenDetails]
179
+ #
180
+ def request_token_sync(token_params = {}, auth_options = {})
181
+ auth_sync.request_token(token_params, auth_options)
182
+ end
183
+
184
+ # Creates and signs a token request that can then subsequently be used by any client to request a token
185
+ #
186
+ # @param (see Ably::Auth#create_token_request)
187
+ # @option (see Ably::Auth#create_token_request)
188
+ #
189
+ # @return [Ably::Util::SafeDeferrable]
190
+ # @yield [Models::TokenRequest]
191
+ #
192
+ # @example
193
+ # client.auth.create_token_request({ ttl: 3600 }, id: 'asd.asd') do |token_request|
194
+ # token_request #=> Ably::Models::TokenRequest
195
+ # end
196
+ def create_token_request(token_params = {}, auth_options = {}, &success_callback)
197
+ async_wrap(success_callback) do
198
+ create_token_request_sync(token_params, auth_options)
199
+ end
200
+ end
201
+
202
+ # Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
203
+ # @param (see Ably::Auth#authorize)
204
+ # @option (see Ably::Auth#authorize)
205
+ # @return [Ably::Models::TokenRequest]
206
+ #
207
+ def create_token_request_sync(token_params = {}, auth_options = {})
208
+ auth_sync.create_token_request(token_params, auth_options)
209
+ end
210
+
211
+ # Auth header string used in HTTP requests to Ably
212
+ # Will reauthorize implicitly if required and capable
213
+ #
214
+ # @return [Ably::Util::SafeDeferrable]
215
+ # @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
216
+ #
217
+ def auth_header(&success_callback)
218
+ async_wrap(success_callback) do
219
+ auth_header_sync
220
+ end
221
+ end
222
+
223
+ # Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
224
+ # @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
225
+ #
226
+ def auth_header_sync
227
+ auth_sync.auth_header
228
+ end
229
+
230
+ def client_id_for_request_sync
231
+ auth_sync.client_id_for_request
232
+ end
233
+
234
+ # Auth params used in URI endpoint for Realtime connections
235
+ # Will reauthorize implicitly if required and capable
236
+ #
237
+ # @return [Ably::Util::SafeDeferrable]
238
+ # @yield [Hash] Auth params for a new Realtime connection
239
+ #
240
+ def auth_params(&success_callback)
241
+ fail_callback = lambda do |error, deferrable|
242
+ logger.error { "Failed to authenticate: #{error}" }
243
+ if error.kind_of?(Ably::Exceptions::BaseAblyException)
244
+ # Use base exception if it exists carrying forward the status codes
245
+ deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
246
+ else
247
+ deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
248
+ end
249
+ end
250
+ async_wrap(success_callback, fail_callback) do
251
+ auth_params_sync
252
+ end
253
+ end
254
+
255
+ # Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
256
+ # @return [Hash] Auth params for a new Realtime connection
257
+ #
258
+ def auth_params_sync
259
+ auth_sync.auth_params
260
+ end
261
+
262
+ private
263
+ # The synchronous Auth class instanced by the HTTP client
264
+ # @return [Ably::Auth]
265
+ def auth_sync
266
+ @auth_sync
267
+ end
268
+
269
+ def client
270
+ @client
271
+ end
272
+
273
+ # Sends an AUTH ProtocolMessage on the existing connection triggering
274
+ # an inline AUTH process, see #RTC8a
275
+ def perform_inline_auth(token)
276
+ logger.debug { "Performing inline AUTH with Ably using token #{token}" }
277
+ connection.send_protocol_message(
278
+ action: Ably::Models::ProtocolMessage::ACTION.Auth.to_i,
279
+ auth: { access_token: token.token }
280
+ )
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
@@ -1,4 +1,4 @@
1
- module Ably::Realtime
1
+ module Ably::PubSub::Realtime
2
2
  class Channel
3
3
  # ChannelManager is responsible for all actions relating to channel state: attaching, detaching or failure
4
4
  # Channel state changes are performed by this class and executed from {ChannelStateMachine}
@@ -71,7 +71,7 @@ module Ably::Realtime
71
71
  channel.emit :update, Ably::Models::ChannelStateChange.new(
72
72
  current: channel.state,
73
73
  previous: channel.state,
74
- event: Ably::Realtime::Channel::EVENT(:update),
74
+ event: Ably::PubSub::Realtime::Channel::EVENT(:update),
75
75
  reason: protocol_message.error,
76
76
  resumed: false,
77
77
  )
@@ -1,16 +1,16 @@
1
- module Ably::Realtime
1
+ module Ably::PubSub::Realtime
2
2
  class Channel
3
3
  # Describes the properties of the channel state.
4
4
  class ChannelProperties
5
- # {Ably::Realtime::Channel} this object associated with
5
+ # {Ably::PubSub::Realtime::Channel} this object associated with
6
6
  #
7
- # @return [Ably::Realtime::Channel]
7
+ # @return [Ably::PubSub::Realtime::Channel]
8
8
  #
9
9
  attr_reader :channel
10
10
 
11
11
  # Starts unset when a channel is instantiated, then updated with the channelSerial from each
12
- # {Ably::Realtime::Channel::STATE.Attached} event that matches the channel.
13
- # Used as the value for {Ably::Realtime::Channel#history}.
12
+ # {Ably::PubSub::Realtime::Channel::STATE.Attached} event that matches the channel.
13
+ # Used as the value for {Ably::PubSub::Realtime::Channel#history}.
14
14
  #
15
15
  # @spec CP2a
16
16
  #
@@ -1,8 +1,8 @@
1
1
  require 'ably/modules/state_machine'
2
2
 
3
- module Ably::Realtime
3
+ module Ably::PubSub::Realtime
4
4
  class Channel
5
- # Internal class to manage channel state for {Ably::Realtime::Channel}
5
+ # Internal class to manage channel state for {Ably::PubSub::Realtime::Channel}
6
6
  #
7
7
  # @api private
8
8
  #
@@ -1,4 +1,4 @@
1
- module Ably::Realtime
1
+ module Ably::PubSub::Realtime
2
2
  class Channel
3
3
  # Publisher module adds publishing capabilities to the current object
4
4
  module Publisher
@@ -52,13 +52,18 @@ module Ably::Realtime
52
52
  expected_deliveries = messages.count
53
53
  actual_deliveries = 0
54
54
  failed = false
55
+ results = Array.new(messages.count)
55
56
 
56
57
  Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
57
- messages.each do |message|
58
- message.callback do
58
+ messages.each_with_index do |message, index|
59
+ message.callback do |result|
59
60
  next if failed
61
+ results[index] = result
60
62
  actual_deliveries += 1
61
- deferrable.succeed messages if actual_deliveries == expected_deliveries
63
+ if actual_deliveries == expected_deliveries
64
+ all_serials = results.flat_map(&:serials)
65
+ deferrable.succeed Ably::Models::PublishResult.new(serials: all_serials)
66
+ end
62
67
  end
63
68
  message.errback do |error|
64
69
  next if failed
@@ -1,4 +1,4 @@
1
- module Ably::Realtime
1
+ module Ably::PubSub::Realtime
2
2
  class Channel
3
3
  # Enables devices to subscribe to push notifications for a channel.
4
4
  #
@@ -6,7 +6,7 @@ module Ably::Realtime
6
6
  attr_reader :channel
7
7
 
8
8
  def initialize(channel)
9
- raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::Realtime::Channel)
9
+ raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::PubSub::Realtime::Channel)
10
10
  @channel = channel
11
11
  end
12
12