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
@@ -5,13 +5,28 @@ module Ably::Realtime
5
5
  module StatesmanMonkeyPatch
6
6
  # Override Statesman's #before_transition to support :from arrays
7
7
  # This can be removed once https://github.com/gocardless/statesman/issues/95 is solved
8
- def before_transition(options, &block)
9
- if options.fetch(:from, nil).kind_of?(Array)
8
+ def before_transition(options = nil, &block)
9
+ arrayify_transition(options) do |options_without_from_array|
10
+ super *options_without_from_array, &block
11
+ end
12
+ end
13
+
14
+ def after_transition(options = nil, &block)
15
+ arrayify_transition(options) do |options_without_from_array|
16
+ super *options_without_from_array, &block
17
+ end
18
+ end
19
+
20
+ private
21
+ def arrayify_transition(options, &block)
22
+ if options.nil?
23
+ yield []
24
+ elsif options.fetch(:from, nil).kind_of?(Array)
10
25
  options[:from].each do |from_state|
11
- super(options.merge(from: from_state), &block)
26
+ yield [options.merge(from: from_state)]
12
27
  end
13
28
  else
14
- super
29
+ yield [options]
15
30
  end
16
31
  end
17
32
  end
@@ -34,59 +49,63 @@ module Ably::Realtime
34
49
  end
35
50
 
36
51
  transition :from => :initialized, :to => [:connecting, :closed]
37
- transition :from => :connecting, :to => [:connected, :failed, :closed]
52
+ transition :from => :connecting, :to => [:connected, :failed, :closed, :disconnected]
38
53
  transition :from => :connected, :to => [:disconnected, :suspended, :closed, :failed]
39
- transition :from => :disconnected, :to => [:connecting, :closed]
40
- transition :from => :suspended, :to => [:connecting, :closed]
54
+ transition :from => :disconnected, :to => [:connecting, :closed, :failed]
55
+ transition :from => :suspended, :to => [:connecting, :closed, :failed]
41
56
  transition :from => :closed, :to => [:connecting]
42
57
  transition :from => :failed, :to => [:connecting]
43
58
 
44
- before_transition(to: [:connecting], from: [:initialized, :closed, :failed]) do |connection|
45
- connection.setup_transport do |transport|
46
- # Transition this StateMachine once the transport is connected or disconnected
47
- # Invalid state changes are simply ignored and logged
48
- transport.on(:disconnected) do
49
- connection.transition_state_machine :disconnected
50
- end
51
- end
59
+ after_transition do |connection, transition|
60
+ connection.synchronize_state_with_statemachine
61
+ end
62
+
63
+ after_transition(to: [:connecting], from: [:initialized, :closed, :failed]) do |connection|
64
+ connection.manager.setup_transport
65
+ end
66
+
67
+ after_transition(to: [:connecting], from: [:disconnected, :suspended]) do |connection|
68
+ connection.manager.reconnect_transport
52
69
  end
53
70
 
54
- before_transition(to: [:connecting], from: [:disconnected, :suspended]) do |connection|
55
- connection.reconnect_transport
71
+ before_transition(to: [:connected]) do |connection|
72
+ connection.manager.cancel_connection_retry_timers
73
+ end
74
+
75
+ after_transition(to: [:disconnected], from: [:connecting]) do |connection, current_transition|
76
+ connection.manager.respond_to_transport_disconnected current_transition
56
77
  end
57
78
 
58
79
  after_transition(to: [:failed]) do |connection|
59
- connection.transport.disconnect
80
+ connection.manager.destroy_transport
60
81
  end
61
82
 
62
83
  before_transition(to: [:closed], from: [:initialized]) do |connection|
63
- connection.timers.fetch(:initializer, []).each(&:cancel)
84
+ connection.manager.cancel_initialized_timers
64
85
  end
65
86
 
66
87
  before_transition(to: [:closed], from: [:connecting, :connected, :disconnected, :suspended]) do |connection|
67
- connection.send_protocol_message action: Ably::Models::ProtocolMessage::ACTION.Close
68
- connection.transport.disconnect
88
+ connection.manager.close_connection
69
89
  end
