ably-rest 0.9.1 → 0.9.2
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/submodules/ably-ruby/lib/ably/exceptions.rb +3 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +5 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +20 -4
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +3 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +11 -1
- data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +16 -6
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +51 -12
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +4 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +3 -13
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +121 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +121 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +75 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +74 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 006c13b2408ff07c78159727a7e0bbd1a2eea9ab
|
4
|
+
data.tar.gz: 691848a554d61eb6c785cc7515f169e36bed8241
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ef3a684409bf54433d1c81b76da2555e6aa885dc547e4c11c8e4e94f24adf25c56cc84a2613f5d8b11c03294126a5b03b826a6a744820e1765b7eb4433eebf5
|
7
|
+
data.tar.gz: 562e4212388a59f3b53e699ff1933a1d02563b3c62af75370919c8dba10b984013e43a38bc73a33b364fe65952537d02d96eb77b30953e2c1df9d81382caf7fa
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ably/models/message_encoders/base'
|
2
|
+
|
1
3
|
module Ably::Models
|
2
4
|
# Convert messsage argument to a {Message} object and associate with a protocol message if provided
|
3
5
|
#
|
@@ -43,6 +45,9 @@ module Ably::Models
|
|
43
45
|
include Ably::Modules::ModelCommon
|
44
46
|
include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
|
45
47
|
|
48
|
+
# Statically register a default set of encoders for this class
|
49
|
+
Ably::Models::MessageEncoders.register_default_encoders self
|
50
|
+
|
46
51
|
# {Message} initializer
|
47
52
|
#
|
48
53
|
# @param attributes [Hash] object with the underlying message detail key value attributes
|
@@ -13,10 +13,11 @@ module Ably::Models::MessageEncoders
|
|
13
13
|
# Base interface for an Ably Encoder
|
14
14
|
#
|
15
15
|
class Base
|
16
|
-
attr_reader :client
|
16
|
+
attr_reader :client, :options
|
17
17
|
|
18
|
-
def initialize(client)
|
18
|
+
def initialize(client, options = {})
|
19
19
|
@client = client
|
20
|
+
@options = options
|
20
21
|
end
|
21
22
|
|
22
23
|
# #encode is called once before a message is sent to Ably
|
@@ -94,11 +95,26 @@ module Ably::Models::MessageEncoders
|
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
97
|
-
|
98
|
+
# @api private
|
99
|
+
def self.register_default_encoders(client, binary_protocol: false)
|
98
100
|
client.register_encoder Ably::Models::MessageEncoders::Utf8
|
99
101
|
client.register_encoder Ably::Models::MessageEncoders::Json
|
100
102
|
client.register_encoder Ably::Models::MessageEncoders::Cipher
|
101
|
-
client.register_encoder Ably::Models::MessageEncoders::Base64
|
103
|
+
client.register_encoder Ably::Models::MessageEncoders::Base64, binary_protocol: binary_protocol
|
104
|
+
end
|
105
|
+
|
106
|
+
# @api private
|
107
|
+
def self.encoder_from(encoder, options)
|
108
|
+
encoder_klass = if encoder.kind_of?(String)
|
109
|
+
encoder.split('::').inject(Kernel) do |base, klass_name|
|
110
|
+
base.public_send(:const_get, klass_name)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
encoder
|
114
|
+
end
|
115
|
+
|
116
|
+
raise "Encoder must inherit from `Ably::Models::MessageEncoders::Base`" unless encoder_klass.ancestors.include?(Ably::Models::MessageEncoders::Base)
|
117
|
+
encoder_klass.new(self, options)
|
102
118
|
end
|
103
119
|
end
|
104
120
|
|
@@ -52,6 +52,9 @@ module Ably::Models
|
|
52
52
|
:update
|
53
53
|
)
|
54
54
|
|
55
|
+
# Statically register a default set of encoders for this class
|
56
|
+
Ably::Models::MessageEncoders.register_default_encoders self
|
57
|
+
|
55
58
|
# {PresenceMessage} initializer
|
56
59
|
#
|
57
60
|
# @param attributes [Hash] object with the underlying presence message key value attributes
|
@@ -73,7 +73,17 @@ module Ably::Models
|
|
73
73
|
# @!attribute [r] capability
|
74
74
|
# @return [Hash] Capabilities assigned to this token
|
75
75
|
def capability
|
76
|
-
|
76
|
+
if attributes.has_key?(:capability)
|
77
|
+
capability_val = attributes.fetch(:capability)
|
78
|
+
case capability_val
|
79
|
+
when Hash
|
80
|
+
capability_val
|
81
|
+
when Ably::Models::IdiomaticRubyWrapper
|
82
|
+
capability_val.as_json
|
83
|
+
else
|
84
|
+
JSON.parse(attributes.fetch(:capability))
|
85
|
+
end
|
86
|
+
end
|
77
87
|
end
|
78
88
|
|
79
89
|
# @!attribute [r] client_id
|
@@ -42,7 +42,7 @@ module Ably::Models
|
|
42
42
|
# @!attribute [r] key_name
|
43
43
|
# @return [String] API key name of the key against which this request is made. An API key is made up of an API key name and secret delimited by a +:+
|
44
44
|
def key_name
|
45
|
-
attributes.fetch(:key_name)
|
45
|
+
attributes.fetch(:key_name) { raise Ably::Exceptions::InvalidTokenRequest, 'Key name is missing' }
|
46
46
|
end
|
47
47
|
|
48
48
|
# @!attribute [r] ttl
|
@@ -59,7 +59,16 @@ module Ably::Models
|
|
59
59
|
# the capability of the returned token will be the intersection of
|
60
60
|
# this capability with the capability of the issuing key.
|
61
61
|
def capability
|
62
|
-
|
62
|
+
capability_val = attributes.fetch(:capability) { raise Ably::Exceptions::InvalidTokenRequest, 'Capability is missing' }
|
63
|
+
|
64
|
+
case capability_val
|
65
|
+
when Hash
|
66
|
+
capability_val
|
67
|
+
when Ably::Models::IdiomaticRubyWrapper
|
68
|
+
capability_val.as_json
|
69
|
+
else
|
70
|
+
JSON.parse(attributes.fetch(:capability))
|
71
|
+
end
|
63
72
|
end
|
64
73
|
|
65
74
|
# @!attribute [r] client_id
|
@@ -75,7 +84,8 @@ module Ably::Models
|
|
75
84
|
# token requests from being replayed.
|
76
85
|
# Timestamp when sent to Ably is in milliseconds.
|
77
86
|
def timestamp
|
78
|
-
|
87
|
+
timestamp_val = attributes.fetch(:timestamp) { raise Ably::Exceptions::InvalidTokenRequest, 'Timestamp is missing' }
|
88
|
+
as_time_from_epoch(timestamp_val, granularity: :ms)
|
79
89
|
end
|
80
90
|
|
81
91
|
# @!attribute [r] nonce
|
@@ -83,21 +93,21 @@ module Ably::Models
|
|
83
93
|
# uniqueness of this request. Any subsequent request using the
|
84
94
|
# same nonce will be rejected.
|
85
95
|
def nonce
|
86
|
-
attributes.fetch(:nonce)
|
96
|
+
attributes.fetch(:nonce) { raise Ably::Exceptions::InvalidTokenRequest, 'Nonce is missing' }
|
87
97
|
end
|
88
98
|
|
89
99
|
# @!attribute [r] mac
|
90
100
|
# @return [String] the Message Authentication Code for this request. See the
|
91
101
|
# {https://www.ably.io/documentation Ably Authentication documentation} for more details.
|
92
102
|
def mac
|
93
|
-
attributes.fetch(:mac)
|
103
|
+
attributes.fetch(:mac) { raise Ably::Exceptions::InvalidTokenRequest, 'MAC is missing' }
|
94
104
|
end
|
95
105
|
|
96
106
|
# Requests that the token is always persisted
|
97
107
|
# @api private
|
98
108
|
#
|
99
109
|
def persisted
|
100
|
-
attributes
|
110
|
+
attributes[:persisted]
|
101
111
|
end
|
102
112
|
|
103
113
|
# @!attribute [r] attributes
|
@@ -10,20 +10,60 @@ module Ably::Modules
|
|
10
10
|
# - A #raw_hash_object attribute that returns the original hash object used to create this object
|
11
11
|
#
|
12
12
|
module Encodeable
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Return a Message or Presence object from the encoded JSON-like object, using the optional channel options
|
19
|
+
# @param message_object [Hash] JSON-like object representation of an encoded message
|
20
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
21
|
+
# @yield [Ably::Exceptions::BaseAblyException] yields an Ably exception if decoding fails
|
22
|
+
# @return [Message,Presence]
|
23
|
+
def from_encoded(message_object, channel_options = {}, &error_block)
|
24
|
+
new(message_object).tap do |message|
|
25
|
+
message.decode(encoders, channel_options, &error_block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return an Array of Message or Presence objects from the encoded Array of JSON-like objects, using the optional channel options
|
30
|
+
# @param message_objects [Array<Hash>] Array of JSON-like objects with encoded messages
|
31
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
32
|
+
# @return [Array<Message,Presence>]
|
33
|
+
def from_encoded_array(message_object_array, channel_options = {})
|
34
|
+
Array(message_object_array).map do |message_object|
|
35
|
+
from_encoded(message_object, channel_options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Register an encoder for this object
|
40
|
+
# @api private
|
41
|
+
def register_encoder(encoder, options = {})
|
42
|
+
encoders << Ably::Models::MessageEncoders.encoder_from(encoder, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def encoders
|
47
|
+
@encoders ||= []
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
13
51
|
# Encode a message using the channel options and register encoders for the client
|
14
|
-
# @param
|
52
|
+
# @param encoders [Array<Ably::Models::MessageEncoders::Base>] List of encoders to apply to the message
|
53
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
15
54
|
# @return [void]
|
16
55
|
# @api private
|
17
|
-
def encode(
|
18
|
-
apply_encoders :encode,
|
56
|
+
def encode(encoders, channel_options, &error_block)
|
57
|
+
apply_encoders :encode, encoders, channel_options, &error_block
|
19
58
|
end
|
20
59
|
|
21
60
|
# Decode a message using the channel options and registered encoders for the client
|
22
|
-
# @param
|
61
|
+
# @param encoders [Array<Ably::Models::MessageEncoders::Base>] List of encoders to apply to the message
|
62
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
23
63
|
# @return [void]
|
24
64
|
# @api private
|
25
|
-
def decode(
|
26
|
-
apply_encoders :decode,
|
65
|
+
def decode(encoders, channel_options, &error_block)
|
66
|
+
apply_encoders :decode, encoders, channel_options, &error_block
|
27
67
|
end
|
28
68
|
|
29
69
|
# The original encoding of this message when it was received as a raw message from the Ably service
|
@@ -44,7 +84,7 @@ module Ably::Modules
|
|
44
84
|
end
|
45
85
|
end
|
46
86
|
|
47
|
-
def apply_encoders(method,
|
87
|
+
def apply_encoders(method, encoders, channel_options, &error_callback)
|
48
88
|
max_encoding_length = 512
|
49
89
|
message_attributes = attributes.dup
|
50
90
|
|
@@ -54,16 +94,15 @@ module Ably::Modules
|
|
54
94
|
end
|
55
95
|
|
56
96
|
previous_encoding = message_attributes[:encoding]
|
57
|
-
|
58
|
-
encoder.send method, message_attributes,
|
97
|
+
encoders.each do |encoder|
|
98
|
+
encoder.send method, message_attributes, channel_options
|
59
99
|
end
|
60
100
|
end until previous_encoding == message_attributes[:encoding]
|
61
101
|
|
62
102
|
set_attributes_object message_attributes
|
63
103
|
rescue Ably::Exceptions::CipherError => cipher_error
|
64
|
-
if
|
65
|
-
|
66
|
-
channel.emit :error, cipher_error
|
104
|
+
if block_given?
|
105
|
+
yield cipher_error, "Encoder error #{cipher_error.code} trying to #{method} message: #{cipher_error.message}"
|
67
106
|
else
|
68
107
|
raise cipher_error
|
69
108
|
end
|
@@ -8,6 +8,10 @@ module Ably::Modules
|
|
8
8
|
include Conversions
|
9
9
|
include MessagePack
|
10
10
|
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
11
15
|
# Provide a normal Hash accessor to the underlying raw message object
|
12
16
|
#
|
13
17
|
# @return [Object]
|
@@ -38,6 +42,19 @@ module Ably::Modules
|
|
38
42
|
attributes.hash
|
39
43
|
end
|
40
44
|
|
45
|
+
module ClassMethods
|
46
|
+
# Return a new instance of this object using the provided JSON-like object or JSON string
|
47
|
+
# @param [Hash, String] JSON-like object or JSON string
|
48
|
+
# @return a new instance o this object
|
49
|
+
def from_json(json_like_object)
|
50
|
+
if json_like_object.kind_of?(String)
|
51
|
+
new(JSON.parse(json_like_object))
|
52
|
+
else
|
53
|
+
new(json_like_object)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
41
58
|
private
|
42
59
|
def ensure_utf8_string_for(attribute, value)
|
43
60
|
if value
|
@@ -299,7 +299,10 @@ module Ably
|
|
299
299
|
|
300
300
|
def setup_event_handlers
|
301
301
|
__incoming_msgbus__.subscribe(:message) do |message|
|
302
|
-
message.decode
|
302
|
+
message.decode(client.encoders, options) do |encode_error, error_message|
|
303
|
+
client.logger.error error_message
|
304
|
+
emit :error, encode_error
|
305
|
+
end
|
303
306
|
emit_message message.name, message
|
304
307
|
end
|
305
308
|
|
@@ -387,7 +390,10 @@ module Ably
|
|
387
390
|
|
388
391
|
def create_message(message)
|
389
392
|
Ably::Models::Message(message.dup).tap do |msg|
|
390
|
-
msg.encode
|
393
|
+
msg.encode(client.encoders, options) do |encode_error, error_message|
|
394
|
+
client.logger.error error_message
|
395
|
+
emit :error, encode_error
|
396
|
+
end
|
391
397
|
end
|
392
398
|
end
|
393
399
|
|
@@ -346,7 +346,10 @@ module Ably::Realtime
|
|
346
346
|
}
|
347
347
|
|
348
348
|
Ably::Models::PresenceMessage.new(model, logger: logger).tap do |presence_message|
|
349
|
-
presence_message.encode
|
349
|
+
presence_message.encode(client.encoders, channel.options) do |encode_error, error_message|
|
350
|
+
client.logger.error error_message
|
351
|
+
emit :error, encode_error
|
352
|
+
end
|
350
353
|
end
|
351
354
|
end
|
352
355
|
|
@@ -165,7 +165,10 @@ module Ably::Realtime
|
|
165
165
|
|
166
166
|
def setup_event_handlers
|
167
167
|
presence.__incoming_msgbus__.subscribe(:presence, :sync) do |presence_message|
|
168
|
-
presence_message.decode channel
|
168
|
+
presence_message.decode(client.encoders, channel.options) do |encode_error, error_message|
|
169
|
+
client.logger.error error_message
|
170
|
+
channel.emit :error, encode_error
|
171
|
+
end
|
169
172
|
update_members_and_emit_events presence_message
|
170
173
|
end
|
171
174
|
|
@@ -65,7 +65,7 @@ module Ably
|
|
65
65
|
|
66
66
|
payload = messages.map do |message|
|
67
67
|
Ably::Models::Message(message.dup).tap do |msg|
|
68
|
-
msg.encode
|
68
|
+
msg.encode client.encoders, options
|
69
69
|
|
70
70
|
next if msg.client_id.nil?
|
71
71
|
if msg.client_id == '*'
|
@@ -134,7 +134,7 @@ module Ably
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def decode_message(message)
|
137
|
-
message.decode
|
137
|
+
message.decode client.encoders, options
|
138
138
|
rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
|
139
139
|
client.logger.error "Decoding Error on channel '#{name}', message event name '#{message.name}'. #{e.class.name}: #{e.message}"
|
140
140
|
end
|
@@ -346,18 +346,8 @@ module Ably
|
|
346
346
|
# @return [void]
|
347
347
|
#
|
348
348
|
# @api private
|
349
|
-
def register_encoder(encoder)
|
350
|
-
|
351
|
-
encoder.split('::').inject(Kernel) do |base, klass_name|
|
352
|
-
base.public_send(:const_get, klass_name)
|
353
|
-
end
|
354
|
-
else
|
355
|
-
encoder
|
356
|
-
end
|
357
|
-
|
358
|
-
raise "Encoder must inherit from `Ably::Models::MessageEncoders::Base`" unless encoder_klass.ancestors.include?(Ably::Models::MessageEncoders::Base)
|
359
|
-
|
360
|
-
encoders << encoder_klass.new(self)
|
349
|
+
def register_encoder(encoder, options = {})
|
350
|
+
encoders << Ably::Models::MessageEncoders.encoder_from(encoder, options)
|
361
351
|
end
|
362
352
|
|
363
353
|
# @!attribute [r] protocol_binary?
|
@@ -535,7 +525,7 @@ module Ably
|
|
535
525
|
end
|
536
526
|
|
537
527
|
def initialize_default_encoders
|
538
|
-
Ably::Models::MessageEncoders.register_default_encoders self
|
528
|
+
Ably::Models::MessageEncoders.register_default_encoders self, binary_protocol: protocol == :msgpack
|
539
529
|
end
|
540
530
|
end
|
541
531
|
end
|
@@ -88,7 +88,7 @@ module Ably
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def decode_message(presence_message)
|
91
|
-
presence_message.decode channel
|
91
|
+
presence_message.decode client.encoders, channel.options
|
92
92
|
rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
|
93
93
|
client.logger.error "Decoding Error on presence channel '#{channel.name}', presence message client_id '#{presence_message.client_id}'. #{e.class.name}: #{e.message}"
|
94
94
|
end
|
@@ -367,11 +367,11 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
367
367
|
# All 3 messages should be batched into a single Protocol Message by the client library
|
368
368
|
# message.id = "{protocol_message.id}:{protocol_message_index}"
|
369
369
|
# Check that all messages share the same protocol_message.id
|
370
|
-
message_id = messages.map { |msg| msg.id.split(':')[0] }
|
370
|
+
message_id = messages.map { |msg| msg.id.split(':')[0...-1].join(':') }
|
371
371
|
expect(message_id.uniq.count).to eql(1)
|
372
372
|
|
373
373
|
# Check that messages use index 0,1,2 in the ID
|
374
|
-
message_indexes = messages.map { |msg| msg.id.split(':')
|
374
|
+
message_indexes = messages.map { |msg| msg.id.split(':').last }
|
375
375
|
expect(message_indexes).to include("0", "1", "2")
|
376
376
|
stop_reactor
|
377
377
|
end
|
@@ -1226,11 +1226,11 @@ describe Ably::Realtime::Presence, :event_machine do
|
|
1226
1226
|
let(:client_options) { default_options.merge(log_level: :none) }
|
1227
1227
|
|
1228
1228
|
def connect_members_deferrables
|
1229
|
-
(members_per_page * pages + 1).times.map do |
|
1229
|
+
(members_per_page * pages + 1).times.map do |mem_index|
|
1230
1230
|
# rate limit to 10 per second
|
1231
1231
|
EventMachine::DefaultDeferrable.new.tap do |deferrable|
|
1232
|
-
EventMachine.add_timer(
|
1233
|
-
presence_client_one.enter_client("client:#{
|
1232
|
+
EventMachine.add_timer(mem_index/10) do
|
1233
|
+
presence_client_one.enter_client("client:#{mem_index}").tap do |enter_deferrable|
|
1234
1234
|
enter_deferrable.callback { |*args| deferrable.succeed *args }
|
1235
1235
|
enter_deferrable.errback { |*args| deferrable.fail *args }
|
1236
1236
|
end
|
@@ -57,8 +57,9 @@ describe Ably::Models::MessageEncoders::Base64 do
|
|
57
57
|
|
58
58
|
context '#encode' do
|
59
59
|
context 'over binary transport' do
|
60
|
+
subject { Ably::Models::MessageEncoders::Base64.new(client, binary_protocol: true) }
|
61
|
+
|
60
62
|
before do
|
61
|
-
allow(client).to receive(:protocol_binary?).and_return(true)
|
62
63
|
subject.encode message, {}
|
63
64
|
end
|
64
65
|
|
@@ -379,4 +379,125 @@ describe Ably::Models::Message do
|
|
379
379
|
end
|
380
380
|
end
|
381
381
|
end
|
382
|
+
|
383
|
+
context '#from_encoded (TM3)' do
|
384
|
+
context 'with no encoding' do
|
385
|
+
let(:message_data) do
|
386
|
+
{ name: 'name', data: 'data-string' }
|
387
|
+
end
|
388
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
389
|
+
|
390
|
+
it 'returns a message object' do
|
391
|
+
expect(from_encoded).to be_a(Ably::Models::Message)
|
392
|
+
expect(from_encoded.name).to eql('name')
|
393
|
+
expect(from_encoded.data).to eql('data-string')
|
394
|
+
expect(from_encoded.encoding).to be_nil
|
395
|
+
end
|
396
|
+
|
397
|
+
context 'with a block' do
|
398
|
+
it 'does not call the block' do
|
399
|
+
block_called = false
|
400
|
+
subject.from_encoded(message_data) do |exception, message|
|
401
|
+
block_called = true
|
402
|
+
end
|
403
|
+
expect(block_called).to be_falsey
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
context 'with an encoding' do
|
409
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
410
|
+
let(:message_data) do
|
411
|
+
{ name: 'name', data: JSON.dump(hash_data), encoding: 'json' }
|
412
|
+
end
|
413
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
414
|
+
|
415
|
+
it 'returns a message object' do
|
416
|
+
expect(from_encoded).to be_a(Ably::Models::Message)
|
417
|
+
expect(from_encoded.name).to eql('name')
|
418
|
+
expect(from_encoded.data).to eql(hash_data)
|
419
|
+
expect(from_encoded.encoding).to be_nil
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
context 'with a custom encoding' do
|
424
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
425
|
+
let(:message_data) do
|
426
|
+
{ name: 'name', data: JSON.dump(hash_data), encoding: 'foo/json' }
|
427
|
+
end
|
428
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
429
|
+
|
430
|
+
it 'returns a message object with the residual incompatible transforms left in the encoding property' do
|
431
|
+
expect(from_encoded).to be_a(Ably::Models::Message)
|
432
|
+
expect(from_encoded.name).to eql('name')
|
433
|
+
expect(from_encoded.data).to eql(hash_data)
|
434
|
+
expect(from_encoded.encoding).to eql('foo')
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
context 'with a Cipher encoding' do
|
439
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
440
|
+
let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
441
|
+
let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
|
442
|
+
let(:payload) { random_str }
|
443
|
+
let(:message_data) do
|
444
|
+
{ name: 'name', data: crypto.encrypt(payload), encoding: 'utf-8/cipher+aes-128-cbc' }
|
445
|
+
end
|
446
|
+
let(:channel_options) { { cipher: cipher_params } }
|
447
|
+
let(:from_encoded) { subject.from_encoded(message_data, channel_options) }
|
448
|
+
|
449
|
+
it 'returns a message object with the residual incompatible transforms left in the encoding property' do
|
450
|
+
expect(from_encoded).to be_a(Ably::Models::Message)
|
451
|
+
expect(from_encoded.name).to eql('name')
|
452
|
+
expect(from_encoded.data).to eql(payload)
|
453
|
+
expect(from_encoded.encoding).to be_nil
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
context 'with invalid Cipher encoding' do
|
458
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
459
|
+
let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
460
|
+
let(:unencryped_payload) { random_str }
|
461
|
+
let(:message_data) do
|
462
|
+
{ name: 'name', data: unencryped_payload, encoding: 'utf-8/cipher+aes-128-cbc' }
|
463
|
+
end
|
464
|
+
let(:channel_options) { { cipher: cipher_params } }
|
465
|
+
|
466
|
+
context 'without a block' do
|
467
|
+
it 'raises an exception' do
|
468
|
+
expect { subject.from_encoded(message_data, channel_options) }.to raise_exception(Ably::Exceptions::CipherError)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
context 'with a block' do
|
473
|
+
it 'calls the block with the exception' do
|
474
|
+
block_called = false
|
475
|
+
subject.from_encoded(message_data, channel_options) do |exception, message|
|
476
|
+
expect(exception).to be_a(Ably::Exceptions::CipherError)
|
477
|
+
block_called = true
|
478
|
+
end
|
479
|
+
expect(block_called).to be_truthy
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
context '#from_encoded_array (TM3)' do
|
486
|
+
context 'with no encoding' do
|
487
|
+
let(:message_data) do
|
488
|
+
[{ name: 'name1', data: 'data-string' }, { name: 'name2', data: 'data-string' }]
|
489
|
+
end
|
490
|
+
let(:from_encoded) { subject.from_encoded_array(message_data) }
|
491
|
+
|
492
|
+
it 'returns an Array of message objects' do
|
493
|
+
first = from_encoded.first
|
494
|
+
expect(first).to be_a(Ably::Models::Message)
|
495
|
+
expect(first.name).to eql('name1')
|
496
|
+
expect(first.data).to eql('data-string')
|
497
|
+
expect(first.encoding).to be_nil
|
498
|
+
last = from_encoded.last
|
499
|
+
expect(last.name).to eql('name2')
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
382
503
|
end
|
@@ -383,4 +383,125 @@ describe Ably::Models::PresenceMessage do
|
|
383
383
|
end
|
384
384
|
end
|
385
385
|
end
|
386
|
+
|
387
|
+
|
388
|
+
context '#from_encoded (TP4)' do
|
389
|
+
context 'with no encoding' do
|
390
|
+
let(:message_data) do
|
391
|
+
{ action: 2, data: 'data-string' }
|
392
|
+
end
|
393
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
394
|
+
|
395
|
+
it 'returns a presence message object' do
|
396
|
+
expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
|
397
|
+
expect(from_encoded.action).to eq(:enter)
|
398
|
+
expect(from_encoded.data).to eql('data-string')
|
399
|
+
expect(from_encoded.encoding).to be_nil
|
400
|
+
end
|
401
|
+
|
402
|
+
context 'with a block' do
|
403
|
+
it 'does not call the block' do
|
404
|
+
block_called = false
|
405
|
+
subject.from_encoded(message_data) do |exception, message|
|
406
|
+
block_called = true
|
407
|
+
end
|
408
|
+
expect(block_called).to be_falsey
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
context 'with an encoding' do
|
414
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
415
|
+
let(:message_data) do
|
416
|
+
{ action: 'leave', data: JSON.dump(hash_data), encoding: 'json' }
|
417
|
+
end
|
418
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
419
|
+
|
420
|
+
it 'returns a presence message object' do
|
421
|
+
expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
|
422
|
+
expect(from_encoded.action).to eq(:leave)
|
423
|
+
expect(from_encoded.data).to eql(hash_data)
|
424
|
+
expect(from_encoded.encoding).to be_nil
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
context 'with a custom encoding' do
|
429
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
430
|
+
let(:message_data) do
|
431
|
+
{ action: 1, data: JSON.dump(hash_data), encoding: 'foo/json' }
|
432
|
+
end
|
433
|
+
let(:from_encoded) { subject.from_encoded(message_data) }
|
434
|
+
|
435
|
+
it 'returns a presence message object with the residual incompatible transforms left in the encoding property' do
|
436
|
+
expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
|
437
|
+
expect(from_encoded.action).to eq(1)
|
438
|
+
expect(from_encoded.data).to eql(hash_data)
|
439
|
+
expect(from_encoded.encoding).to eql('foo')
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
context 'with a Cipher encoding' do
|
444
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
445
|
+
let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
446
|
+
let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
|
447
|
+
let(:payload) { random_str }
|
448
|
+
let(:message_data) do
|
449
|
+
{ action: 1, data: crypto.encrypt(payload), encoding: 'utf-8/cipher+aes-128-cbc' }
|
450
|
+
end
|
451
|
+
let(:channel_options) { { cipher: cipher_params } }
|
452
|
+
let(:from_encoded) { subject.from_encoded(message_data, channel_options) }
|
453
|
+
|
454
|
+
it 'returns a presence message object with the residual incompatible transforms left in the encoding property' do
|
455
|
+
expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
|
456
|
+
expect(from_encoded.data).to eql(payload)
|
457
|
+
expect(from_encoded.encoding).to be_nil
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
context 'with invalid Cipher encoding' do
|
462
|
+
let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
|
463
|
+
let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
464
|
+
let(:unencryped_payload) { random_str }
|
465
|
+
let(:message_data) do
|
466
|
+
{ action: 1, data: unencryped_payload, encoding: 'utf-8/cipher+aes-128-cbc' }
|
467
|
+
end
|
468
|
+
let(:channel_options) { { cipher: cipher_params } }
|
469
|
+
|
470
|
+
context 'without a block' do
|
471
|
+
it 'raises an exception' do
|
472
|
+
expect { subject.from_encoded(message_data, channel_options) }.to raise_exception(Ably::Exceptions::CipherError)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
context 'with a block' do
|
477
|
+
it 'calls the block with the exception' do
|
478
|
+
block_called = false
|
479
|
+
subject.from_encoded(message_data, channel_options) do |exception, message|
|
480
|
+
expect(exception).to be_a(Ably::Exceptions::CipherError)
|
481
|
+
block_called = true
|
482
|
+
end
|
483
|
+
expect(block_called).to be_truthy
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
context '#from_encoded_array (TP4)' do
|
490
|
+
context 'with no encoding' do
|
491
|
+
let(:message_data) do
|
492
|
+
[{ action: 1, data: 'data-string' }, { action: 2, data: 'data-string' }]
|
493
|
+
end
|
494
|
+
let(:from_encoded) { subject.from_encoded_array(message_data) }
|
495
|
+
|
496
|
+
it 'returns an Array of presence message objects' do
|
497
|
+
first = from_encoded.first
|
498
|
+
expect(first).to be_a(Ably::Models::PresenceMessage)
|
499
|
+
expect(first.action).to eq(1)
|
500
|
+
expect(first.data).to eql('data-string')
|
501
|
+
expect(first.encoding).to be_nil
|
502
|
+
last = from_encoded.last
|
503
|
+
expect(last.action).to eq(:enter)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
386
507
|
end
|
@@ -146,4 +146,79 @@ describe Ably::Models::TokenDetails do
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
end
|
149
|
+
|
150
|
+
context 'from_json (TD7)' do
|
151
|
+
let(:issued_time) { Time.now }
|
152
|
+
let(:expires_time) { Time.now + 24*60*60 }
|
153
|
+
let(:capabilities) { { '*' => ['publish'] } }
|
154
|
+
|
155
|
+
context 'with Ruby idiomatic Hash object' do
|
156
|
+
subject { Ably::Models::TokenDetails.from_json(token_details_object) }
|
157
|
+
|
158
|
+
let(:token_details_object) do
|
159
|
+
{
|
160
|
+
token: 'val1',
|
161
|
+
key_name: 'val2',
|
162
|
+
issued: issued_time.to_i * 1000,
|
163
|
+
expires: expires_time.to_i * 1000,
|
164
|
+
capability: capabilities,
|
165
|
+
client_id: 'val3'
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'returns a valid TokenDetails object' do
|
170
|
+
expect(subject.token).to eql('val1')
|
171
|
+
expect(subject.key_name).to eql('val2')
|
172
|
+
expect(subject.issued.to_f).to be_within(1).of(issued_time.to_f)
|
173
|
+
expect(subject.expires.to_f).to be_within(1).of(expires_time.to_f)
|
174
|
+
expect(subject.capability).to eql(capabilities)
|
175
|
+
expect(subject.client_id).to eql('val3')
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'with JSON-like object' do
|
180
|
+
subject { Ably::Models::TokenDetails.from_json(token_details_object) }
|
181
|
+
|
182
|
+
let(:token_details_object) do
|
183
|
+
{
|
184
|
+
'keyName' => 'val2',
|
185
|
+
'issued' => issued_time.to_i * 1000,
|
186
|
+
'expires' => expires_time.to_i * 1000,
|
187
|
+
'capability' => JSON.dump(capabilities),
|
188
|
+
'clientId' => 'val3'
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'returns a valid TokenDetails object' do
|
193
|
+
expect(subject.token).to be_nil
|
194
|
+
expect(subject.key_name).to eql('val2')
|
195
|
+
expect(subject.issued.to_f).to be_within(1).of(issued_time.to_f)
|
196
|
+
expect(subject.expires.to_f).to be_within(1).of(expires_time.to_f)
|
197
|
+
expect(subject.capability).to eql(capabilities)
|
198
|
+
expect(subject.client_id).to eql('val3')
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'with JSON string' do
|
203
|
+
subject { Ably::Models::TokenDetails.from_json(JSON.dump(token_details_object)) }
|
204
|
+
|
205
|
+
let(:token_details_object) do
|
206
|
+
{
|
207
|
+
'keyName' => 'val2',
|
208
|
+
'issued' => issued_time.to_i * 1000,
|
209
|
+
'expires' => expires_time.to_i * 1000,
|
210
|
+
'clientId' => 'val3'
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'returns a valid TokenDetails object' do
|
215
|
+
expect(subject.token).to be_nil
|
216
|
+
expect(subject.key_name).to eql('val2')
|
217
|
+
expect(subject.issued.to_f).to be_within(1).of(issued_time.to_f)
|
218
|
+
expect(subject.expires.to_f).to be_within(1).of(expires_time.to_f)
|
219
|
+
expect(subject.capability).to be_nil
|
220
|
+
expect(subject.client_id).to eql('val3')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
149
224
|
end
|
@@ -107,4 +107,78 @@ describe Ably::Models::TokenRequest do
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
context 'from_json (TE6)' do
|
112
|
+
let(:timestamp) { Time.now }
|
113
|
+
let(:capabilities) { { '*' => ['publish'] } }
|
114
|
+
let(:ttl_seconds) { 60 * 1000 }
|
115
|
+
|
116
|
+
context 'with Ruby idiomatic Hash object' do
|
117
|
+
subject { Ably::Models::TokenRequest.from_json(token_request_object) }
|
118
|
+
|
119
|
+
let(:token_request_object) do
|
120
|
+
{
|
121
|
+
nonce: 'val1',
|
122
|
+
key_name: 'val2',
|
123
|
+
ttl: ttl_seconds * 1000,
|
124
|
+
timestamp: timestamp.to_i * 1000,
|
125
|
+
capability: capabilities,
|
126
|
+
client_id: 'val3'
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'returns a valid TokenRequest object' do
|
131
|
+
expect(subject.nonce).to eql('val1')
|
132
|
+
expect(subject.key_name).to eql('val2')
|
133
|
+
expect(subject.timestamp.to_f).to be_within(1).of(timestamp.to_f)
|
134
|
+
expect(subject.ttl).to eql(ttl_seconds)
|
135
|
+
expect(subject.capability).to eql(capabilities)
|
136
|
+
expect(subject.client_id).to eql('val3')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'with JSON-like object' do
|
141
|
+
subject { Ably::Models::TokenRequest.from_json(token_request_object) }
|
142
|
+
|
143
|
+
let(:token_request_object) do
|
144
|
+
{
|
145
|
+
'keyName' => 'val2',
|
146
|
+
'ttl' => ttl_seconds * 1000,
|
147
|
+
'timestamp' => timestamp.to_i * 1000,
|
148
|
+
'clientId' => 'val3'
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'returns a valid TokenRequest object' do
|
153
|
+
expect { subject.nonce }.to raise_error(Ably::Exceptions::InvalidTokenRequest)
|
154
|
+
expect(subject.key_name).to eql('val2')
|
155
|
+
expect(subject.timestamp.to_f).to be_within(1).of(timestamp.to_f)
|
156
|
+
expect(subject.ttl).to eql(ttl_seconds)
|
157
|
+
expect { subject.capability }.to raise_error(Ably::Exceptions::InvalidTokenRequest)
|
158
|
+
expect(subject.client_id).to eql('val3')
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'with JSON string' do
|
163
|
+
subject { Ably::Models::TokenRequest.from_json(JSON.dump(token_request_object)) }
|
164
|
+
|
165
|
+
let(:token_request_object) do
|
166
|
+
{
|
167
|
+
'nonce' => 'val1',
|
168
|
+
'ttl' => ttl_seconds * 1000,
|
169
|
+
'capability' => JSON.dump(capabilities),
|
170
|
+
'clientId' => 'val3'
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'returns a valid TokenRequest object' do
|
175
|
+
expect(subject.nonce).to eql('val1')
|
176
|
+
expect { subject.key_name }.to raise_error(Ably::Exceptions::InvalidTokenRequest)
|
177
|
+
expect { subject.timestamp }.to raise_error(Ably::Exceptions::InvalidTokenRequest)
|
178
|
+
expect(subject.ttl).to eql(ttl_seconds)
|
179
|
+
expect(subject.capability).to eql(capabilities)
|
180
|
+
expect(subject.client_id).to eql('val3')
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
110
184
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ably-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew O'Riordan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -405,7 +405,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
405
405
|
version: '0'
|
406
406
|
requirements: []
|
407
407
|
rubyforge_project:
|
408
|
-
rubygems_version: 2.
|
408
|
+
rubygems_version: 2.4.6
|
409
409
|
signing_key:
|
410
410
|
specification_version: 4
|
411
411
|
summary: A Ruby REST only client library for ably.io realtime messaging
|