ably-rest 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|