70
90
 
71
- after_transition do |connection, transition|
72
- connection.change_state transition.to_state
91
+ # Override Statesman's #transition_to so that:
92
+ # * log state change failures to {Logger}
93
+ def transition_to(state, *args)
94
+ unless result = super(state, *args)
95
+ logger.fatal "ConnectionStateMachine: Unable to transition from #{current_state} => #{state}"
96
+ end
97
+ result
73
98
  end
74
99
 
75
- def initialize(connection)
76
- @connection = connection
77
- super(connection)
100
+ def previous_transition
101
+ history[-2]
78
102
  end
79
103
 
80
- # Override Statesman's #transition_to to simply log state change failures
81
- def transition_to(*args)
82
- unless super(*args)
83
- logger.debug "Unable to transition to #{args[0]} from #{current_state}"
84
- end
104
+ def previous_state
105
+ previous_transition.to_state if previous_transition
85
106
  end
86
107
 
87
108
  private
88
- attr_reader :connection
89
-
90
109
  # TODO: Implement once CLOSED ProtocolMessage is sent back from Ably in response to a CLOSE message
91
110
  #
92
111
  # FORCE_CONNECTION_CLOSED_TIMEOUT = 5
@@ -103,6 +122,10 @@ module Ably::Realtime
103
122
  # end.clear
104
123
  # end
105
124
 
125
+ def connection
126
+ object
127
+ end
128
+
106
129
  def logger
107
130
  connection.logger
108
131
  end
@@ -4,7 +4,6 @@ module Ably::Realtime
4
4
  # @api private
5
5
  class WebsocketTransport < EventMachine::Connection
6
6
  include Ably::Modules::EventEmitter
7
- include Ably::Modules::Conversions
8
7
  extend Ably::Modules::Enum
9
8
 
10
9
  # Valid WebSocket connection states
@@ -17,28 +16,17 @@ module Ably::Realtime
17
16
  )
18
17
  include Ably::Modules::StateEmitter
19
18
 
20
- def initialize(connection)
19
+ def initialize(connection, url)
21
20
  @connection = connection
22
21
  @state = STATE.Initialized
23
- end
22
+ @url = url
24
23
 
25
- # Send object down the WebSocket driver connection as a serialized string/byte array based on protocol
26
- # @param [Object] object to serialize and send to the WebSocket driver
27
- # @api public
28
- def send_object(object)
29
- case client.protocol
30
- when :json
31
- driver.text(object.to_json)
32
- when :msgpack
33
- driver.binary(object.to_msgpack.unpack('c*'))
34
- else
35
- client.logger.error "Unsupported protocol '#{client.protocol}' for serialization, object cannot be serialized and sent to Ably over this WebSocket"
36
- end
24
+ setup_event_handlers
37
25
  end
38
26
 
39
27
  # Disconnect the socket transport connection and write all pending text.
40
28
  # If Disconnected state is not automatically triggered, it will be triggered automatically
41
- # @return <void>
29
+ # @return [void]
42
30
  # @api public
43
31
  def disconnect
44
32
  close_connection_after_writing
@@ -81,13 +69,7 @@ module Ably::Realtime
81
69
  # URL end point including initialization configuration
82
70
  # {http://www.rubydoc.info/gems/websocket-driver/0.3.5/WebSocket/Driver WebSocket::Driver} interface
83
71
  def url
84
- URI(client.endpoint).tap do |endpoint|
85
- endpoint.query = URI.encode_www_form(client.auth.auth_params.merge(
86
- timestamp: as_since_epoch(Time.now),
87
- format: client.protocol,
88
- echo: client.echo_messages
89
- ))
90
- end.to_s
72
+ @url
91
73
  end
92
74
 
93
75
  # {http://www.rubydoc.info/gems/websocket-driver/0.3.5/WebSocket/Driver WebSocket::Driver} interface
@@ -101,9 +83,44 @@ module Ably::Realtime
101
83
  !connecting? && !connected?
102
84
  end
103
85
 
