ably 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +9 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +8 -1
  6. data/Rakefile +10 -0
  7. data/ably.gemspec +18 -18
  8. data/lib/ably.rb +6 -5
  9. data/lib/ably/auth.rb +11 -14
  10. data/lib/ably/exceptions.rb +18 -15
  11. data/lib/ably/logger.rb +102 -0
  12. data/lib/ably/models/error_info.rb +1 -1
  13. data/lib/ably/models/message.rb +19 -5
  14. data/lib/ably/models/message_encoders/base.rb +107 -0
  15. data/lib/ably/models/message_encoders/base64.rb +39 -0
  16. data/lib/ably/models/message_encoders/cipher.rb +80 -0
  17. data/lib/ably/models/message_encoders/json.rb +33 -0
  18. data/lib/ably/models/message_encoders/utf8.rb +33 -0
  19. data/lib/ably/models/paginated_resource.rb +23 -6
  20. data/lib/ably/models/presence_message.rb +19 -7
  21. data/lib/ably/models/protocol_message.rb +5 -4
  22. data/lib/ably/models/token.rb +2 -2
  23. data/lib/ably/modules/channels_collection.rb +0 -3
  24. data/lib/ably/modules/conversions.rb +3 -3
  25. data/lib/ably/modules/encodeable.rb +68 -0
  26. data/lib/ably/modules/event_emitter.rb +10 -4
  27. data/lib/ably/modules/event_machine_helpers.rb +6 -4
  28. data/lib/ably/modules/http_helpers.rb +7 -2
  29. data/lib/ably/modules/model_common.rb +2 -0
  30. data/lib/ably/modules/state_emitter.rb +10 -1
  31. data/lib/ably/realtime.rb +19 -12
  32. data/lib/ably/realtime/channel.rb +26 -13
  33. data/lib/ably/realtime/client.rb +31 -7
  34. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -3
  35. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +13 -4
  36. data/lib/ably/realtime/connection.rb +152 -46
  37. data/lib/ably/realtime/connection/connection_manager.rb +168 -0
  38. data/lib/ably/realtime/connection/connection_state_machine.rb +56 -33
  39. data/lib/ably/realtime/connection/websocket_transport.rb +56 -29
  40. data/lib/ably/{models → realtime/models}/nil_channel.rb +1 -1
  41. data/lib/ably/realtime/presence.rb +38 -13
  42. data/lib/ably/rest.rb +7 -5
  43. data/lib/ably/rest/channel.rb +24 -3
  44. data/lib/ably/rest/client.rb +56 -17
  45. data/lib/ably/rest/middleware/encoder.rb +49 -0
  46. data/lib/ably/rest/middleware/exceptions.rb +3 -2
  47. data/lib/ably/rest/middleware/logger.rb +37 -0
  48. data/lib/ably/rest/presence.rb +10 -2
  49. data/lib/ably/util/crypto.rb +57 -29
  50. data/lib/ably/util/pub_sub.rb +11 -0
  51. data/lib/ably/version.rb +1 -1
  52. data/spec/acceptance/realtime/channel_spec.rb +65 -7
  53. data/spec/acceptance/realtime/connection_spec.rb +123 -27
  54. data/spec/acceptance/realtime/message_spec.rb +319 -34
  55. data/spec/acceptance/realtime/presence_history_spec.rb +58 -0
  56. data/spec/acceptance/realtime/presence_spec.rb +160 -18
  57. data/spec/acceptance/rest/auth_spec.rb +93 -49
  58. data/spec/acceptance/rest/base_spec.rb +10 -10
  59. data/spec/acceptance/rest/channel_spec.rb +35 -19
  60. data/spec/acceptance/rest/channels_spec.rb +8 -8
  61. data/spec/acceptance/rest/message_spec.rb +224 -0
  62. data/spec/acceptance/rest/presence_spec.rb +159 -23
  63. data/spec/acceptance/rest/stats_spec.rb +5 -5
  64. data/spec/acceptance/rest/time_spec.rb +4 -4
  65. data/spec/integration/rest/auth.rb +1 -1
  66. data/spec/resources/crypto-data-128.json +56 -0
  67. data/spec/resources/crypto-data-256.json +56 -0
  68. data/spec/rspec_config.rb +39 -0
  69. data/spec/spec_helper.rb +4 -42
  70. data/spec/support/api_helper.rb +1 -1
  71. data/spec/support/event_machine_helper.rb +0 -5
  72. data/spec/support/protocol_msgbus_helper.rb +3 -3
  73. data/spec/support/test_app.rb +3 -3
  74. data/spec/unit/logger_spec.rb +135 -0
  75. data/spec/unit/models/message_encoders/base64_spec.rb +181 -0
  76. data/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
  77. data/spec/unit/models/message_encoders/json_spec.rb +135 -0
  78. data/spec/unit/models/message_encoders/utf8_spec.rb +100 -0
  79. data/spec/unit/models/message_spec.rb +16 -1
  80. data/spec/unit/models/paginated_resource_spec.rb +46 -0
  81. data/spec/unit/models/presence_message_spec.rb +18 -5
  82. data/spec/unit/models/token_spec.rb +1 -1
  83. data/spec/unit/modules/event_emitter_spec.rb +24 -10
  84. data/spec/unit/realtime/channel_spec.rb +3 -3
  85. data/spec/unit/realtime/channels_spec.rb +1 -1
  86. data/spec/unit/realtime/client_spec.rb +44 -2
  87. data/spec/unit/realtime/connection_spec.rb +2 -2
  88. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +4 -4
  89. data/spec/unit/realtime/presence_spec.rb +1 -1
  90. data/spec/unit/realtime/realtime_spec.rb +3 -3
  91. data/spec/unit/realtime/websocket_transport_spec.rb +24 -0
  92. data/spec/unit/rest/channels_spec.rb +1 -1
  93. data/spec/unit/rest/client_spec.rb +45 -10
  94. data/spec/unit/util/crypto_spec.rb +82 -0
  95. data/spec/unit/{modules → util}/pub_sub_spec.rb +13 -1
  96. metadata +43 -12
  97. data/spec/acceptance/crypto.rb +0 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bc321ac8e501652f72e08617651df2f90118a759
