ably-rest 0.7.1 → 0.7.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 +13 -5
- data/.gitmodules +1 -1
- data/.rspec +1 -0
- data/.travis.yml +7 -3
- data/SPEC.md +495 -419
- data/ably-rest.gemspec +19 -5
- data/lib/ably-rest.rb +9 -1
- data/lib/submodules/ably-ruby/.gitignore +6 -0
- data/lib/submodules/ably-ruby/.rspec +1 -0
- data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
- data/lib/submodules/ably-ruby/.travis.yml +10 -0
- data/lib/submodules/ably-ruby/Gemfile +4 -0
- data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
- data/lib/submodules/ably-ruby/README.md +122 -0
- data/lib/submodules/ably-ruby/Rakefile +34 -0
- data/lib/submodules/ably-ruby/SPEC.md +1794 -0
- data/lib/submodules/ably-ruby/ably.gemspec +36 -0
- data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
- data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
- data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
- data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
- data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
- data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
- metadata +182 -27
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Rest
|
|
6
|
+
module Middleware
|
|
7
|
+
# Encode the body of the message according to the mime type
|
|
8
|
+
class Encoder < ::Faraday::Response::Middleware
|
|
9
|
+
CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
|
|
10
|
+
|
|
11
|
+
def call(env)
|
|
12
|
+
encode env if env.body
|
|
13
|
+
@app.call env
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
def encode(env)
|
|
18
|
+
env.body = case request_type(env)
|
|
19
|
+
when 'application/x-msgpack'
|
|
20
|
+
to_msgpack(env.body)
|
|
21
|
+
when 'application/json', '', nil
|
|
22
|
+
env.request_headers[CONTENT_TYPE] = 'application/json'
|
|
23
|
+
to_json(env.body)
|
|
24
|
+
else
|
|
25
|
+
env.body
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_msgpack(body)
|
|
30
|
+
body.to_msgpack
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_json(body)
|
|
34
|
+
if body.kind_of?(String)
|
|
35
|
+
body
|
|
36
|
+
else
|
|
37
|
+
body.to_json
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def request_type(env)
|
|
42
|
+
type = env.request_headers[CONTENT_TYPE].to_s
|
|
43
|
+
type = type.split(';', 2).first if type.index(';')
|
|
44
|
+
type
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Rest
|
|
6
|
+
module Middleware
|
|
7
|
+
# HTTP exceptions raised by Ably due to an error status code
|
|
8
|
+
# Ably returns JSON/Msgpack error codes and messages so include this if possible in the exception messages
|
|
9
|
+
class Exceptions < Faraday::Response::Middleware
|
|
10
|
+
def on_complete(env)
|
|
11
|
+
if env.status >= 400
|
|
12
|
+
error_status_code = env.status
|
|
13
|
+
error_code = nil
|
|
14
|
+
|
|
15
|
+
if env.body.kind_of?(Hash)
|
|
16
|
+
error = env.body.fetch('error', {})
|
|
17
|
+
error_status_code = error['statusCode'].to_i if error['statusCode']
|
|
18
|
+
error_code = error['code'].to_i if error['code']
|
|
19
|
+
|
|
20
|
+
if error
|
|
21
|
+
message = "#{error['message']} (status: #{error_status_code}, code: #{error_code})"
|
|
22
|
+
else
|
|
23
|
+
message = env.body
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
message = env.body
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
message = 'Unknown server error' if message.to_s.strip == ''
|
|
30
|
+
|
|
31
|
+
if env.status >= 500
|
|
32
|
+
raise Ably::Exceptions::ServerError, message
|
|
33
|
+
else
|
|
34
|
+
raise Ably::Exceptions::InvalidRequest.new(message, error_status_code, error_code)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
|
|
3
|
+
module Ably
|
|
4
|
+
module Rest
|
|
5
|
+
module Middleware
|
|
6
|
+
# HTTP exceptions raised due to a status code error on a 3rd party site
|
|
7
|
+
# Used by auth calls
|
|
8
|
+
class ExternalExceptions < Faraday::Response::Middleware
|
|
9
|
+
def on_complete(env)
|
|
10
|
+
if env.status >= 400
|
|
11
|
+
error_status_code = env.status
|
|
12
|
+
message = "Error #{error_status_code}: #{(env.body || '')[0...200]}"
|
|
13
|
+
|
|
14
|
+
if error_status_code >= 500
|
|
15
|
+
raise Ably::Exceptions::ServerError, message
|
|
16
|
+
else
|
|
17
|
+
raise Ably::Exceptions::InvalidRequest, message
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Rest
|
|
6
|
+
module Middleware
|
|
7
|
+
class FailIfUnsupportedMimeType < Faraday::Response::Middleware
|
|
8
|
+
def on_complete(env)
|
|
9
|
+
unless env.response_headers['Ably-Middleware-Parsed'] == true
|
|
10
|
+
raise Ably::Exceptions::InvalidResponseBody,
|
|
11
|
+
"Content Type #{env.response_headers['Content-Type']} is not supported by this client library"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
|
|
3
|
+
module Ably
|
|
4
|
+
module Rest
|
|
5
|
+
module Middleware
|
|
6
|
+
class Logger < Faraday::Response::Middleware
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def initialize(app, logger = nil)
|
|
10
|
+
super(app)
|
|
11
|
+
@logger = logger || begin
|
|
12
|
+
require 'logger'
|
|
13
|
+
::Logger.new(STDOUT)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
|
18
|
+
|
|
19
|
+
def call(env)
|
|
20
|
+
debug "=> URL: #{env.method} #{env.url}, Headers: #{dump_headers env.request_headers}"
|
|
21
|
+
debug "=> Body: #{body_for(env)}"
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def on_complete(env)
|
|
26
|
+
debug "<= Status: #{env.status}, Headers: #{dump_headers env.response_headers}"
|
|
27
|
+
debug "<= Body: #{body_for(env)}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
def dump_headers(headers)
|
|
32
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def body_for(env)
|
|
36
|
+
return '' if !env.body || env.body.empty?
|
|
37
|
+
|
|
38
|
+
if env.request_headers['Content-Type'] == 'application/x-msgpack'
|
|
39
|
+
MessagePack.unpack(env.body)
|
|
40
|
+
else
|
|
41
|
+
env.body
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
rescue StandardError
|
|
45
|
+
readable_body(env.body)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def readable_body(body)
|
|
49
|
+
if body.respond_to?(:encoding) && body.encoding == Encoding::ASCII_8BIT
|
|
50
|
+
body.unpack('H*')
|
|
51
|
+
else
|
|
52
|
+
body
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Rest
|
|
6
|
+
module Middleware
|
|
7
|
+
class ParseJson < Faraday::Response::Middleware
|
|
8
|
+
def on_complete(env)
|
|
9
|
+
if env.response_headers['Content-Type'] == 'application/json'
|
|
10
|
+
env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
|
|
11
|
+
env.response_headers['Ably-Middleware-Parsed'] = true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def parse(body)
|
|
16
|
+
if body.length > 0
|
|
17
|
+
JSON.parse(body)
|
|
18
|
+
else
|
|
19
|
+
body
|
|
20
|
+
end
|
|
21
|
+
rescue JSON::ParserError => e
|
|
22
|
+
raise Ably::Exceptions::InvalidResponseBody, "Expected JSON response: #{e.message}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'msgpack'
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Rest
|
|
6
|
+
module Middleware
|
|
7
|
+
class ParseMessagePack < Faraday::Response::Middleware
|
|
8
|
+
def on_complete(env)
|
|
9
|
+
if env.response_headers['Content-Type'] == 'application/x-msgpack'
|
|
10
|
+
env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
|
|
11
|
+
env.response_headers['Ably-Middleware-Parsed'] = true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def parse(body)
|
|
16
|
+
if body.length > 0
|
|
17
|
+
MessagePack.unpack(body)
|
|
18
|
+
else
|
|
19
|
+
body
|
|
20
|
+
end
|
|
21
|
+
rescue MessagePack::MalformedFormatError => e
|
|
22
|
+
raise Ably::Exceptions::InvalidResponseBody, "Expected MessagePack response: #{e.message}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module Rest
|
|
3
|
+
class Presence
|
|
4
|
+
include Ably::Modules::Conversions
|
|
5
|
+
|
|
6
|
+
# {Ably::Rest::Client} for this Presence object
|
|
7
|
+
# @return {Ably::Rest::Client}
|
|
8
|
+
attr_reader :client
|
|
9
|
+
|
|
10
|
+
# {Ably::Rest::Channel} this Presence object is associated with
|
|
11
|
+
# @return {Ably::Rest::Channel}
|
|
12
|
+
attr_reader :channel
|
|
13
|
+
|
|
14
|
+
# Initialize a new Presence object
|
|
15
|
+
#
|
|
16
|
+
# @param client [Ably::Rest::Client]
|
|
17
|
+
# @param channel [Channel] The channel object
|
|
18
|
+
def initialize(client, channel)
|
|
19
|
+
@client = client
|
|
20
|
+
@channel = channel
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Obtain the set of members currently present for a channel
|
|
24
|
+
#
|
|
25
|
+
# @param [Hash] options the options for the set of members present
|
|
26
|
+
# @option options [Integer,Time] :start Time or millisecond since epoch
|
|
27
|
+
# @option options [Integer,Time] :end Time or millisecond since epoch
|
|
28
|
+
# @option options [Symbol] :direction `:forwards` or `:backwards`
|
|
29
|
+
# @option options [Integer] :limit Maximum number of members to retrieve up to 10,000
|
|
30
|
+
#
|
|
31
|
+
# @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
|
|
32
|
+
#
|
|
33
|
+
def get(options = {})
|
|
34
|
+
options = options.dup
|
|
35
|
+
|
|
36
|
+
paginated_options = {
|
|
37
|
+
coerce_into: 'Ably::Models::PresenceMessage',
|
|
38
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
response = client.get(base_path, options)
|
|
42
|
+
|
|
43
|
+
Ably::Models::PaginatedResource.new(response, base_path, client, paginated_options) do |presence_message|
|
|
44
|
+
presence_message.tap do |presence_message|
|
|
45
|
+
decode_message presence_message
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Return the presence messages history for the channel
|
|
51
|
+
#
|
|
52
|
+
# @param [Hash] options the options for the message history request
|
|
53
|
+
# @option options [Integer,Time] :start Time or millisecond since epoch
|
|
54
|
+
# @option options [Integer,Time] :end Time or millisecond since epoch
|
|
55
|
+
# @option options [Symbol] :direction `:forwards` or `:backwards`
|
|
56
|
+
# @option options [Integer] :limit Maximum number of presence messages to retrieve up to 10,000
|
|
57
|
+
#
|
|
58
|
+
# @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
|
|
59
|
+
#
|
|
60
|
+
def history(options = {})
|
|
61
|
+
url = "#{base_path}/history"
|
|
62
|
+
options = options.dup
|
|
63
|
+
|
|
64
|
+
[:start, :end].each { |option| options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
|
|
65
|
+
|
|
66
|
+
paginated_options = {
|
|
67
|
+
coerce_into: 'Ably::Models::PresenceMessage',
|
|
68
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
response = client.get(url, options)
|
|
72
|
+
|
|
73
|
+
Ably::Models::PaginatedResource.new(response, url, client, paginated_options) do |presence_message|
|
|
74
|
+
presence_message.tap do |presence_message|
|
|
75
|
+
decode_message presence_message
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
def base_path
|
|
82
|
+
"/channels/#{CGI.escape(channel.name)}/presence"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def decode_message(presence_message)
|
|
86
|
+
presence_message.decode self.channel
|
|
87
|
+
rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
|
|
88
|
+
client.logger.error "Decoding Error on presence channel '#{channel.name}', presence message client_id '#{presence_message.client_id}'. #{e.class.name}: #{e.message}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'msgpack'
|
|
2
|
+
require 'openssl'
|
|
3
|
+
|
|
4
|
+
module Ably::Util
|
|
5
|
+
class Crypto
|
|
6
|
+
DEFAULTS = {
|
|
7
|
+
algorithm: 'AES',
|
|
8
|
+
mode: 'CBC',
|
|
9
|
+
key_length: 128,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
BLOCK_LENGTH = 16
|
|
13
|
+
|
|
14
|
+
# Configured options for this Crypto object, see {#initialize} for a list of configured options
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash]
|
|
17
|
+
attr_reader :options
|
|
18
|
+
|
|
19
|
+
# Creates a {Ably::Util::Crypto} object
|
|
20
|
+
#
|
|
21
|
+
# @param [Hash] options an options Hash used to configure the Crypto library
|
|
22
|
+
# @option options [String] :key Required secret key used for encrypting and decrypting
|
|
23
|
+
# @option options [String] :algorithm optional (default AES), specify the encryption algorithm supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
|
|
24
|
+
# @option options [String] :mode optional (default CBC), specify the cipher mode supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
|
|
25
|
+
# @option options [Integer] :key_length optional (default 128), specify the key length of the cipher supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
|
|
26
|
+
# @option options [String] :combined optional (default AES-128-CBC), specify in one option the algorithm, key length and cipher of the cipher supported by {http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html OpenSSL::Cipher}
|
|
27
|
+
#
|
|
28
|
+
# @return [Ably::Util::Crypto]
|
|
29
|
+
#
|
|
30
|
+
# @example
|
|
31
|
+
# crypto = Ably::Util::Crypto.new(key: 'mysecret')
|
|
32
|
+
# encrypted = crypto.encrypt('secret text')
|
|
33
|
+
# crypto.decrypt(decrypted) # => 'secret text'
|
|
34
|
+
#
|
|
35
|
+
def initialize(options)
|
|
36
|
+
raise ArgumentError, ':key is required' unless options.has_key?(:key)
|
|
37
|
+
@options = DEFAULTS.merge(options).freeze
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Encrypt payload using configured Cipher
|
|
41
|
+
#
|
|
42
|
+
# @param [String] payload the payload to be encrypted
|
|
43
|
+
# @param [Hash] encrypt_options an options Hash to configure the encrypt action
|
|
44
|
+
# @option encrypt_options [String] :iv optionally use the provided Initialization Vector instead of a randomly generated IV
|
|
45
|
+
#
|
|
46
|
+
# @return [String] binary string with {Encoding::ASCII_8BIT} encoding
|
|
47
|
+
#
|
|
48
|
+
def encrypt(payload, encrypt_options = {})
|
|
49
|
+
cipher = openssl_cipher
|
|
50
|
+
cipher.encrypt
|
|
51
|
+
cipher.key = key
|
|
52
|
+
iv = encrypt_options[:iv] || options[:iv] || cipher.random_iv
|
|
53
|
+
cipher.iv = iv
|
|
54
|
+
|
|
55
|
+
iv << cipher.update(payload) << cipher.final
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Decrypt payload using configured Cipher
|
|
59
|
+
#
|
|
60
|
+
# @param [String] encrypted_payload_with_iv the encrypted payload to be decrypted
|
|
61
|
+
#
|
|
62
|
+
# @return [String]
|
|
63
|
+
#
|
|
64
|
+
def decrypt(encrypted_payload_with_iv)
|
|
65
|
+
raise Ably::Exceptions::CipherError, 'iv is missing or not long enough' unless encrypted_payload_with_iv.length >= BLOCK_LENGTH*2
|
|
66
|
+
|
|
67
|
+
iv = encrypted_payload_with_iv.slice(0...BLOCK_LENGTH)
|
|
68
|
+
encrypted_payload = encrypted_payload_with_iv.slice(BLOCK_LENGTH..-1)
|
|
69
|
+
|
|
70
|
+
decipher = openssl_cipher
|
|
71
|
+
decipher.decrypt
|
|
72
|
+
decipher.key = key
|
|
73
|
+
decipher.iv = iv
|
|
74
|
+
|
|
75
|
+
decipher.update(encrypted_payload) << decipher.final
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Generate a random key
|
|
79
|
+
# @return [String]
|
|
80
|
+
def random_key
|
|
81
|
+
openssl_cipher.random_key
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Generate a random IV
|
|
85
|
+
# @return [String]
|
|
86
|
+
def random_iv
|
|
87
|
+
openssl_cipher.random_iv
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# The Cipher algorithm string such as AES-128-CBC
|
|
91
|
+
# @return [String]
|
|
92
|
+
def cipher_type
|
|
93
|
+
(options[:combined] || "#{options[:algorithm]}-#{options[:key_length]}-#{options[:mode]}").to_s.upcase
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
def key
|
|
98
|
+
options[:key]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def openssl_cipher
|
|
102
|
+
OpenSSL::Cipher.new(cipher_type)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|