86
+ # @!attribute [r] __incoming_protocol_msgbus__
87
+ # @return [Ably::Util::PubSub] Websocket Transport internal incoming protocol message bus
88
+ # @api private
89
+ def __incoming_protocol_msgbus__
90
+ @__incoming_protocol_msgbus__ ||= create_pub_sub_message_bus
91
+ end
92
+
93
+ # @!attribute [r] __outgoing_protocol_msgbus__
94
+ # @return [Ably::Util::PubSub] Websocket Transport internal outgoing protocol message bus
95
+ # @api private
96
+ def __outgoing_protocol_msgbus__
97
+ @__outgoing_protocol_msgbus__ ||= create_pub_sub_message_bus
98
+ end
99
+
104
100
  private
105
101
  attr_reader :connection, :driver
106
102
 
103
+ # Send object down the WebSocket driver connection as a serialized string/byte array based on protocol
104
+ # @param [Object] object to serialize and send to the WebSocket driver
105
+ # @api public
106
+ def send_object(object)
107
+ case client.protocol
108
+ when :json
109
+ driver.text(object.to_json)
110
+ when :msgpack
111
+ driver.binary(object.to_msgpack.unpack('C*'))
112
+ else
113
+ client.logger.fatal "WebsocketTransport: Unsupported protocol '#{client.protocol}' for serialization, object cannot be serialized and sent to Ably over this WebSocket"
114
+ end
115
+ end
116
+
117
+ def setup_event_handlers
118
+ __outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
119
+ send_object protocol_message
120
+ client.logger.debug "WebsocketTransport: Prot msg sent =>: #{protocol_message.action} #{protocol_message}"
121
+ end
122
+ end
123
+
107
124
  def clear_timer
108
125
  if @timer
109
126
  @timer.cancel
@@ -121,17 +138,18 @@ module Ably::Realtime
121
138
  @driver = WebSocket::Driver.client(self)
122
139
 
123
140
  driver.on("open") do
124
- logger.debug "WebSocket connection opened to #{url}, waiting for Connected protocol message"
141
+ logger.debug "WebsocketTransport: socket opened to #{url}, waiting for Connected protocol message"
125
142
  end
126
143
 
127
144
  driver.on("message") do |event|
128
145
  event_data = parse_event_data(event.data).freeze
129
146
  protocol_message = Ably::Models::ProtocolMessage.new(event_data)
130
- logger.debug "Prot msg recv <=: #{protocol_message.action} #{event_data}"
147
+ logger.debug "WebsocketTransport: Prot msg recv <=: #{protocol_message.action} #{event_data}"
148
+
131
149
  if protocol_message.invalid?
132
- logger.error "Invalid Protocol Message received: #{event_data}\nNo action taken"
150
+ logger.fatal "WebsocketTransport: Invalid Protocol Message received: #{event_data}\nNo action taken"
133
151
  else
134
- connection.__incoming_protocol_msgbus__.publish :message, protocol_message
152
+ __incoming_protocol_msgbus__.publish :protocol_message, protocol_message
135
153
  end
136
154
  end
137
155
  end
@@ -150,12 +168,21 @@ module Ably::Realtime
150
168
  when :json
151
169
  JSON.parse(data)
152
170
  when :msgpack
153
- MessagePack.unpack(data.pack('c*'))
171
+ MessagePack.unpack(data.pack('C*'))
154
172
  else
155
- client.logger.error "Unsupported Protocol Message format #{client.protocol}"
173
+ client.logger.fatal "WebsocketTransport: Unsupported Protocol Message format #{client.protocol}"
156
174
  data
157
175
  end
158
176
  end
177
+
178
+ def create_pub_sub_message_bus
179
+ Ably::Util::PubSub.new(
180
+ coerce_into: Proc.new do |event|
181
+ raise KeyError, "Expected :protocol_message, :#{event} is disallowed" unless event == :protocol_message
182
+ :protocol_message
183
+ end
184
+ )
185
+ end
159
186
  end
160
187
  end
161
188
  end