4
- data.tar.gz: 9f9b3f5abedeba6a4ac79841a7e1d5d09bf2bc4c
3
+ metadata.gz: d814eac0ae04dc623743bbe5973e80a58662056d
4
+ data.tar.gz: 95426e76baeaee6fbc297031b83cc128e5bed688
5
5
  SHA512:
6
- metadata.gz: cdd44c54e0015062c3ecd62bb39f2e03e2a5fe39118939bd7bd18d1bbddd3d774cd511634dac8273890d57b2fd2f2a2191df91016090a54e4e9ca8ffed3823c6
7
- data.tar.gz: 4ef9786cc786a7d4b6b824bf5bc137b17d92180c0b3d201ba48cb3d6aa9cf85a56fb8b3639170a4d0ce4f41179e1b6780569e8727df761f5a9f384df20f4535c
6
+ metadata.gz: b660702de87dec06d7f982ea110d59310ba1f9a130be320bd2ec7a40f777b2e5452cfa4f97f6a08a0cf751646326f53196e7cf3a39c023ce55795583309ad4db
7
+ data.tar.gz: 8088bb09de07b180385a4e817827ef2d867ccb2c6645f55c68888bfaf932df7f2a7c2ec7392b3aa1471a5045beda59d0f93fa5775171ca99b1a1083b3fca2037
data/.gitignore CHANGED
@@ -2,3 +2,5 @@ Gemfile.lock
2
2
  .yardoc
