ably-rest 0.8.2 → 0.8.3
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/CHANGELOG.md +1 -43
- data/SPEC.md +707 -580
- data/lib/submodules/ably-ruby/.travis.yml +1 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +143 -3
- data/lib/submodules/ably-ruby/README.md +1 -1
- data/lib/submodules/ably-ruby/SPEC.md +842 -520
- data/lib/submodules/ably-ruby/ably.gemspec +1 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +114 -87
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +40 -14
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +3 -5
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_result.rb +3 -12
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -3
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +7 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +191 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +97 -25
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +11 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +22 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +73 -40
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +48 -33
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +17 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +43 -16
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +57 -26
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +242 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +277 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +64 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +26 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +23 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +167 -16
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +9 -8
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +1 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +121 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +13 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +161 -79
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +142 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +180 -18
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +8 -8
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +136 -25
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +60 -4
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +54 -3
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +7 -6
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +1 -9
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_result_spec.rb +1 -18
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +21 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +10 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +27 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +0 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +7 -7
- metadata +5 -2
@@ -92,12 +92,10 @@ module Ably::Models
|
|
92
92
|
@hash_object
|
93
93
|
end
|
94
94
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
hash.dup.tap do |message|
|
95
|
+
def to_json(*args)
|
96
|
+
as_json(*args).tap do |message|
|
99
97
|
decode_binary_data_before_to_json message
|
100
|
-
end.
|
98
|
+
end.to_json
|
101
99
|
end
|
102
100
|
|
103
101
|
# Assign this message to a ProtocolMessage before delivery to the Ably system
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Ably::Models
|
2
2
|
# Wraps any Ably HTTP response that supports paging and provides methods to iterate through
|
3
|
-
# the pages using {#first}, {#next}, {#
|
3
|
+
# the pages using {#first}, {#next}, {#has_next?} and {#last?}
|
4
4
|
#
|
5
5
|
# All items in the HTTP response are available in the Array returned from {#items}
|
6
6
|
#
|
@@ -68,14 +68,6 @@ module Ably::Models
|
|
68
68
|
pagination_header('next').nil?
|
69
69
|
end
|
70
70
|
|
71
|
-
# True if this is the first page in the paged resource set
|
72
|
-
#
|
73
|
-
# @return [Boolean]
|
74
|
-
def first?
|
75
|
-
!supports_pagination? ||
|
76
|
-
pagination_header('first') == pagination_header('current')
|
77
|
-
end
|
78
|
-
|
79
71
|
# True if there is a subsequent page in this paginated set available with {#next}
|
80
72
|
#
|
81
73
|
# @return [Boolean]
|
@@ -94,8 +86,7 @@ module Ably::Models
|
|
94
86
|
<<-EOF.gsub(/^ /, '')
|
95
87
|
#<#{self.class.name}:#{self.object_id}
|
96
88
|
@base_url="#{base_url}",
|
97
|
-
@
|
98
|
-
@last?=#{!!first?},
|
89
|
+
@last?=#{!!last?},
|
99
90
|
@has_next?=#{!!has_next?},
|
100
91
|
@items=
|
101
92
|
#{items.map { |item| item.inspect }.join(",\n ") }
|
@@ -132,7 +123,7 @@ module Ably::Models
|
|
132
123
|
end
|
133
124
|
|
134
125
|
def pagination_url(id)
|
135
|
-
raise Ably::Exceptions::
|
126
|
+
raise Ably::Exceptions::PageMissing, "Paging header link #{id} does not exist" unless pagination_header(id)
|
136
127
|
|
137
128
|
if pagination_header(id).match(%r{^\./})
|
138
129
|
"#{base_url}#{pagination_header(id)[2..-1]}"
|
@@ -109,12 +109,18 @@ module Ably::Models
|
|
109
109
|
def as_json(*args)
|
110
110
|
hash.dup.tap do |presence_message|
|
111
111
|
presence_message['action'] = action.to_i
|
112
|
-
|
113
|
-
end.as_json
|
112
|
+
end.as_json.reject { |key, val| val.nil? }
|
114
113
|
rescue KeyError
|
115
114
|
raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
|
116
115
|
end
|
117
116
|
|
117
|
+
def to_json(*args)
|
118
|
+
as_json(*args).tap do |presence_message|
|
119
|
+
decode_binary_data_before_to_json presence_message
|
120
|
+
end.to_json
|
121
|
+
end
|
122
|
+
|
123
|
+
|
118
124
|
# Assign this presence message to a ProtocolMessage before delivery to the Ably system
|
119
125
|
# @api private
|
120
126
|
def assign_to_protocol_message(protocol_message)
|
@@ -27,9 +27,9 @@ module Ably::Models
|
|
27
27
|
# @!attribute [r] timestamp
|
28
28
|
# @return [Time] An optional timestamp, applied by the service in messages sent to the client, to indicate the system time at which the message was sent (milliseconds past epoch)
|
29
29
|
# @!attribute [r] messages
|
30
|
-
# @return [Message] A {ProtocolMessage} with a `:message` action contains one or more messages belonging to
|
30
|
+
# @return [Array<Message>] A {ProtocolMessage} with a `:message` action contains one or more messages belonging to the channel
|
31
31
|
# @!attribute [r] presence
|
32
|
-
# @return [PresenceMessage] A {ProtocolMessage} with a `:presence` action contains one or more presence updates belonging to
|
32
|
+
# @return [Array<PresenceMessage>] A {ProtocolMessage} with a `:presence` action contains one or more presence updates belonging to the channel
|
33
33
|
# @!attribute [r] flags
|
34
34
|
# @return [Integer] Flags indicating special ProtocolMessage states
|
35
35
|
# @!attribute [r] hash
|
@@ -37,6 +37,7 @@ module Ably::Models
|
|
37
37
|
#
|
38
38
|
class ProtocolMessage
|
39
39
|
include Ably::Modules::ModelCommon
|
40
|
+
include Ably::Modules::Encodeable
|
40
41
|
include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
|
41
42
|
extend Ably::Modules::Enum
|
42
43
|
|
@@ -203,7 +204,18 @@ module Ably::Models
|
|
203
204
|
end
|
204
205
|
|
205
206
|
def to_s
|
206
|
-
|
207
|
+
json_hash = as_json
|
208
|
+
|
209
|
+
# Decode any binary data to before converting to a JSON string representation
|
210
|
+
%w(messages presence).each do |message_type|
|
211
|
+
if json_hash[message_type] && !json_hash[message_type].empty?
|
212
|
+
json_hash[message_type].each do |message|
|
213
|
+
decode_binary_data_before_to_json message
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
json_hash.to_json
|
207
219
|
end
|
208
220
|
|
209
221
|
# True if the ProtocolMessage appears to be invalid, however this is not a guarantee
|
@@ -25,7 +25,7 @@ module Ably::Models
|
|
25
25
|
|
26
26
|
# Buffer in seconds before a token is considered unusable
|
27
27
|
# For example, if buffer is 10s, the token can no longer be used for new requests 9s before it expires
|
28
|
-
TOKEN_EXPIRY_BUFFER =
|
28
|
+
TOKEN_EXPIRY_BUFFER = 15
|
29
29
|
|
30
30
|
def initialize(attributes)
|
31
31
|
@hash_object = IdiomaticRubyWrapper(attributes.clone.freeze)
|
@@ -18,7 +18,13 @@ module Ably::Modules
|
|
18
18
|
# @return [Channel]
|
19
19
|
#
|
20
20
|
def get(name, channel_options = {})
|
21
|
-
channels
|
21
|
+
if channels.has_key?(name)
|
22
|
+
channels[name].tap do |channel|
|
23
|
+
channel.update_options channel_options if channel_options && !channel_options.empty?
|
24
|
+
end
|
25
|
+
else
|
26
|
+
channels[name] ||= channel_klass.new(client, name, channel_options)
|
27
|
+
end
|
22
28
|
end
|
23
29
|
alias_method :[], :get
|
24
30
|
|
@@ -109,7 +109,7 @@ module Ably::Modules
|
|
109
109
|
payload.kind_of?(Array) ||
|
110
110
|
payload.nil?
|
111
111
|
|
112
|
-
raise Ably::Exceptions::
|
112
|
+
raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400, 40011)
|
113
113
|
end
|
114
114
|
end
|
115
115
|
end
|
@@ -35,9 +35,12 @@ module Ably::Modules
|
|
35
35
|
|
36
36
|
private
|
37
37
|
def decode_binary_data_before_to_json(message)
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
data_key = message[:data] ? :data : 'data'
|
39
|
+
encoding_key = message[:encoding] ? :encoding : 'encoding'
|
40
|
+
|
41
|
+
if message[data_key].kind_of?(String) && message[data_key].encoding == ::Encoding::ASCII_8BIT
|
42
|
+
message[data_key] = ::Base64.encode64(message[data_key])
|
43
|
+
message[encoding_key] = [message[encoding_key], 'base64'].compact.join('/')
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
@@ -7,8 +7,8 @@ module Ably::Modules
|
|
7
7
|
module MessagePack
|
8
8
|
# Generate a packed MsgPack version of this object based on the JSON representation.
|
9
9
|
# Keys thus use mixedCase syntax as expected by the Realtime API
|
10
|
-
def to_msgpack(
|
11
|
-
as_json(
|
10
|
+
def to_msgpack(pk = nil)
|
11
|
+
as_json.to_msgpack(pk)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -22,7 +22,7 @@ module Ably::Modules
|
|
22
22
|
|
23
23
|
# Return a JSON ready object from the underlying #hash using Ably naming conventions for keys
|
24
24
|
def as_json
|
25
|
-
hash.as_json.
|
25
|
+
hash.as_json.reject { |key, val| val.nil? }
|
26
26
|
end
|
27
27
|
|
28
28
|
# Stringify the JSON representation of this object from the underlying #hash
|
@@ -40,10 +40,10 @@ module Ably::Modules
|
|
40
40
|
previous_transition.to_state if previous_transition
|
41
41
|
end
|
42
42
|
|
43
|
-
# @return [Ably::Exceptions::
|
43
|
+
# @return [Ably::Exceptions::InvalidStateChange]
|
44
44
|
def exception_for_state_change_to(state)
|
45
45
|
error_message = "#{self.class}: Unable to transition from #{current_state} => #{state}"
|
46
|
-
Ably::Exceptions::
|
46
|
+
Ably::Exceptions::InvalidStateChange.new(error_message, nil, 80020)
|
47
47
|
end
|
48
48
|
|
49
49
|
module ClassMethods
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'ably/auth'
|
2
|
+
|
3
|
+
module Ably
|
4
|
+
module Realtime
|
5
|
+
# Auth is responsible for authentication with {https://www.ably.io Ably} using basic or token authentication
|
6
|
+
# This {Ably::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
|
7
|
+
#
|
8
|
+
# Find out more about Ably authentication at: https://www.ably.io/documentation/general/authentication/
|
9
|
+
#
|
10
|
+
# @!attribute [r] client_id
|
11
|
+
# (see Ably::Auth#client_id)
|
12
|
+
# @!attribute [r] current_token_details
|
13
|
+
# (see Ably::Auth#current_token_details)
|
14
|
+
# @!attribute [r] token
|
15
|
+
# (see Ably::Auth#token)
|
16
|
+
# @!attribute [r] key
|
17
|
+
# (see Ably::Auth#key)
|
18
|
+
# @!attribute [r] key_name
|
19
|
+
# (see Ably::Auth#key_name)
|
20
|
+
# @!attribute [r] key_secret
|
21
|
+
# (see Ably::Auth#key_secret)
|
22
|
+
# @!attribute [r] options
|
23
|
+
# (see Ably::Auth#options)
|
24
|
+
# @!attribute [r] token_params
|
25
|
+
# (see Ably::Auth#options)
|
26
|
+
# @!attribute [r] using_basic_auth?
|
27
|
+
# (see Ably::Auth#using_basic_auth?)
|
28
|
+
# @!attribute [r] using_token_auth?
|
29
|
+
# (see Ably::Auth#using_token_auth?)
|
30
|
+
# @!attribute [r] token_renewable?
|
31
|
+
# (see Ably::Auth#token_renewable?)
|
32
|
+
# @!attribute [r] authentication_security_requirements_met?
|
33
|
+
# (see Ably::Auth#authentication_security_requirements_met?)
|
34
|
+
#
|
35
|
+
class Auth
|
36
|
+
extend Forwardable
|
37
|
+
include Ably::Modules::AsyncWrapper
|
38
|
+
|
39
|
+
def_delegators :auth_sync, :client_id
|
40
|
+
def_delegators :auth_sync, :current_token_details, :token
|
41
|
+
def_delegators :auth_sync, :key, :key_name, :key_secret, :options, :auth_options, :token_params
|
42
|
+
def_delegators :auth_sync, :using_basic_auth?, :using_token_auth?
|
43
|
+
def_delegators :auth_sync, :token_renewable?, :authentication_security_requirements_met?
|
44
|
+
def_delegators :client, :logger
|
45
|
+
|
46
|
+
def initialize(client)
|
47
|
+
@client = client
|
48
|
+
@auth_sync = client.rest_client.auth
|
49
|
+
end
|
50
|
+
|
51
|
+
# 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.
|
52
|
+
#
|
53
|
+
# In the event that a new token request is made, the provided options are used
|
54
|
+
#
|
55
|
+
# @param (see Ably::Auth#authorise)
|
56
|
+
# @option (see Ably::Auth#authorise)
|
57
|
+
#
|
58
|
+
# @return [Ably::Util::SafeDeferrable]
|
59
|
+
# @yield [Ably::Models::TokenDetails]
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# # will issue a simple token request using basic auth
|
63
|
+
# client = Ably::Rest::Client.new(key: 'key.id:secret')
|
64
|
+
# client.auth.authorise do |token_details|
|
65
|
+
# token_details #=> Ably::Models::TokenDetails
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
def authorise(auth_options = {}, token_params = {}, &success_callback)
|
69
|
+
async_wrap(success_callback) do
|
70
|
+
auth_sync.authorise(auth_options, token_params)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Synchronous version of {#authorise}. See {Ably::Auth#authorise} for method definition
|
75
|
+
# @param (see Ably::Auth#authorise)
|
76
|
+
# @option (see Ably::Auth#authorise)
|
77
|
+
# @return [Ably::Models::TokenDetails]
|
78
|
+
#
|
79
|
+
def authorise_sync(auth_options = {}, token_params = {})
|
80
|
+
auth_sync.authorise(auth_options, token_params)
|
81
|
+
end
|
82
|
+
|
83
|
+
# def_delegator :auth_sync, :request_token, :request_token_sync
|
84
|
+
# def_delegator :auth_sync, :create_token_request, :create_token_request_sync
|
85
|
+
# def_delegator :auth_sync, :auth_header, :auth_header_sync
|
86
|
+
# def_delegator :auth_sync, :auth_params, :auth_params_sync
|
87
|
+
|
88
|
+
# Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
|
89
|
+
#
|
90
|
+
# @param (see Ably::Auth#request_token)
|
91
|
+
# @option (see Ably::Auth#request_token)
|
92
|
+
#
|
93
|
+
# @return [Ably::Util::SafeDeferrable]
|
94
|
+
# @yield [Ably::Models::TokenDetails]
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# # simple token request using basic auth
|
98
|
+
# client = Ably::Rest::Client.new(key: 'key.id:secret')
|
99
|
+
# client.auth.request_token do |token_details|
|
100
|
+
# token_details #=> Ably::Models::TokenDetails
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
def request_token(auth_options = {}, token_params = {}, &success_callback)
|
104
|
+
async_wrap(success_callback) do
|
105
|
+
request_token_sync(auth_options, token_params)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Synchronous version of {#request_token}. See {Ably::Auth#request_token} for method definition
|
110
|
+
# @param (see Ably::Auth#authorise)
|
111
|
+
# @option (see Ably::Auth#authorise)
|
112
|
+
# @return [Ably::Models::TokenDetails]
|
113
|
+
#
|
114
|
+
def request_token_sync(auth_options = {}, token_params = {})
|
115
|
+
auth_sync.request_token(auth_options, token_params)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Creates and signs a token request that can then subsequently be used by any client to request a token
|
119
|
+
#
|
120
|
+
# @param (see Ably::Auth#create_token_request)
|
121
|
+
# @option (see Ably::Auth#create_token_request)
|
122
|
+
#
|
123
|
+
# @return [Ably::Util::SafeDeferrable]
|
124
|
+
# @yield [Models::TokenRequest]
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# client.auth.create_token_request(id: 'asd.asd', ttl: 3600) do |token_request|
|
128
|
+
# token_request #=> Ably::Models::TokenRequest
|
129
|
+
# end
|
130
|
+
def create_token_request(auth_options = {}, token_params = {}, &success_callback)
|
131
|
+
async_wrap(success_callback) do
|
132
|
+
create_token_request_sync(auth_options, token_params)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Synchronous version of {#create_token_request}. See {Ably::Auth#create_token_request} for method definition
|
137
|
+
# @param (see Ably::Auth#authorise)
|
138
|
+
# @option (see Ably::Auth#authorise)
|
139
|
+
# @return [Ably::Models::TokenRequest]
|
140
|
+
#
|
141
|
+
def create_token_request_sync(auth_options = {}, token_params = {})
|
142
|
+
auth_sync.create_token_request(auth_options, token_params)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Auth header string used in HTTP requests to Ably
|
146
|
+
# Will reauthorise implicitly if required and capable
|
147
|
+
#
|
148
|
+
# @return [Ably::Util::SafeDeferrable]
|
149
|
+
# @yield [String] HTTP authentication value used in HTTP_AUTHORIZATION header
|
150
|
+
#
|
151
|
+
def auth_header(&success_callback)
|
152
|
+
async_wrap(success_callback) do
|
153
|
+
auth_header_sync
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Synchronous version of {#auth_header}. See {Ably::Auth#auth_header} for method definition
|
158
|
+
# @return [String] HTTP authentication value used in HTTP_AUTHORIZATION header
|
159
|
+
#
|
160
|
+
def auth_header_sync
|
161
|
+
auth_sync.auth_header
|
162
|
+
end
|
163
|
+
|
164
|
+
# Auth params used in URI endpoint for Realtime connections
|
165
|
+
# Will reauthorise implicitly if required and capable
|
166
|
+
#
|
167
|
+
# @return [Ably::Util::SafeDeferrable]
|
168
|
+
# @yield [Hash] Auth params for a new Realtime connection
|
169
|
+
#
|
170
|
+
def auth_params(&success_callback)
|
171
|
+
async_wrap(success_callback) do
|
172
|
+
auth_params_sync
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Synchronous version of {#auth_params}. See {Ably::Auth#auth_params} for method definition
|
177
|
+
# @return [Hash] Auth params for a new Realtime connection
|
178
|
+
#
|
179
|
+
def auth_params_sync
|
180
|
+
auth_sync.auth_params
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
# The synchronous Auth class instanced by the Rest client
|
185
|
+
# @return [Ably::Auth]
|
186
|
+
attr_reader :auth_sync
|
187
|
+
|
188
|
+
attr_reader :client
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -87,9 +87,9 @@ module Ably
|
|
87
87
|
def initialize(client, name, channel_options = {})
|
88
88
|
ensure_utf_8 :name, name
|
89
89
|
|
90
|
+
update_options channel_options
|
90
91
|
@client = client
|
91
92
|
@name = name
|
92
|
-
@options = channel_options.clone.freeze
|
93
93
|
@queue = []
|
94
94
|
|
95
95
|
@state_machine = ChannelStateMachine.new(self)
|
@@ -100,17 +100,33 @@ module Ably
|
|
100
100
|
setup_presence
|
101
101
|
end
|
102
102
|
|
103
|
-
# Publish
|
103
|
+
# Publish one or more messages to the channel.
|
104
104
|
#
|
105
105
|
# When publishing a message, if the channel is not attached, the channel is implicitly attached
|
106
106
|
#
|
107
|
-
# @param name [String]
|
108
|
-
# @param data [String,ByteArray] payload
|
109
|
-
#
|
110
|
-
# @
|
107
|
+
# @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
|
108
|
+
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
109
|
+
#
|
110
|
+
# @yield [Ably::Models::Message,Array<Ably::Models::Message>] On success, will call the block with the {Ably::Models::Message} if a single message is publishde, or an Array of {Ably::Models::Message} when multiple messages are published
|
111
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
|
111
112
|
#
|
112
113
|
# @example
|
113
|
-
#
|
114
|
+
# # Publish a single message
|
115
|
+
# channel.publish 'click', { x: 1, y: 2 }
|
116
|
+
#
|
117
|
+
# # Publish an array of message Hashes
|
118
|
+
# messages = [
|
119
|
+
# { name: 'click', { x: 1, y: 2 } },
|
120
|
+
# { name: 'click', { x: 2, y: 3 } }
|
121
|
+
# ]
|
122
|
+
# channel.publish messages
|
123
|
+
#
|
124
|
+
# # Publish an array of Ably::Models::Message objects
|
125
|
+
# messages = [
|
126
|
+
# Ably::Models::Message(name: 'click', { x: 1, y: 2 })
|
127
|
+
# Ably::Models::Message(name: 'click', { x: 2, y: 3 })
|
128
|
+
# ]
|
129
|
+
# channel.publish messages
|
114
130
|
#
|
115
131
|
# channel.publish('click', 'body') do |message|
|
116
132
|
# puts "#{message.name} event received with #{message.data}"
|
@@ -120,13 +136,24 @@ module Ably
|
|
120
136
|
# puts "#{message.name} was not received, error #{error.message}"
|
121
137
|
# end
|
122
138
|
#
|
123
|
-
def publish(name, data, &success_block)
|
124
|
-
|
125
|
-
|
139
|
+
def publish(name, data = nil, &success_block)
|
140
|
+
raise Ably::Exceptions::ChannelInactive.new('Cannot publish messages on a detached channel') if detached? || detaching?
|
141
|
+
raise Ably::Exceptions::ChannelInactive.new('Cannot publish messages on a failed channel') if failed?
|
126
142
|
|
127
|
-
|
128
|
-
|
129
|
-
|
143
|
+
if !connection.can_publish_messages?
|
144
|
+
raise Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is configured to disallow queueing of messages and connection is currently #{connection.state}")
|
145
|
+
end
|
146
|
+
|
147
|
+
messages = if name.kind_of?(Enumerable)
|
148
|
+
name
|
149
|
+
else
|
150
|
+
ensure_utf_8 :name, name, allow_nil: true
|
151
|
+
ensure_supported_payload data
|
152
|
+
[{ name: name, data: data }]
|
153
|
+
end
|
154
|
+
|
155
|
+
queue_messages(messages).tap do |deferrable|
|
156
|
+
deferrable.callback &success_block if block_given?
|
130
157
|
end
|
131
158
|
end
|
132
159
|
|
@@ -163,6 +190,8 @@ module Ably
|
|
163
190
|
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callback
|
164
191
|
#
|
165
192
|
def attach(&success_block)
|
193
|
+
raise Ably::Exceptions::InvalidStateChange.new("Cannot ATTACH channel when the connection is in a closed, suspended or failed state. Connection state: #{connection.state}") if connection.closing? || connection.closed? || connection.suspended? || connection.failed?
|
194
|
+
|
166
195
|
transition_state_machine :attaching if can_transition_to?(:attaching)
|
167
196
|
deferrable_for_state_change_to(STATE.Attached, &success_block)
|
168
197
|
end
|
@@ -170,10 +199,18 @@ module Ably
|
|
170
199
|
# Detach this channel, and call the block if provided when in a Detached or Failed state
|
171
200
|
#
|
172
201
|
# @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Detached or Failed state
|
173
|
-
# @return [
|
202
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callback
|
174
203
|
#
|
175
204
|
def detach(&success_block)
|
176
|
-
|
205
|
+
if initialized?
|
206
|
+
success_block.call if block_given?
|
207
|
+
return Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
208
|
+
EventMachine.next_tick { deferrable.succeed }
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
raise exception_for_state_change_to(:detaching) if failed?
|
213
|
+
|
177
214
|
transition_state_machine :detaching if can_transition_to?(:detaching)
|
178
215
|
deferrable_for_state_change_to(STATE.Detached, &success_block)
|
179
216
|
end
|
@@ -237,6 +274,11 @@ module Ably
|
|
237
274
|
@attached_serial = serial
|
238
275
|
end
|
239
276
|
|
277
|
+
# @api private
|
278
|
+
def update_options(channel_options)
|
279
|
+
@options = channel_options.clone.freeze
|
280
|
+
end
|
281
|
+
|
240
282
|
# Used by {Ably::Modules::StateEmitter} to debug state changes
|
241
283
|
# @api private
|
242
284
|
def logger
|
@@ -257,16 +299,50 @@ module Ably
|
|
257
299
|
end
|
258
300
|
end
|
259
301
|
|
260
|
-
# Queue
|
302
|
+
# Queue messages and process queue if channel is attached.
|
261
303
|
# If channel is not yet attached, attempt to attach it before the message queue is processed.
|
262
|
-
|
263
|
-
|
304
|
+
# @returns [Ably::Util::SafeDeferrable]
|
305
|
+
def queue_messages(raw_messages)
|
306
|
+
messages = Array(raw_messages).map { |msg| create_message(msg) }
|
307
|
+
queue.push *messages
|
264
308
|
|
265
309
|
if attached?
|
266
310
|
process_queue
|
267
311
|
else
|
268
312
|
attach
|
269
313
|
end
|
314
|
+
|
315
|
+
if messages.count == 1
|
316
|
+
# A message is a Deferrable so, if publishing only one message, simply return that Deferrable
|
317
|
+
messages.first
|
318
|
+
else
|
319
|
+
deferrable_for_multiple_messages(messages)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# A deferrable object that calls the success callback once all messages are delivered
|
324
|
+
# If any message fails, the errback is called immediately
|
325
|
+
# Only one callback or errback is ever called i.e. if a group of messages all fail, only once
|
326
|
+
# errback will be invoked
|
327
|
+
def deferrable_for_multiple_messages(messages)
|
328
|
+
expected_deliveries = messages.count
|
329
|
+
actual_deliveries = 0
|
330
|
+
failed = false
|
331
|
+
|
332
|
+
Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
333
|
+
messages.each do |message|
|
334
|
+
message.callback do
|
335
|
+
return if failed
|
336
|
+
actual_deliveries += 1
|
337
|
+
deferrable.succeed messages if actual_deliveries == expected_deliveries
|
338
|
+
end
|
339
|
+
message.errback do |error|
|
340
|
+
return if failed
|
341
|
+
failed = true
|
342
|
+
deferrable.fail error, message
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
270
346
|
end
|
271
347
|
|
272
348
|
def messages_in_queue?
|
@@ -282,19 +358,15 @@ module Ably
|
|
282
358
|
end
|
283
359
|
|
284
360
|
def send_messages_within_protocol_message(messages)
|
285
|
-
|
361
|
+
connection.send_protocol_message(
|
286
362
|
action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
|
287
363
|
channel: name,
|
288
364
|
messages: messages
|
289
365
|
)
|
290
366
|
end
|
291
367
|
|
292
|
-
def create_message(
|
293
|
-
message
|
294
|
-
message.merge!(data: data) unless data.nil?
|
295
|
-
message.merge!(clientId: client.client_id) if client.client_id
|
296
|
-
|
297
|
-
Ably::Models::Message.new(message, logger: logger).tap do |message|
|
368
|
+
def create_message(message)
|
369
|
+
Ably::Models::Message(message.dup).tap do |message|
|
298
370
|
message.encode self
|
299
371
|
end
|
300
372
|
end
|