@@ -1,4 +1,4 @@
1
- module Ably::Models
1
+ module Ably::Realtime::Models
2
2
  # Nil object for Channels, this object is only used within the internal API of this client library
3
3
  class NilChannel
4
4
  include Ably::Modules::EventEmitter
@@ -17,13 +17,19 @@ module Ably::Realtime
17
17
  # {Ably::Realtime::Channel} this Presence object is assoicated with
18
18
  attr_reader :channel
19
19
 
20
+ # A unique member identifier for this channel client, disambiguating situations where a given
21
+ # client_id is present on multiple connections simultaneously.
22
+ # TODO: This does not work at present as no ACK is sent from the server with a memberId
23
+ attr_reader :member_id
24
+
20
25
  def initialize(channel)
21
26
  @channel = channel
22
27
  @state = STATE.Initialized
23
28
  @members = Hash.new
24
29
  @subscriptions = Hash.new { |hash, key| hash[key] = [] }
25
30
  @client_id = client.client_id
26
- @client_data = nil
31
+ @data = nil
32
+ @member_id = nil
27
33
 
28
34
  setup_event_handlers
29
35
  end
@@ -31,17 +37,17 @@ module Ably::Realtime
31
37
  # Enter this client into this channel. This client will be added to the presence set
32
38
  # and presence subscribers will see an enter message for this client.
33
39
  # @param [Hash,String] options an options Hash to specify client data and/or client ID, or a String with the client data
34
- # @option options [String] :client_data optional data (eg a status message) for this member
40
+ # @option options [String] :data optional data (eg a status message) for this member
35
41
  # @option options [String] :client_id the optional id of the client.
36
42
  # This option is provided to support connections from server instances that act on behalf of
37
43
  # multiple client_ids. In order to be able to enter the channel with this method, the client
38
44
  # library must have been instanced either with a key, or with a token bound to the wildcard clientId.
39
45
  # @yield [Ably::Realtime::Presence] On success, will call the block with the {Ably::Realtime::Presence}
40
- # @return [Ably::Realtime::PresenceMessage] Deferrable {Ably::Realtime::PresenceMessage} that supports both success (callback) and failure (errback) callbacks
46
+ # @return [Ably::Models::PresenceMessage] Deferrable {Ably::Models::PresenceMessage} that supports both success (callback) and failure (errback) callbacks
41
47
  #
42
48
  def enter(options = {}, &blk)
43
- @client_id = options.fetch(:client_id, client_id)
44
- @client_data = options.fetch(:client_data, client_data)
49
+ @client_id = options.fetch(:client_id, client_id)
50
+ @data = options.fetch(:data, data)
45
51
 
46
52
  raise Ably::Exceptions::Standard.new('Unable to enter presence channel without a client_id', 400, 91000) unless client_id
47
53
 
@@ -57,7 +63,7 @@ module Ably::Realtime
57
63
  change_state STATE.Entering
58
64
  send_presence_protocol_message(Ably::Models::PresenceMessage::ACTION.Enter).tap do |deferrable|
59
65
  deferrable.errback { |message, error| change_state STATE.Failed, error }
60
- deferrable.callback { |message| change_state STATE.Entered }
66
+ deferrable.callback { |message| change_state STATE.Entered, message }
61
67
  end
62
68
  end
63
69
  end
@@ -72,7 +78,7 @@ module Ably::Realtime
72
78
  def leave(options = {}, &blk)
73
79
  raise Ably::Exceptions::Standard.new('Unable to leave presence channel that is not entered', 400, 91002) unless ably_to_leave?
74
80
 
75
- @client_data = options.fetch(:client_data, client_data)
81
+ @data = options.fetch(:data, data)
76
82
 
77
83
  if state == STATE.Left
78
84
  blk.call self if block_given?
@@ -100,12 +106,12 @@ module Ably::Realtime
100
106
  # @return (see Presence#enter)
101
107
  #
102
108
  def update(options = {}, &blk)
103
- @client_data = options.fetch(:client_data, client_data)
109
+ @data = options.fetch(:data, data)
104
110
 
105
111
  ensure_channel_attached do
