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.
- checksums.yaml +4 -4
- data/lib/ably/auth.rb +5 -5
- data/lib/ably/exceptions.rb +5 -0
- data/lib/ably/internal.rb +115 -0
- data/lib/ably/logger.rb +3 -3
- data/lib/ably/models/channel_details.rb +1 -1
- data/lib/ably/models/channel_metrics.rb +1 -1
- data/lib/ably/models/channel_occupancy.rb +1 -1
- data/lib/ably/models/channel_state_change.rb +7 -7
- data/lib/ably/models/channel_status.rb +1 -1
- data/lib/ably/models/cipher_params.rb +1 -1
- data/lib/ably/models/connection_details.rb +2 -2
- data/lib/ably/models/connection_state_change.rb +6 -6
- data/lib/ably/models/http_paginated_response.rb +3 -3
- data/lib/ably/models/message.rb +69 -2
- data/lib/ably/models/message_operation.rb +53 -0
- data/lib/ably/models/paginated_result.rb +2 -2
- data/lib/ably/models/presence_message.rb +1 -1
- data/lib/ably/models/protocol_message.rb +14 -1
- data/lib/ably/models/publish_result.rb +32 -0
- data/lib/ably/models/stats.rb +41 -84
- data/lib/ably/models/update_delete_result.rb +32 -0
- data/lib/ably/modules/ably.rb +13 -12
- data/lib/ably/modules/channels_collection.rb +1 -1
- data/lib/ably/modules/http_helpers.rb +11 -11
- data/lib/ably/{rest → pubsub/http}/channel/push_channel.rb +3 -3
- data/lib/ably/pubsub/http/channel.rb +284 -0
- data/lib/ably/pubsub/http/channels.rb +49 -0
- data/lib/ably/pubsub/http/client.rb +738 -0
- data/lib/ably/pubsub/http/middleware/encoder.rb +51 -0
- data/lib/ably/pubsub/http/middleware/exceptions.rb +55 -0
- data/lib/ably/pubsub/http/middleware/external_exceptions.rb +26 -0
- data/lib/ably/pubsub/http/middleware/fail_if_unsupported_mime_type.rb +24 -0
- data/lib/ably/pubsub/http/middleware/logger.rb +60 -0
- data/lib/ably/pubsub/http/middleware/parse_json.rb +29 -0
- data/lib/ably/pubsub/http/middleware/parse_message_pack.rb +45 -0
- data/lib/ably/pubsub/http/presence.rb +117 -0
- data/lib/ably/{rest → pubsub/http}/push/admin.rb +5 -5
- data/lib/ably/{rest → pubsub/http}/push/channel_subscriptions.rb +1 -1
- data/lib/ably/{rest → pubsub/http}/push/device_registrations.rb +1 -1
- data/lib/ably/pubsub/http/push.rb +27 -0
- data/lib/ably/pubsub/http.rb +38 -0
- data/lib/ably/pubsub/realtime/auth.rb +285 -0
- data/lib/ably/{realtime → pubsub/realtime}/channel/channel_manager.rb +2 -2
- data/lib/ably/{realtime → pubsub/realtime}/channel/channel_properties.rb +5 -5
- data/lib/ably/{realtime → pubsub/realtime}/channel/channel_state_machine.rb +2 -2
- data/lib/ably/{realtime → pubsub/realtime}/channel/publisher.rb +9 -4
- data/lib/ably/{realtime → pubsub/realtime}/channel/push_channel.rb +2 -2
- data/lib/ably/pubsub/realtime/channel.rb +545 -0
- data/lib/ably/pubsub/realtime/channels.rb +92 -0
- data/lib/ably/{realtime → pubsub/realtime}/client/incoming_message_dispatcher.rb +43 -8
- data/lib/ably/{realtime → pubsub/realtime}/client/outgoing_message_dispatcher.rb +2 -2
- data/lib/ably/pubsub/realtime/client.rb +372 -0
- data/lib/ably/{realtime → pubsub/realtime}/connection/connection_manager.rb +6 -6
- data/lib/ably/{realtime → pubsub/realtime}/connection/connection_state_machine.rb +2 -2
- data/lib/ably/{realtime → pubsub/realtime}/connection/websocket_transport.rb +1 -1
- data/lib/ably/pubsub/realtime/connection.rb +724 -0
- data/lib/ably/{realtime → pubsub/realtime}/models/nil_channel.rb +3 -3
- data/lib/ably/{realtime → pubsub/realtime}/presence/members_map.rb +2 -2
- data/lib/ably/{realtime → pubsub/realtime}/presence/presence_manager.rb +3 -3
- data/lib/ably/{realtime → pubsub/realtime}/presence/presence_state_machine.rb +2 -2
- data/lib/ably/{realtime → pubsub/realtime}/presence.rb +23 -23
- data/lib/ably/{realtime → pubsub/realtime}/push/admin.rb +8 -8
- data/lib/ably/{realtime → pubsub/realtime}/push/channel_subscriptions.rb +6 -6
- data/lib/ably/{realtime → pubsub/realtime}/push/device_registrations.rb +6 -6
- data/lib/ably/pubsub/realtime/push.rb +27 -0
- data/lib/ably/pubsub/realtime/recovery_key_context.rb +38 -0
- data/lib/ably/pubsub/realtime.rb +58 -0
- data/lib/ably/pubsub.rb +11 -0
- data/lib/ably/version.rb +2 -2
- data/lib/ably.rb +6 -2
- metadata +50 -46
- data/lib/ably/models/stats_types.rb +0 -107
- data/lib/ably/realtime/auth.rb +0 -283
- data/lib/ably/realtime/channel.rb +0 -440
- data/lib/ably/realtime/channels.rb +0 -71
- data/lib/ably/realtime/client.rb +0 -363
- data/lib/ably/realtime/connection.rb +0 -738
- data/lib/ably/realtime/push.rb +0 -25
- data/lib/ably/realtime/recovery_key_context.rb +0 -36
- data/lib/ably/realtime.rb +0 -60
- data/lib/ably/rest/channel.rb +0 -194
- data/lib/ably/rest/channels.rb +0 -47
- data/lib/ably/rest/client.rb +0 -727
- data/lib/ably/rest/middleware/encoder.rb +0 -49
- data/lib/ably/rest/middleware/exceptions.rb +0 -53
- data/lib/ably/rest/middleware/external_exceptions.rb +0 -24
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +0 -22
- data/lib/ably/rest/middleware/logger.rb +0 -58
- data/lib/ably/rest/middleware/parse_json.rb +0 -27
- data/lib/ably/rest/middleware/parse_message_pack.rb +0 -43
- data/lib/ably/rest/presence.rb +0 -113
- data/lib/ably/rest/push.rb +0 -25
- data/lib/ably/rest.rb +0 -40
data/lib/ably/models/stats.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'ably/models/stats_types'
|
|
2
|
-
|
|
3
1
|
module Ably::Models
|
|
4
2
|
# Convert stat argument to a {Stats} object
|
|
5
3
|
#
|
|
@@ -17,16 +15,15 @@ module Ably::Models
|
|
|
17
15
|
|
|
18
16
|
# A class representing an individual statistic for a specified {#interval_id}
|
|
19
17
|
#
|
|
18
|
+
# @spec TS12
|
|
19
|
+
#
|
|
20
20
|
class Stats
|
|
21
21
|
include Ably::Modules::ModelCommon
|
|
22
22
|
extend Ably::Modules::Enum
|
|
23
23
|
|
|
24
24
|
# Describes the interval unit over which statistics are gathered.
|
|
25
25
|
#
|
|
26
|
-
#
|
|
27
|
-
# HOUR Interval unit over which statistics are gathered as hours.
|
|
28
|
-
# DAY Interval unit over which statistics are gathered as days.
|
|
29
|
-
# MONTH Interval unit over which statistics are gathered as months.
|
|
26
|
+
# @spec TS12c
|
|
30
27
|
#
|
|
31
28
|
GRANULARITY = ruby_enum('GRANULARITY',
|
|
32
29
|
:minute,
|
|
@@ -103,123 +100,83 @@ module Ably::Models
|
|
|
103
100
|
|
|
104
101
|
# {Stats} initializer
|
|
105
102
|
#
|
|
106
|
-
# @param hash_object
|
|
103
|
+
# @param hash_object [Hash] object with the underlying stat details
|
|
107
104
|
#
|
|
108
105
|
def initialize(hash_object)
|
|
109
|
-
@raw_hash_object
|
|
106
|
+
@raw_hash_object = hash_object
|
|
110
107
|
set_attributes_object hash_object
|
|
111
108
|
end
|
|
112
109
|
|
|
113
|
-
#
|
|
110
|
+
# The interval ID for this stats object.
|
|
114
111
|
#
|
|
115
|
-
# @spec
|
|
116
|
-
#
|
|
117
|
-
# @return [Stats::MessageTypes]
|
|
118
|
-
#
|
|
119
|
-
def all
|
|
120
|
-
@all ||= Stats::MessageTypes.new(attributes[:all])
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# A {Ably::Models::Stats::MessageTraffic} object containing the aggregate count of inbound message stats.
|
|
124
|
-
#
|
|
125
|
-
# @spec TS12f
|
|
126
|
-
#
|
|
127
|
-
# @return [Ably::Models::Stats::MessageTraffic]
|
|
128
|
-
#
|
|
129
|
-
def inbound
|
|
130
|
-
@inbound ||= Stats::MessageTraffic.new(attributes[:inbound])
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# A {Ably::Models::Stats::MessageTraffic} object containing the aggregate count of outbound message stats.
|
|
134
|
-
#
|
|
135
|
-
# @spec TS12g
|
|
136
|
-
#
|
|
137
|
-
# @return [Ably::Models::Stats::MessageTraffic]
|
|
138
|
-
#
|
|
139
|
-
def outbound
|
|
140
|
-
@outbound ||= Stats::MessageTraffic.new(attributes[:outbound])
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# A {Ably::Models::Stats::MessageTraffic} object containing the aggregate count of persisted message stats.
|
|
144
|
-
#
|
|
145
|
-
# @spec TS12h
|
|
112
|
+
# @spec TS12a
|
|
146
113
|
#
|
|
147
|
-
# @return [
|
|
114
|
+
# @return [String]
|
|
148
115
|
#
|
|
149
|
-
def
|
|
150
|
-
|
|
116
|
+
def interval_id
|
|
117
|
+
attributes.fetch(:interval_id)
|
|
151
118
|
end
|
|
152
119
|
|
|
153
|
-
#
|
|
120
|
+
# Represents the intervalId as a time object.
|
|
154
121
|
#
|
|
155
|
-
# @spec
|
|
122
|
+
# @spec TS12p
|
|
156
123
|
#
|
|
157
|
-
# @return [
|
|
124
|
+
# @return [Time]
|
|
158
125
|
#
|
|
159
|
-
def
|
|
160
|
-
|
|
126
|
+
def interval_time
|
|
127
|
+
self.class.from_interval_id(interval_id)
|
|
161
128
|
end
|
|
162
129
|
|
|
163
|
-
#
|
|
130
|
+
# The unit of the interval, as provided by the API response.
|
|
164
131
|
#
|
|
165
|
-
# @spec
|
|
132
|
+
# @spec TS12c
|
|
166
133
|
#
|
|
167
|
-
# @return [
|
|
134
|
+
# @return [String]
|
|
168
135
|
#
|
|
169
|
-
def
|
|
170
|
-
|
|
136
|
+
def unit
|
|
137
|
+
attributes[:unit]
|
|
171
138
|
end
|
|
172
139
|
|
|
173
|
-
#
|
|
140
|
+
# For entries that are still in progress, the last sub-interval included.
|
|
174
141
|
#
|
|
175
|
-
# @spec
|
|
142
|
+
# @spec TS12q
|
|
176
143
|
#
|
|
177
|
-
# @return [
|
|
144
|
+
# @return [String, nil]
|
|
178
145
|
#
|
|
179
|
-
def
|
|
180
|
-
|
|
146
|
+
def in_progress
|
|
147
|
+
attributes[:in_progress]
|
|
181
148
|
end
|
|
182
149
|
|
|
183
|
-
# A
|
|
150
|
+
# A flat dictionary of statistics entries with dot-separated keys.
|
|
184
151
|
#
|
|
185
|
-
# @spec
|
|
152
|
+
# @spec TS12r
|
|
186
153
|
#
|
|
187
|
-
# @return [
|
|
154
|
+
# @return [Hash]
|
|
188
155
|
#
|
|
189
|
-
def
|
|
190
|
-
|
|
156
|
+
def entries
|
|
157
|
+
raw_entries = raw_hash_object[:entries] || raw_hash_object['entries']
|
|
158
|
+
return {} unless raw_entries
|
|
159
|
+
raw_entries.is_a?(Hash) ? raw_entries : {}
|
|
191
160
|
end
|
|
192
161
|
|
|
193
|
-
# The
|
|
194
|
-
# the format YYYY-mm-dd:HH:MM, if hour it will be YYYY-mm-dd:HH, if day it will be YYYY-mm-dd:00
|
|
195
|
-
# and if month it will be YYYY-mm-01:00.
|
|
162
|
+
# The JSON schema URI for this stats object.
|
|
196
163
|
#
|
|
197
|
-
# @spec
|
|
164
|
+
# @spec TS12s
|
|
198
165
|
#
|
|
199
166
|
# @return [String]
|
|
200
167
|
#
|
|
201
|
-
def
|
|
202
|
-
attributes
|
|
168
|
+
def schema
|
|
169
|
+
attributes[:schema]
|
|
203
170
|
end
|
|
204
171
|
|
|
205
|
-
#
|
|
172
|
+
# The Ably application ID this stats object relates to.
|
|
206
173
|
#
|
|
207
|
-
# @spec
|
|
174
|
+
# @spec TS12t
|
|
208
175
|
#
|
|
209
|
-
# @return [
|
|
210
|
-
#
|
|
211
|
-
def interval_time
|
|
212
|
-
self.class.from_interval_id(interval_id)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
# The length of the interval the stats span. Values will be a [StatsIntervalGranularity]{@link StatsIntervalGranularity}.
|
|
216
|
-
#
|
|
217
|
-
# @spec TS12c
|
|
218
|
-
#
|
|
219
|
-
# @return [GRANULARITY] The granularity of the interval for the stat such as :day, :hour, :minute, see {GRANULARITY}
|
|
176
|
+
# @return [String]
|
|
220
177
|
#
|
|
221
|
-
def
|
|
222
|
-
|
|
178
|
+
def app_id
|
|
179
|
+
attributes[:app_id]
|
|
223
180
|
end
|
|
224
181
|
|
|
225
182
|
def attributes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
# Contains the result of an update or delete message operation.
|
|
3
|
+
#
|
|
4
|
+
# @spec UDR
|
|
5
|
+
#
|
|
6
|
+
class UpdateDeleteResult
|
|
7
|
+
include Ably::Modules::ModelCommon
|
|
8
|
+
|
|
9
|
+
# @param attributes [Hash]
|
|
10
|
+
# @option attributes [String, nil] :version_serial The new version serial string of the updated or deleted message.
|
|
11
|
+
# Will be nil if the message was superseded by a subsequent update before it could be published.
|
|
12
|
+
#
|
|
13
|
+
def initialize(attributes = {})
|
|
14
|
+
@hash_object = IdiomaticRubyWrapper(attributes || {})
|
|
15
|
+
@hash_object.freeze
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The version serial of the updated or deleted message, or nil if superseded.
|
|
19
|
+
#
|
|
20
|
+
# @spec UDR2a
|
|
21
|
+
#
|
|
22
|
+
# @return [String, nil]
|
|
23
|
+
#
|
|
24
|
+
def version_serial
|
|
25
|
+
attributes[:version_serial]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def attributes
|
|
29
|
+
@hash_object
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/ably/modules/ably.rb
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
# Ably is the base namespace for the Ably {Ably::Realtime Realtime} & {Ably::
|
|
1
|
+
# Ably is the base namespace for the Ably {Ably::PubSub::Realtime Realtime} & {Ably::PubSub::Http Rest} client libraries.
|
|
2
2
|
#
|
|
3
3
|
# Please refer to the {file:README.md Readme} on getting started.
|
|
4
4
|
#
|
|
5
5
|
# @see file:README.md README
|
|
6
6
|
module Ably
|
|
7
|
-
#
|
|
8
|
-
#
|
|
7
|
+
# Default routing policy used when the +:endpoint+ client option is not provided
|
|
8
|
+
# @spec REC1a
|
|
9
|
+
ENDPOINT = 'main'.freeze
|
|
10
|
+
|
|
11
|
+
PROD_ROOT_DOMAIN = 'ably.net'.freeze
|
|
12
|
+
PROD_FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
|
13
|
+
|
|
14
|
+
# Fallback hosts are used when a connection to the primary domain is not possible due to
|
|
15
|
+
# network failures either at the client, between the client and Ably, within an Ably data center, or at the domain registrar
|
|
9
16
|
# see https://ably.com/docs/client-lib-development-guide/features/#RSC15a
|
|
10
|
-
#
|
|
11
|
-
FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
|
12
17
|
FALLBACK_IDS = %w(a b c d e).freeze
|
|
13
18
|
|
|
14
|
-
# Default production fallbacks a.ably-realtime.com ... e.ably-realtime.com
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Custom environment default fallbacks {ENV}-a-fallback.ably-realtime.com ... {ENV}-a-fallback.ably-realtime.com
|
|
18
|
-
CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES = FALLBACK_IDS.map do |host|
|
|
19
|
-
"-#{host}-fallback.#{FALLBACK_DOMAIN}".freeze
|
|
20
|
-
end.freeze
|
|
19
|
+
# Default production fallbacks main.a.fallback.ably-realtime.com ... main.e.fallback.ably-realtime.com
|
|
20
|
+
# @spec REC2c1
|
|
21
|
+
FALLBACK_HOSTS = FALLBACK_IDS.map { |id| "#{ENDPOINT}.#{id}.fallback.#{PROD_FALLBACK_DOMAIN}".freeze }.freeze
|
|
21
22
|
|
|
22
23
|
INTERNET_CHECK = {
|
|
23
24
|
url: '//internet-up.ably-realtime.com/is-the-internet-up.txt',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Ably::Modules
|
|
2
|
-
# ChannelsCollection module provides common functionality to the
|
|
2
|
+
# ChannelsCollection module provides common functionality to the HTTP and Realtime Channels objects
|
|
3
3
|
# such as #get, #[], #fetch, and #release
|
|
4
4
|
module ChannelsCollection
|
|
5
5
|
include Enumerable
|
|
@@ -2,12 +2,12 @@ require 'base64'
|
|
|
2
2
|
|
|
3
3
|
require 'ably/version'
|
|
4
4
|
|
|
5
|
-
require 'ably/
|
|
6
|
-
require 'ably/
|
|
7
|
-
require 'ably/
|
|
8
|
-
require 'ably/
|
|
9
|
-
require 'ably/
|
|
10
|
-
require 'ably/
|
|
5
|
+
require 'ably/pubsub/http/middleware/encoder'
|
|
6
|
+
require 'ably/pubsub/http/middleware/external_exceptions'
|
|
7
|
+
require 'ably/pubsub/http/middleware/fail_if_unsupported_mime_type'
|
|
8
|
+
require 'ably/pubsub/http/middleware/logger'
|
|
9
|
+
require 'ably/pubsub/http/middleware/parse_json'
|
|
10
|
+
require 'ably/pubsub/http/middleware/parse_message_pack'
|
|
11
11
|
|
|
12
12
|
module Ably::Modules
|
|
13
13
|
# HttpHelpers provides common private methods to classes to simplify HTTP interactions with Ably
|
|
@@ -23,19 +23,19 @@ module Ably::Modules
|
|
|
23
23
|
|
|
24
24
|
def setup_outgoing_middleware(builder)
|
|
25
25
|
# Convert request params to "www-form-urlencoded"
|
|
26
|
-
builder.use Ably::
|
|
26
|
+
builder.use Ably::PubSub::Http::Middleware::Encoder
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def setup_incoming_middleware(builder, logger, options = {})
|
|
30
|
-
builder.use Ably::
|
|
30
|
+
builder.use Ably::PubSub::Http::Middleware::Logger, logger
|
|
31
31
|
|
|
32
32
|
# Parse JSON / MsgPack response bodies. ParseJson must be first (default) parsing middleware
|
|
33
33
|
if options[:fail_if_unsupported_mime_type] == true
|
|
34
|
-
builder.use Ably::
|
|
34
|
+
builder.use Ably::PubSub::Http::Middleware::FailIfUnsupportedMimeType
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
builder.use Ably::
|
|
38
|
-
builder.use Ably::
|
|
37
|
+
builder.use Ably::PubSub::Http::Middleware::ParseJson
|
|
38
|
+
builder.use Ably::PubSub::Http::Middleware::ParseMessagePack
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
module Ably::
|
|
1
|
+
module Ably::PubSub::Http
|
|
2
2
|
class Channel
|
|
3
3
|
# A push channel used for push notifications
|
|
4
|
-
# Each PushChannel maps to exactly one
|
|
4
|
+
# Each PushChannel maps to exactly one HTTP Channel
|
|
5
5
|
#
|
|
6
6
|
class PushChannel
|
|
7
7
|
attr_reader :channel
|
|
8
8
|
|
|
9
9
|
def initialize(channel)
|
|
10
|
-
raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::
|
|
10
|
+
raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::PubSub::Http::Channel)
|
|
11
11
|
@channel = channel
|
|
12
12
|
end
|
|
13
13
|
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module PubSub
|
|
3
|
+
module Http
|
|
4
|
+
# Enables messages to be published and historic messages to be retrieved for a channel.
|
|
5
|
+
#
|
|
6
|
+
class Channel
|
|
7
|
+
include Ably::Modules::Conversions
|
|
8
|
+
|
|
9
|
+
# Ably client associated with this channel
|
|
10
|
+
# @return [Ably::PubSub::Realtime::Client]
|
|
11
|
+
# @api private
|
|
12
|
+
attr_reader :client
|
|
13
|
+
|
|
14
|
+
# The channel name.
|
|
15
|
+
# @return [String]
|
|
16
|
+
attr_reader :name
|
|
17
|
+
|
|
18
|
+
attr_reader :options
|
|
19
|
+
|
|
20
|
+
# A {Ably::PubSub::Http::Channel::PushChannel} object
|
|
21
|
+
# @spec RSH4
|
|
22
|
+
# @return [Ably::PubSub::Http::Channel::PushChannel]
|
|
23
|
+
# @api private
|
|
24
|
+
attr_reader :push
|
|
25
|
+
|
|
26
|
+
IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH = 9 # See spec RSL1k1
|
|
27
|
+
|
|
28
|
+
# Initialize a new Channel object
|
|
29
|
+
#
|
|
30
|
+
# @param client [Ably::PubSub::Http::Client]
|
|
31
|
+
# @param name [String] The name of the channel
|
|
32
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
33
|
+
#
|
|
34
|
+
def initialize(client, name, channel_options = {})
|
|
35
|
+
name = (ensure_utf_8 :name, name)
|
|
36
|
+
|
|
37
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
38
|
+
@client = client
|
|
39
|
+
@name = name
|
|
40
|
+
@push = PushChannel.new(self)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Publishes a message to the channel. A callback may optionally be passed in to this call to be notified of success or failure of the operation.
|
|
44
|
+
#
|
|
45
|
+
# @spec RSL1
|
|
46
|
+
#
|
|
47
|
+
# @param name [String, Array<Ably::Models::Message|Hash>, Ably::Models::Message, 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, or a single Ably::Model::Message object
|
|
48
|
+
# @param data [String, Array, Hash, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument, in which case an optional hash of query parameters
|
|
49
|
+
# @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 (Deprecated, will be removed in 2.0 in favour of constructing a Message object)
|
|
50
|
+
# @return [Ably::Models::PublishResult] A {Ably::Models::PublishResult} containing the serials of the published messages.
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# # Publish a single message with (name, data) form
|
|
54
|
+
# channel.publish 'click', { x: 1, y: 2 }
|
|
55
|
+
#
|
|
56
|
+
# # Publish a single message with single Hash form
|
|
57
|
+
# message = { name: 'click', data: { x: 1, y: 2 } }
|
|
58
|
+
# channel.publish message
|
|
59
|
+
#
|
|
60
|
+
# # Publish an array of message Hashes form
|
|
61
|
+
# messages = [
|
|
62
|
+
# { name: 'click', data: { x: 1, y: 2 } },
|
|
63
|
+
# { name: 'click', data: { x: 2, y: 3 } }
|
|
64
|
+
# ]
|
|
65
|
+
# channel.publish messages
|
|
66
|
+
#
|
|
67
|
+
# # Publish an array of Ably::Models::Message objects form
|
|
68
|
+
# messages = [
|
|
69
|
+
# Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
70
|
+
# Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
|
|
71
|
+
# ]
|
|
72
|
+
# channel.publish messages
|
|
73
|
+
#
|
|
74
|
+
# # Publish a single Ably::Models::Message object form
|
|
75
|
+
# message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
76
|
+
# channel.publish message
|
|
77
|
+
#
|
|
78
|
+
def publish(name, data = nil, attributes = {})
|
|
79
|
+
qs_params = nil
|
|
80
|
+
qs_params = data if name.kind_of?(Enumerable) || name.kind_of?(Ably::Models::Message)
|
|
81
|
+
|
|
82
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
|
83
|
+
|
|
84
|
+
if messages.sum(&:size) > (max_message_size = client.max_message_size || Ably::PubSub::Http::Client::MAX_MESSAGE_SIZE)
|
|
85
|
+
raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{max_message_size} bytes.")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
payload = messages.map do |message|
|
|
89
|
+
Ably::Models::Message(message.dup).tap do |msg|
|
|
90
|
+
msg.encode client.encoders, options
|
|
91
|
+
|
|
92
|
+
next if msg.client_id.nil?
|
|
93
|
+
if msg.client_id == '*'
|
|
94
|
+
raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
|
|
95
|
+
end
|
|
96
|
+
unless client.auth.can_assume_client_id?(msg.client_id)
|
|
97
|
+
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}'")
|
|
98
|
+
end
|
|
99
|
+
end.as_json
|
|
100
|
+
end.tap do |payload|
|
|
101
|
+
if client.idempotent_rest_publishing
|
|
102
|
+
# We cannot mutate for idempotent publishing if one or more messages already has an ID
|
|
103
|
+
if payload.all? { |msg| !msg['id'] }
|
|
104
|
+
# Mutate the JSON to support idempotent publishing where a Message.id does not exist
|
|
105
|
+
idempotent_publish_id = SecureRandom.base64(IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH)
|
|
106
|
+
payload.each_with_index do |msg, idx|
|
|
107
|
+
msg['id'] = "#{idempotent_publish_id}:#{idx}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
options = qs_params ? { qs_params: qs_params } : {}
|
|
114
|
+
response = client.post("#{base_path}/publish", payload.length == 1 ? payload.first : payload, options)
|
|
115
|
+
|
|
116
|
+
parse_publish_result(response)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Updates a previously published message on the channel.
|
|
120
|
+
#
|
|
121
|
+
# @spec RSL15
|
|
122
|
+
#
|
|
123
|
+
# @param message [Ably::Models::Message, Hash] A Message object or Hash containing a populated :serial field
|
|
124
|
+
# and the fields to update.
|
|
125
|
+
# @param operation [Hash, Ably::Models::MessageOperation, nil] Optional operation metadata containing
|
|
126
|
+
# :description and/or :metadata fields.
|
|
127
|
+
# @param params [Hash, nil] Optional parameters sent as part of the query string.
|
|
128
|
+
#
|
|
129
|
+
# @return [Ably::Models::UpdateDeleteResult] The result containing the version_serial.
|
|
130
|
+
#
|
|
131
|
+
def update_message(message, operation = nil, params = {})
|
|
132
|
+
send_message_action(message, Ably::Models::Message::ACTION.MessageUpdate, operation, params)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Deletes a previously published message on the channel.
|
|
136
|
+
#
|
|
137
|
+
# @spec RSL15
|
|
138
|
+
#
|
|
139
|
+
# @param message [Ably::Models::Message, Hash] A Message object or Hash containing a populated :serial field.
|
|
140
|
+
# @param operation [Hash, Ably::Models::MessageOperation, nil] Optional operation metadata containing
|
|
141
|
+
# :description and/or :metadata fields.
|
|
142
|
+
# @param params [Hash, nil] Optional parameters sent as part of the query string.
|
|
143
|
+
#
|
|
144
|
+
# @return [Ably::Models::UpdateDeleteResult] The result containing the version_serial.
|
|
145
|
+
#
|
|
146
|
+
def delete_message(message, operation = nil, params = {})
|
|
147
|
+
send_message_action(message, Ably::Models::Message::ACTION.MessageDelete, operation, params)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Appends data to a previously published message on the channel.
|
|
151
|
+
#
|
|
152
|
+
# @spec RSL15
|
|
153
|
+
#
|
|
154
|
+
# @param message [Ably::Models::Message, Hash] A Message object or Hash containing a populated :serial field
|
|
155
|
+
# and the data to append.
|
|
156
|
+
# @param operation [Hash, Ably::Models::MessageOperation, nil] Optional operation metadata containing
|
|
157
|
+
# :description and/or :metadata fields.
|
|
158
|
+
# @param params [Hash, nil] Optional parameters sent as part of the query string.
|
|
159
|
+
#
|
|
160
|
+
# @return [Ably::Models::UpdateDeleteResult] The result containing the version_serial.
|
|
161
|
+
#
|
|
162
|
+
def append_message(message, operation = nil, params = {})
|
|
163
|
+
send_message_action(message, Ably::Models::Message::ACTION.MessageAppend, operation, params)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Retrieves a {Ably::Models::PaginatedResult} object, containing an array of historical {Ably::Models::Message}
|
|
167
|
+
# objects for the channel. If the channel is configured to persist messages, then messages can be retrieved from
|
|
168
|
+
# history for up to 72 hours in the past. If not, messages can only be retrieved from history for up to two minutes in the past.
|
|
169
|
+
#
|
|
170
|
+
# @spec RSL2a
|
|
171
|
+
#
|
|
172
|
+
# @param [Hash] options the options for the message history request
|
|
173
|
+
# @option options [Integer,Time] :start The time from which messages are retrieved, specified as milliseconds since the Unix epoch. RSL2b1
|
|
174
|
+
# @option options [Integer,Time] :end The time until messages are retrieved, specified as milliseconds since the Unix epoch. RSL2b1
|
|
175
|
+
# @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. RSL2b2
|
|
176
|
+
# @option options [Integer] :limit An upper limit on the number of messages returned. The default is 100, and the maximum is 1000. RSL2b3
|
|
177
|
+
#
|
|
178
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::Message>] A {Ably::Models::PaginatedResult} object containing an array of {Ably::Models::Message} objects.
|
|
179
|
+
#
|
|
180
|
+
def history(options = {})
|
|
181
|
+
url = "#{base_path}/messages"
|
|
182
|
+
options = {
|
|
183
|
+
:direction => :backwards,
|
|
184
|
+
:limit => 100
|
|
185
|
+
}.merge(options)
|
|
186
|
+
|
|
187
|
+
[:start, :end].each { |option| options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
|
|
188
|
+
raise ArgumentError, ":end must be equal to or after :start" if options[:start] && options[:end] && (options[:start] > options[:end])
|
|
189
|
+
|
|
190
|
+
paginated_options = {
|
|
191
|
+
coerce_into: 'Ably::Models::Message',
|
|
192
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
response = client.get(url, options)
|
|
196
|
+
|
|
197
|
+
Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |message|
|
|
198
|
+
message.tap do |msg|
|
|
199
|
+
decode_message msg
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# A {Ably::PubSub::Http::Presence} object.
|
|
205
|
+
# @spec RSL3
|
|
206
|
+
# @return [Ably::PubSub::Http::Presence]
|
|
207
|
+
def presence
|
|
208
|
+
@presence ||= Presence.new(client, self)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Sets the {Ably::Models::ChannelOptions} for the channel.
|
|
212
|
+
# @spec RSL7
|
|
213
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
214
|
+
# @return [Ably::Models::ChannelOptions]
|
|
215
|
+
def set_options(channel_options)
|
|
216
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
217
|
+
end
|
|
218
|
+
alias options= set_options
|
|
219
|
+
|
|
220
|
+
# Retrieves a {Ably::Models::ChannelDetails} object for the channel, which includes status and occupancy metrics.
|
|
221
|
+
# @spec RSL8
|
|
222
|
+
# @return [Ably::Models::ChannelDetails] A {Ably::Models::ChannelDetails} object.
|
|
223
|
+
def status
|
|
224
|
+
Ably::Models::ChannelDetails.new(client.get(base_path).body)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
private
|
|
228
|
+
|
|
229
|
+
def send_message_action(message, action_enum, operation = nil, params = {})
|
|
230
|
+
message = Ably::Models::Message(message)
|
|
231
|
+
|
|
232
|
+
raise Ably::Exceptions::InvalidRequest.new(
|
|
233
|
+
'Message serial is required. Ensure the message has a serial field.'
|
|
234
|
+
) unless message.serial
|
|
235
|
+
|
|
236
|
+
update_attrs = message.as_json
|
|
237
|
+
update_attrs['action'] = action_enum.to_i
|
|
238
|
+
|
|
239
|
+
if operation
|
|
240
|
+
op_hash = operation.respond_to?(:as_json) ? operation.as_json : operation
|
|
241
|
+
update_attrs['version'] = op_hash
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
updated_message = Ably::Models::Message.new(update_attrs)
|
|
245
|
+
updated_message.encode client.encoders, options
|
|
246
|
+
|
|
247
|
+
payload = updated_message.as_json
|
|
248
|
+
serial = message.serial
|
|
249
|
+
|
|
250
|
+
request_options = params && !params.empty? ? { qs_params: params } : {}
|
|
251
|
+
response = client.patch(
|
|
252
|
+
"#{base_path}/messages/#{URI.encode_www_form_component(serial)}",
|
|
253
|
+
payload,
|
|
254
|
+
request_options
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
Ably::Models::UpdateDeleteResult.new(response.body || {})
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def parse_publish_result(response)
|
|
261
|
+
body = response.body
|
|
262
|
+
if body.is_a?(Hash)
|
|
263
|
+
serials = body['serials'] || body[:serials] || []
|
|
264
|
+
Ably::Models::PublishResult.new(serials: serials)
|
|
265
|
+
else
|
|
266
|
+
Ably::Models::PublishResult.new(serials: [])
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def base_path
|
|
271
|
+
"/channels/#{URI.encode_www_form_component(name)}"
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def decode_message(message)
|
|
275
|
+
message.decode client.encoders, options
|
|
276
|
+
rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
|
|
277
|
+
client.logger.error { "Decoding Error on channel '#{name}', message event name '#{message.name}'. #{e.class.name}: #{e.message}" }
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
require 'ably/pubsub/http/channel/push_channel'
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module PubSub
|
|
3
|
+
module Http
|
|
4
|
+
class Channels
|
|
5
|
+
include Ably::Modules::ChannelsCollection
|
|
6
|
+
|
|
7
|
+
# @return [Ably::PubSub::Http::Channels]
|
|
8
|
+
def initialize(client)
|
|
9
|
+
super client, Ably::PubSub::Http::Channel
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Return a {Ably::PubSub::Http::Channel} for the given name
|
|
13
|
+
#
|
|
14
|
+
# @param name [String] The name of the channel
|
|
15
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
|
16
|
+
#
|
|
17
|
+
# @return [Ably::PubSub::Http::Channel]
|
|
18
|
+
#
|
|
19
|
+
def get(*args)
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Return a {Ably::PubSub::Http::Channel} for the given name if it exists, else the block will be called.
|
|
24
|
+
# This method is intentionally similar to {http://ruby-doc.org/core-2.1.3/Hash.html#method-i-fetch Hash#fetch} providing a simple way to check if a channel exists or not without creating one
|
|
25
|
+
#
|
|
26
|
+
# @param name [String] The name of the channel
|
|
27
|
+
# @yield [options] (optional) if a missing_block is passed to this method and no channel exists matching the name, this block is called
|
|
28
|
+
# @yieldparam [String] name of the missing channel
|
|
29
|
+
#
|
|
30
|
+
# @return [Ably::PubSub::Http::Channel]
|
|
31
|
+
#
|
|
32
|
+
def fetch(*args)
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Destroy the {Ably::PubSub::Http::Channel} and releases the associated resources.
|
|
37
|
+
#
|
|
38
|
+
# Releasing a {Ably::PubSub::Http::Channel} is not typically necessary as a channel consumes no resources other than the memory footprint of the
|
|
39
|
+
# {Ably::PubSub::Http::Channel} object. Explicitly release channels to free up resources if required
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
#
|
|
43
|
+
def release(*args)
|
|
44
|
+
super
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|