3
3
  doc/*
4
4
  pkg
5
+ .bundle
6
+ bin
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.1
6
+ - jruby-18mode # JRuby in 1.8 mode
7
+ - jruby-19mode # JRuby in 1.9 mode
8
+ - rbx-2.4.1
9
+
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Lewis Marshall
1
+ Copyright (c) 2014 Ably
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # [Ably](https://ably.io)
2
2
 
3
+ [![Build Status](https://travis-ci.org/ably/ably-ruby.png)](https://travis-ci.org/ably/ably-ruby)
4
+ [![Gem Version](https://badge.fury.io/rb/ably.svg)](http://badge.fury.io/rb/ably)
5
+
3
6
  A Ruby client library for [ably.io](https://ably.io), the real-time messaging service.
4
7
 
5
8
  ## Installation
@@ -60,7 +63,7 @@ channel.publish("greeting", "Hello World!")
60
63
  ```ruby
61
64
  client = Ably::Realtime.new(api_key: "xxxxx")
62
65
  channel = client.channel("test")
63
- channel.presence.enter(client_data: 'john.doe') do |presence|
66
+ channel.presence.enter(data: 'john.doe') do |presence|
64
67
  presence.get #=> [Array of members present]
65
68
  end
66
69
  ```
@@ -106,6 +109,10 @@ client = Ably::Rest.new(api_key: "xxxxx")
106
109
  client.time #=> 2013-12-12 14:23:34 +0000
107
110
  ```
108
111
 
112
+ ## Dependencies
113
+
114
+ If you only need to use the REST features of this library and do not want EventMachine as a dependency, then you should use the [Ably Ruby REST gem](https://rubygems.org/gems/ably-rest).
115
+
109
116
  ## Contributing
110
117
 
111
118
  1. Fork it
data/Rakefile CHANGED
@@ -2,3 +2,13 @@ require "bundler/gem_tasks"
2
2
 
3
3
  require "yard"
4
4
  YARD::Rake::YardocTask.new
5
+
6
+ begin
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :default => :spec
12
+ rescue LoadError
13
+ # no rspec available
14
+ end
data/ably.gemspec CHANGED
@@ -4,31 +4,31 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'ably/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "ably"
7
+ spec.name = 'ably'
8
8
  spec.version = Ably::VERSION
9
- spec.authors = ["Lewis Marshall", "Matthew O'Riordan"]
10
- spec.email = ["lewis@lmars.net", "matt@ably.io"]
9
+ spec.authors = ['Lewis Marshall', "Matthew O'Riordan"]
10
+ spec.email = ['lewis@lmars.net', 'matt@ably.io']
11
11
  spec.description = %q{A Ruby client library for ably.io, the real-time messaging service}
12
12
  spec.summary = %q{A Ruby client library for ably.io, the real-time messaging service}
13
- spec.homepage = "http://github.com/ably/ably-ruby"
14
- spec.license = "MIT"
13
+ spec.homepage = 'http://github.com/ably/ably-ruby'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_runtime_dependency "eventmachine", "~> 1.0"
22
- spec.add_runtime_dependency "statesman", "~> 1.0.0.beta2"
23
- spec.add_runtime_dependency "faraday", "~> 0.9"
24
- spec.add_runtime_dependency "json"
25
- spec.add_runtime_dependency "websocket-driver", "~> 0.3"
26
- spec.add_runtime_dependency "msgpack", "~> 0.5"
21
+ spec.add_runtime_dependency 'eventmachine', '~> 1.0'
22
+ spec.add_runtime_dependency 'statesman', '~> 1.0.0'
23
+ spec.add_runtime_dependency 'faraday', '~> 0.9'
24
+ spec.add_runtime_dependency 'json'
25
+ spec.add_runtime_dependency 'websocket-driver', '~> 0.3'
26
+ spec.add_runtime_dependency 'msgpack-ably', '~> 0.5.10'
27
27
 
28
- spec.add_development_dependency "bundler", "~> 1.3"
29
- spec.add_development_dependency "rake"
30
- spec.add_development_dependency "redcarpet"
31
- spec.add_development_dependency "rspec", "~> 3.0"
32
- spec.add_development_dependency "yard"
33
- spec.add_development_dependency "webmock"
28
+ spec.add_development_dependency 'bundler', '~> 1.3'
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'redcarpet'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ spec.add_development_dependency 'yard'
33
+ spec.add_development_dependency 'webmock'
34
34
  end
data/lib/ably.rb CHANGED
@@ -4,11 +4,12 @@
4
4
  end
5
5
  end
6
6
 
7
- require "ably/auth"
8
- require "ably/exceptions"
9
- require "ably/realtime"
10
- require "ably/rest"
11
- require "ably/version"
7
+ require 'ably/auth'
8
+ require 'ably/exceptions'
9
+ require 'ably/logger'
10
+ require 'ably/realtime'
11
+ require 'ably/rest'
12
+ require 'ably/version'
12
13
 
13
14
  # Ably is the base namespace for the Ably {Ably::Realtime Realtime} & {Ably::Rest Rest} client libraries.
14
15
  #
data/lib/ably/auth.rb CHANGED
@@ -2,7 +2,7 @@ require 'json'
2
2
  require 'faraday'
3
3
  require 'securerandom'
4
4
 
5
- require "ably/rest/middleware/external_exceptions"
5
+ require 'ably/rest/middleware/external_exceptions'
6
6
 
7
7
  module Ably
8
8
  # Auth is responsible for authentication with {https://ably.io Ably} using basic or token authentication
@@ -44,26 +44,26 @@ module Ably
44
44
  @auth_callback = auth_block if block_given?
45
45
 
46
46
  unless auth_options.kind_of?(Hash)
47
- raise ArgumentError, "Expected auth_options to be a Hash"
47
+ raise ArgumentError, 'Expected auth_options to be a Hash'
48
48
  end
49
49
 
50
50
  if auth_options[:api_key] && (auth_options[:key_secret] || auth_options[:key_id])
51
- raise ArgumentError, "api_key and key_id or key_secret are mutually exclusive. Provider either an api_key or key_id & key_secret"
51
+ raise ArgumentError, 'api_key and key_id or key_secret are mutually exclusive. Provider either an api_key or key_id & key_secret'
52
52
  end
53
53
 
54
54
  if auth_options[:api_key]
55
55
  api_key_parts = auth_options[:api_key].to_s.match(/(?<id>[\w_-]+\.[\w_-]+):(?<secret>[\w_-]+)/)
56
- raise ArgumentError, "api_key is invalid" unless api_key_parts
56
+ raise ArgumentError, 'api_key is invalid' unless api_key_parts
57
57
  auth_options[:key_id] = api_key_parts[:id]
58
58
  auth_options[:key_secret] = api_key_parts[:secret]
59
59
  end
60
60
 
61
61
  if using_basic_auth? && !api_key_present?
62
- raise ArgumentError, "api_key is missing. Either an API key, token, or token auth method must be provided"
62
+ raise ArgumentError, 'api_key is missing. Either an API key, token, or token auth method must be provided'
63
63
  end
64
64
 
65
65
  if has_client_id? && !api_key_present?
66
- raise ArgumentError, "client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token"
66
+ raise ArgumentError, 'client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token'
67
67
  end
68
68
 
69
69
  @options.freeze
@@ -162,7 +162,7 @@ module Ably
162
162
 
163
163
  token_request = IdiomaticRubyWrapper(token_request)
164
164
 
165
- response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request, send_auth_header: false)
165
+ response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request.hash, send_auth_header: false)
166
166
  body = IdiomaticRubyWrapper(response.body)
167
167
 
168
168
  Ably::Models::Token.new(body.fetch(:access_token))
@@ -199,7 +199,7 @@ module Ably
199
199
  request_key_id = token_options.delete(:key_id) || key_id
200
200
  request_key_secret = token_options.delete(:key_secret) || key_secret
201
201
 
202
- raise Ably::Exceptions::TokenRequestError, "Key ID and Key Secret are required to generate a new token request" unless request_key_id && request_key_secret
202
+ raise Ably::Exceptions::TokenRequestError, 'Key ID and Key Secret are required to generate a new token request' unless request_key_id && request_key_secret
203
203
 
204
204
  timestamp = if token_options[:query_time]
205
205
  client.time
@@ -294,7 +294,7 @@ module Ably
294
294
 
295
295
  # Basic Auth HTTP Authorization header value
296
296
  def basic_auth_header
297
- raise Ably::Exceptions::InsecureRequestError, "Cannot use Basic Auth over non-TLS connections" unless client.use_tls?
297
+ raise Ably::Exceptions::InsecureRequestError, 'Cannot use Basic Auth over non-TLS connections' unless client.use_tls?
298
298
  "Basic #{encode64("#{api_key}")}"
299
299
  end
300
300
 
@@ -313,7 +313,7 @@ module Ably
313
313
 
314
314
  # Basic Auth params to authenticate the Realtime connection
315
315
  def basic_auth_params
316
- raise Ably::Exceptions::InsecureRequestError, "Cannot use Basic Auth over non-TLS connections" unless client.use_tls?
316
+ raise Ably::Exceptions::InsecureRequestError, 'Cannot use Basic Auth over non-TLS connections' unless client.use_tls?
317
317
  # TODO: Change to key_secret when API is updated
318
318
  {
319
319
  key_id: key_id,
@@ -395,10 +395,7 @@ module Ably
395
395
  # Raise exceptions if response code is invalid
396
396
  builder.use Ably::Rest::Middleware::ExternalExceptions
397
397
 
398
- setup_incoming_middleware builder
399
-
400
- # Log HTTP requests if log level is DEBUG option set
401
- builder.response :logger if client.log_level == Logger::DEBUG
398
+ setup_incoming_middleware builder, client.logger
402
399
 
403
400
  # Set Faraday's HTTP adapter
404
401
  builder.adapter Faraday.default_adapter
@@ -9,7 +9,7 @@ module Ably
9
9
  # @return [String] HTTP status code of error
10
10
  # @!attribute [r] code
11
11
  # @return [String] Ably specific error code
12
- class Base < StandardError
12
+ class BaseAblyException < StandardError
13
13
  attr_reader :status, :code
14
14
  def initialize(message, status = nil, code = nil)
15
15
  super message
@@ -19,7 +19,23 @@ module Ably
19
19
  end
20
20
 
21
21
  # An invalid request was received by Ably
22
- class InvalidRequest < Base; end
22
+ class InvalidRequest < BaseAblyException; end
23
+
24
+ # The token is invalid
25
+ class InvalidToken < BaseAblyException; end
26
+
27
+ # Ably Protocol message received that is invalid
28
+ class ProtocolError < BaseAblyException; end
29
+
30
+ # Encryption or Decryption failure
31
+ class CipherError < BaseAblyException; end
32
+
33
+ # Encoding or decoding failure
34
+ class EncoderError < BaseAblyException; end
35
+
36
+ # A generic Ably exception taht supports a status & code.
37
+ # See https://github.com/ably/ably-common/blob/master/protocol/errors.json for a list of Ably errors
38
+ class Standard < BaseAblyException; end
23
39
 
24
40
  # The HTTP request has returned a 500 error
25
41
  class ServerError < StandardError; end
@@ -35,18 +51,5 @@ module Ably
35
51
 
36
52
  # The token request could not be created
37
53
  class TokenRequestError < StandardError; end
38
-
39
- # The token is invalid
40
- class InvalidToken < Base; end
41
-
42
- # Encryption or decryption related failures
43
- class EncryptionError < StandardError; end
44
-
45
- # Ably Protocol message received that is invalid
46
- class ProtocolError < Base; end
47
-
48
- # A generic Ably exception taht supports a status & code.
49
- # See https://github.com/ably/ably-common/blob/master/protocol/errors.json for a list of Ably errors
50
- class Standard < Base; end
51
54
  end
52
55
  end
@@ -0,0 +1,102 @@
1
+ module Ably
2
+ # Logger unifies logging for #debug, #info, #warn, #error, and #fatal messages.
3
+ # A new Ably client uses this Logger and sets the appropriate log level.
4
+ # A custom Logger can be configured when instantiating the client, refer to the {Ably::Rest::Client} and {Ably::Realtime::Client} documentation
5
+ #
6
+ class Logger
7
+ extend Forwardable
8
+
9
+ # @param client [Ably::Rest::Client,Ably::Realtime::Client] Rest or Realtime Ably client
10
+ # @param log_level [Integer] {http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html Ruby Logger} log level
11
+ # @param custom_logger [nil,Object] A custom logger can optionally be used instead of the,
12
+ # however it must provide a {http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html Ruby Logger} compatible interface.
13
+ #
14
+ def initialize(client, log_level, custom_logger = nil)
15
+ @client = client
16
+ @custom_logger = custom_logger
17
+ @logger = custom_logger || default_logger
18
+ @log_level = log_level
19
+
20
+ ensure_logger_interface_is_valid
21
+
22
+ @logger.level = log_level
23
+ end
24
+
25
+ # The logger used by this class, defaults to {http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html Ruby Logger}
26
+ # @return {Object,Logger}
27
+ attr_reader :logger
28
+
29
+ # If a custom logger is being used with this Logger, this property is not nil
30
+ # @return {nil,Object}
31
+ attr_reader :custom_logger
32
+
33
+ # The log level ranging from DEBUG to FATAL, refer to http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html
34
+ # @return {Integer}
35
+ attr_reader :log_level
36
+
37
+ def_delegators :logger, :fatal, :error, :warn, :info, :debug
38
+
39
+ private
40
+ attr_reader :client
41
+
42
+ def color(color_value, string)
43
+ "\033[#{color_value}m#{string}\033[0m"
44
+ end
45
+
46
+ def red(string)
47
+ color(31, string)
48
+ end
49
+
50
+ def magenta(string)
51
+ color(35, string)
52
+ end
53
+
54
+ def cyan(string)
55
+ color(36, string)
56
+ end
57
+
58
+ def connection_id
59
+ if realtime?
60
+ if client.connection.id
61
+ "[#{cyan(client.connection.id)}] "
62
+ else
63
+ "[ #{cyan('--')} ] "
64
+ end
65
+ end
66
+ end
67
+
68
+ def realtime?
69
+ client.respond_to?(:connection)
70
+ end
71
+
72
+ def default_logger
73
+ ::Logger.new(STDOUT).tap do |logger|
74
+ logger.formatter = proc do |severity, datetime, progname, msg|
75
+ severity = ::Logger::SEV_LABEL.index(severity) if severity.kind_of?(String)
76
+
77
+ formatted_date = if severity == ::Logger::DEBUG
78
+ datetime.strftime("%H:%M:%S.%L")
79
+ else
80
+ datetime.strftime("%Y-%m-%d %H:%M:%S.%L")
81
+ end
82
+
83
+ severity_label = if severity <= ::Logger::INFO
84
+ magenta(::Logger::SEV_LABEL[severity])
85
+ else
86
+ red(::Logger::SEV_LABEL[severity])
87
+ end
88
+
89
+ "#{formatted_date} #{severity_label} #{connection_id}#{msg}\n"
90
+ end
91
+ end
92
+ end
93
+
94
+ def ensure_logger_interface_is_valid
95
+ %w(fatal error warn info debug level level=).each do |method|
96
+ unless logger.respond_to?(method)
97
+ raise ArgumentError, "The custom Logger's interface does not provide the method '#{method}'"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -31,7 +31,7 @@ module Ably::Models
31
31
  end
32
32
 
33
33
  def to_s
34
- "Error: #{message} (code: #{code}, status_code: #{status_code})"
34
+ "Error: #{message} (code: #{code}, http status: #{status})"
35
35
  end
36
36
  end
37
37
  end
@@ -25,6 +25,9 @@ module Ably::Models
25
25
  # @return [String] The id of the publisher of this message
26
26
  # @!attribute [r] data
27
27
  # @return [Object] The message payload. See the documentation for supported datatypes.
28
+ # @!attribute [r] encoding
29
+ # @return [Object] The encoding for the message data. Encoding and decoding of messages is handled automatically by the client library.
30
+ # Therefore, the `encoding` attribute should always be nil unless an Ably library decoding error has occurred.
28
31
  # @!attribute [r] timestamp
29
32
  # @return [Time] Timestamp when the message was received by the Ably the real-time service
30
33
  # @!attribute [r] id
@@ -34,6 +37,7 @@ module Ably::Models
34
37
  #
35
38
  class Message
36
39
  include Ably::Modules::ModelCommon
40
+ include Ably::Modules::Encodeable
37
41
  include EventMachine::Deferrable
38
42
 
39
43
  # {Message} initializer
@@ -44,10 +48,11 @@ module Ably::Models
44
48
  def initialize(hash_object, protocol_message = nil)
45
49
  @protocol_message = protocol_message
46
50
  @raw_hash_object = hash_object
47
- @hash_object = IdiomaticRubyWrapper(hash_object.clone.freeze, stop_at: [:data])
51
+
52
+ set_hash_object hash_object
48
53
  end
49
54
 
50
- %w( name client_id ).each do |attribute|
55
+ %w( name client_id encoding ).each do |attribute|
51
56
  define_method attribute do
52
57
  hash[attribute.to_sym]
53
58
  end
@@ -74,8 +79,11 @@ module Ably::Models
74
79
  end
75
80
 
76
81
  def as_json(*args)
77
- raise RuntimeError, ":name is missing, cannot generate a valid Hash for Message" unless name
78
- super
82
+ raise RuntimeError, ':name is missing, cannot generate a valid Hash for Message' unless name
83
+
84
+ hash.dup.tap do |message|
85
+ decode_binary_data_before_to_json message
86
+ end.as_json
79
87
  end
80
88
 
81
89
  # Assign this message to a ProtocolMessage before delivery to the Ably system
@@ -95,11 +103,13 @@ module Ably::Models
95
103
  # @return [Ably::Models::ProtocolMessage]
96
104
  # @api private
97
105
  def protocol_message
98
- raise RuntimeError, "Message is not yet published with a ProtocolMessage. ProtocolMessage is nil" if @protocol_message.nil?
106
+ raise RuntimeError, 'Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
99
107
  @protocol_message
100
108
  end
101
109
 
102
110
  private
111
+ attr_reader :raw_hash_object
112
+
103
113
  def protocol_message_index
104
114
  protocol_message.messages.index(self)
105
115
  end
@@ -111,5 +121,9 @@ module Ably::Models
111
121
  def message_serial
112
122
  protocol_message.message_serial
113
123
  end
124
+
125
+ def set_hash_object(hash)
126
+ @hash_object = IdiomaticRubyWrapper(hash.clone.freeze, stop_at: [:data])
127
+ end
114
128
  end
115
129
  end