106
112
  send_presence_protocol_message(Ably::Models::PresenceMessage::ACTION.Update).tap do |deferrable|
107
113
  deferrable.callback do |message|
108
- change_state STATE.Entered unless entered?
114
+ change_state STATE.Entered, message unless entered?
109
115
  blk.call self if block_given?
110
116
  end
111
117
  end
@@ -148,6 +154,14 @@ module Ably::Realtime
148
154
  end
149
155
  end
150
156
 
157
+ # Return the presence messages history for the channel
158
+ #
159
+ # @param (see Ably::Rest::Presence#history)
160
+ # @option options (see Ably::Rest::Presence#history)
161
+ def history(options = {})
162
+ rest_presence.history(options)
163
+ end
164
+
151
165
  # @!attribute [r] __incoming_msgbus__
152
166
  # @return [Ably::Util::PubSub] Client library internal channel incoming message bus
153
167
  # @api private
@@ -158,7 +172,7 @@ module Ably::Realtime
158
172
  end
159
173
 
160
174
  private
161
- attr_reader :members, :subscriptions, :client_id, :client_data
175
+ attr_reader :members, :subscriptions, :client_id, :data
162
176
 
163
177
  def ably_to_leave?
164
178
  entering? || entered?
@@ -166,7 +180,9 @@ module Ably::Realtime
166
180
 
167
181
  def setup_event_handlers
168
182
  __incoming_msgbus__.subscribe(:presence) do |presence|
183
+ presence.decode self.channel
169
184
  update_members_from_presence_message presence
185
+
170
186
  subscriptions[:all].each { |cb| cb.call(presence) }
171
187
  subscriptions[presence.action].each { |cb| cb.call(presence) }
172
188
  end
@@ -182,6 +198,10 @@ module Ably::Realtime
182
198
  channel.on(Channel::STATE.Failed) do
183
199
  change_state STATE.Failed unless left? || initialized?
184
200
  end
201
+
202
+ on(STATE.Entered) do |message|
203
+ @member_id = message.member_id
204
+ end
185
205
  end
186
206
 
187
207
  # @return [Ably::Models::PresenceMessage] presence message is returned allowing callbacks to be added
@@ -207,9 +227,11 @@ module Ably::Realtime
207
227
  action: Ably::Models::PresenceMessage.ACTION(action).to_i,
208
228
  clientId: client_id,
209
229
  }
210
- model.merge!(clientData: client_data) if client_data
230
+ model.merge!(data: data) if data
211
231
 
212
- Ably::Models::PresenceMessage.new(model, nil)
232
+ Ably::Models::PresenceMessage.new(model, nil).tap do |presence_message|
233
+ presence_message.encode self.channel
234
+ end
213
235
  end
214
236
 
215
237
  def update_members_from_presence_message(presence_message)
@@ -253,7 +275,10 @@ module Ably::Realtime
253
275
  channel.client
254
276
  end
255
277
 
256
- # Used by {Ably::Modules::StateEmitter} to debug state changes
278
+ def rest_presence
279
+ client.rest_client.channel(channel.name).presence
280
+ end
281
+
257
282
  # Used by {Ably::Modules::StateEmitter} to debug action changes
258
283
  def logger
259
284
  client.logger
data/lib/ably/rest.rb CHANGED
@@ -1,12 +1,14 @@
1
- require "ably/rest/channel"
2
- require "ably/rest/channels"
3
- require "ably/rest/client"
4
- require "ably/rest/presence"
1
+ require 'ably/rest/channel'
2
+ require 'ably/rest/channels'
3
+ require 'ably/rest/client'
4
+ require 'ably/rest/presence'
5
5
 
6
- Dir.glob(File.expand_path("ably/models/*.rb", File.dirname(__FILE__))).each do |file|
6
+ Dir.glob(File.expand_path("models/*.rb", File.dirname(__FILE__))).each do |file|
7
7
  require file
8
8
  end
9
9
 
10
+ require 'ably/models/message_encoders/base'
11
+
10
12
  module Ably
11
13
  # Rest provides the top-level class to be instanced for the Ably Rest library
12
14
  #