deepstream 0.2.9 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/README.md +16 -6
- data/deepstream.gemspec +6 -3
- data/lib/deepstream/ack_timeout_registry.rb +6 -2
- data/lib/deepstream/async_patch.rb +45 -0
- data/lib/deepstream/client.rb +94 -72
- data/lib/deepstream/event_handler.rb +2 -2
- data/lib/deepstream/helpers.rb +3 -7
- data/lib/deepstream/list.rb +7 -1
- data/lib/deepstream/message.rb +9 -3
- data/lib/deepstream/record.rb +21 -3
- data/lib/deepstream/record_handler.rb +9 -1
- metadata +50 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1be2b492dcd241f1900936f9f0ac7dd9a2e79a899a6e2f629bc5af03034b5c0a
|
4
|
+
data.tar.gz: b0f8c42cafdf5e8ef55bde1ec1453f1e7820f81e223cf1405d5d8928a770ab43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71aa8a2594fc40036928a2427f7d89c23c5a181388c26d93d724c550dc4daba35940dabdaa6b6b9085d404bac1d05d0c313e51f8705bdaec756bd432ffa55237
|
7
|
+
data.tar.gz: d5bf9c8bb2af9df2bcbd4610feb423c534a5333eceb5c92728d059d87dcaae17a13c897ac6c9aca275785f856e63d4149a84713daa464d06f6d435549040dbb0
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# deepstream-ruby
|
2
2
|
|
3
3
|
deepstream.io ruby client
|
4
|
+
deepstream version >5 needed
|
4
5
|
|
5
6
|
[![Gem Version](https://badge.fury.io/rb/deepstream.svg)](http://badge.fury.io/rb/deepstream)
|
6
7
|
[![Gem License](https://img.shields.io/badge/license-Apache-blue.svg)](https://github.com/Currency-One/deepstream-ruby/blob/master/LICENSE)
|
@@ -19,19 +20,16 @@ ds = Deepstream::Client.new('localhost')
|
|
19
20
|
# or
|
20
21
|
ds = Deepstream::Client.new('ws://localhost:6020')
|
21
22
|
# or
|
22
|
-
ds = Deepstream::Client.new('ws://localhost:6020/deepstream',
|
23
|
+
ds = Deepstream::Client.new('ws://localhost:6020/deepstream-v3',
|
23
24
|
ack_timeout: nil, # ACK timeout; if nil, then the client never checks ACK timeout errors
|
24
|
-
autologin: false, # authorise the client when a Websocket connection is initialized; you don't need to call login() then
|
25
25
|
credentials: { username: 'John', password: 'Doe' }, # credentials used to authorise the client
|
26
26
|
heartbeat_interval: nil # when two server heartbeats are missed the client considers the connection to be lost
|
27
|
-
max_reconnect_attempts: nil,
|
28
|
-
max_reconnect_interval: 30, # seconds
|
29
|
-
reconnect_interval: 1, # seconds, the final interval is a lower number from (reconnect_interval * failed_attempts, max_reconnect_interval)
|
30
27
|
emit_timeout: 0, # if 0, then events that failed to be emitted are thrown away
|
31
28
|
# if nil, then events are stored in a buffer, waiting for reconnection
|
32
29
|
# if another number, then events are stored in a buffer and sent if the client reconnects in emit_timeout seconds
|
33
30
|
verbose: false, # show verbose information about connection, incoming and outgoing messages etc.
|
34
|
-
debug: false # use for testing only; if true, any exception will terminate the client
|
31
|
+
debug: false, # use for testing only; if true, any exception will terminate the client
|
32
|
+
in_thread: true # if true, putting client in separated thread
|
35
33
|
)
|
36
34
|
# log in to the server
|
37
35
|
ds.login
|
@@ -82,3 +80,15 @@ foo.keys
|
|
82
80
|
# get records from the list
|
83
81
|
foo.all
|
84
82
|
```
|
83
|
+
|
84
|
+
|
85
|
+
## Development
|
86
|
+
|
87
|
+
```bash
|
88
|
+
git submodule update --init --recursive
|
89
|
+
```
|
90
|
+
|
91
|
+
|
92
|
+
## To Do
|
93
|
+
|
94
|
+
Adjust tests, to work with new version (without celluloid)
|
data/deepstream.gemspec
CHANGED
@@ -4,9 +4,9 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "deepstream"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "1.0.1"
|
8
8
|
spec.authors = ["Currency-One S.A."]
|
9
|
-
spec.email = ["
|
9
|
+
spec.email = ["ruby@currency-one.com"]
|
10
10
|
|
11
11
|
spec.summary = %q{deepstream.io ruby client}
|
12
12
|
spec.description = %q{Basic ruby client for the deepstream.io server}
|
@@ -19,7 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
spec.required_ruby_version = '>= 2.3.0'
|
21
21
|
spec.license = "Apache-2.0"
|
22
|
-
spec.add_runtime_dependency '
|
22
|
+
spec.add_runtime_dependency 'async', '~> 1.28.3'
|
23
|
+
spec.add_runtime_dependency 'async-io', '~> 1.30.1'
|
24
|
+
spec.add_runtime_dependency 'async-http', '~> 0.54.1'
|
25
|
+
spec.add_runtime_dependency 'async-websocket', '~> 0.16.0'
|
23
26
|
spec.add_development_dependency 'cucumber'
|
24
27
|
spec.add_development_dependency 'reel'
|
25
28
|
spec.add_development_dependency 'pry'
|
@@ -7,11 +7,15 @@ module Deepstream
|
|
7
7
|
|
8
8
|
def add(name, message)
|
9
9
|
return unless (timeout = @client.options[:ack_timeout])
|
10
|
-
@timeouts[name] =
|
10
|
+
@timeouts[name] = Thread.new do
|
11
|
+
sleep timeout
|
12
|
+
@client.on_error(message)
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
def cancel(name)
|
14
|
-
@timeouts.
|
17
|
+
@timeouts[name].exit rescue nil
|
18
|
+
@timeouts.delete(name)
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Async
|
2
|
+
module WebSocket
|
3
|
+
class Client < ::Protocol::HTTP::Middleware
|
4
|
+
include ::Protocol::WebSocket::Headers
|
5
|
+
|
6
|
+
def self.connect(endpoint, *args, **options, &block)
|
7
|
+
self.open(endpoint, *args) do |client|
|
8
|
+
connection = client.connect(endpoint.path, **options)
|
9
|
+
|
10
|
+
return connection unless block_given?
|
11
|
+
|
12
|
+
begin
|
13
|
+
yield connection
|
14
|
+
ensure
|
15
|
+
connection.close
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
puts "cant connect to #{endpoint}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Connection < ::Protocol::WebSocket::Connection
|
24
|
+
|
25
|
+
def write(object)
|
26
|
+
super(object)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse(buffer)
|
30
|
+
buffer
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Protocol
|
37
|
+
module WebSocket
|
38
|
+
class TextFrame
|
39
|
+
|
40
|
+
def unpack
|
41
|
+
encoded_readed_string = super.encode(Encoding::UTF_8)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/deepstream/client.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require 'forwardable'
|
2
|
-
require '
|
2
|
+
require 'async'
|
3
|
+
require 'async/io/stream'
|
4
|
+
require 'async/http/endpoint'
|
5
|
+
require 'async/websocket/client'
|
6
|
+
require 'async/logger'
|
3
7
|
require 'deepstream/constants'
|
4
8
|
require 'deepstream/error_handler'
|
5
9
|
require 'deepstream/event_handler'
|
@@ -7,17 +11,14 @@ require 'deepstream/record_handler'
|
|
7
11
|
require 'deepstream/helpers'
|
8
12
|
require 'deepstream/message'
|
9
13
|
require 'deepstream/exceptions'
|
14
|
+
require 'deepstream/async_patch'
|
10
15
|
|
11
16
|
module Deepstream
|
12
17
|
class Client
|
13
18
|
attr_reader :options, :state
|
14
19
|
|
15
|
-
include Celluloid
|
16
|
-
include Celluloid::Internals::Logger
|
17
20
|
extend Forwardable
|
18
21
|
|
19
|
-
execute_block_on_receiver :on, :subscribe, :listen
|
20
|
-
|
21
22
|
def_delegators :@event_handler, :on, :emit, :subscribe, :unsubscribe, :listen, :resubscribe, :unlisten
|
22
23
|
def_delegators :@error_handler, :error, :on_error, :on_exception
|
23
24
|
def_delegators :@record_handler, :get, :get_record, :set, :delete, :discard, :get_list
|
@@ -30,23 +31,22 @@ module Deepstream
|
|
30
31
|
@options = Helpers.default_options.merge!(options)
|
31
32
|
@message_buffer = []
|
32
33
|
@last_hearbeat = nil
|
33
|
-
@challenge_denied,
|
34
|
-
@failed_reconnect_attempts = 0
|
34
|
+
@challenge_denied, @@deliberate_close = false
|
35
35
|
@state = CONNECTION_STATE::CLOSED
|
36
|
-
|
36
|
+
@verbose = @options[:verbose]
|
37
|
+
@log = Async.logger
|
38
|
+
@never_connected_before = true
|
37
39
|
connect
|
38
40
|
end
|
39
41
|
|
40
42
|
def on_open
|
41
|
-
info
|
43
|
+
@log.info "Websocket connection opened" if @verbose
|
42
44
|
@state = CONNECTION_STATE::AWAITING_CONNECTION
|
43
|
-
@connection_requested, @deliberate_close = false
|
44
|
-
@failed_reconnect_attempts = 0
|
45
45
|
end
|
46
46
|
|
47
47
|
def on_message(data)
|
48
48
|
message = Message.new(data)
|
49
|
-
info
|
49
|
+
@log.info "Receiving msg = #{message.inspect}" if @verbose
|
50
50
|
case message.topic
|
51
51
|
when TOPIC::AUTH then authentication_message(message)
|
52
52
|
when TOPIC::CONNECTION then connection_message(message)
|
@@ -54,30 +54,19 @@ module Deepstream
|
|
54
54
|
when TOPIC::ERROR then @error_handler.on_error(message)
|
55
55
|
when TOPIC::RECORD then @record_handler.on_message(message)
|
56
56
|
when TOPIC::RPC then raise(UnknownTopic, 'RPC is currently not implemented.')
|
57
|
+
when nil then nil
|
57
58
|
else raise(UnknownTopic, message)
|
58
59
|
end
|
59
60
|
rescue => e
|
60
61
|
on_exception(e)
|
61
62
|
end
|
62
63
|
|
63
|
-
def on_close(code, reason)
|
64
|
-
info("Websocket connection closed: code - #{code.inspect}, reason - #{reason.inspect}")
|
65
|
-
@state = CONNECTION_STATE::CLOSED
|
66
|
-
reconnect unless @deliberate_close
|
67
|
-
rescue => e
|
68
|
-
on_exception(e)
|
69
|
-
end
|
70
|
-
|
71
64
|
def login(credentials = @options[:credentials])
|
72
|
-
@login_requested = true
|
73
65
|
@options[:credentials] = credentials
|
74
66
|
if @challenge_denied
|
75
67
|
on_error("this client's connection was closed")
|
76
|
-
elsif !connected?
|
77
|
-
async.connect
|
78
68
|
elsif @state == CONNECTION_STATE::AUTHENTICATING
|
79
|
-
@
|
80
|
-
send_message(TOPIC::AUTH, ACTION::REQUEST, @options[:credentials].to_json)
|
69
|
+
send_message(TOPIC::AUTH, ACTION::REQUEST, @options[:credentials].to_json, priority: true)
|
81
70
|
end
|
82
71
|
self
|
83
72
|
rescue => e
|
@@ -87,14 +76,19 @@ module Deepstream
|
|
87
76
|
|
88
77
|
def close
|
89
78
|
return unless connected?
|
90
|
-
@state = CONNECTION_STATE::CLOSED
|
91
79
|
@deliberate_close = true
|
92
|
-
@
|
93
|
-
@connection.terminate
|
80
|
+
log.info 'deliberate closing' if @verbose
|
94
81
|
rescue => e
|
95
82
|
on_exception(e)
|
96
83
|
end
|
97
84
|
|
85
|
+
def reconnect
|
86
|
+
return if connected?
|
87
|
+
@deliberate_close = false
|
88
|
+
@state = CONNECTION_STATE::RECONNECTING
|
89
|
+
@log.info 'Reconnecting' if @verbose
|
90
|
+
end
|
91
|
+
|
98
92
|
def connected?
|
99
93
|
@state != CONNECTION_STATE::CLOSED
|
100
94
|
end
|
@@ -111,26 +105,27 @@ module Deepstream
|
|
111
105
|
"#{self.class} #{@url} | connection state: #{@state}"
|
112
106
|
end
|
113
107
|
|
114
|
-
def send_message(*args)
|
108
|
+
def send_message(*args, **kwargs)
|
115
109
|
message = Message.parse(*args)
|
116
|
-
|
117
|
-
|
118
|
-
|
110
|
+
priority = kwargs[:priority] || false
|
111
|
+
timeout = message.topic == TOPIC::EVENT ? kwargs[:timeout] : nil
|
112
|
+
message.set_timeout(timeout) if timeout
|
113
|
+
return unable_to_send_message(message, priority) if !logged_in? && message.needs_authentication?
|
114
|
+
priority ? @message_buffer.unshift(message) : @message_buffer.push(message)
|
119
115
|
rescue Errno::EPIPE
|
120
|
-
unable_to_send_message(message)
|
116
|
+
unable_to_send_message(message, priority)
|
121
117
|
rescue => e
|
122
118
|
on_exception(e)
|
123
119
|
end
|
124
120
|
|
125
121
|
private
|
126
122
|
|
127
|
-
def unable_to_send_message(message)
|
123
|
+
def unable_to_send_message(message, priority)
|
128
124
|
@state = CONNECTION_STATE::CLOSED if logged_in?
|
129
125
|
unless message.expired?
|
130
|
-
|
131
|
-
|
126
|
+
@log.info("Placing a message #{message.inspect} in the buffer, waiting for authentication") if @verbose
|
127
|
+
priority ? @message_buffer.unshift(message) : @message_buffer.push(message)
|
132
128
|
end
|
133
|
-
async.reconnect if !connected? && !@connection_requested
|
134
129
|
end
|
135
130
|
|
136
131
|
def connection_message(message)
|
@@ -160,7 +155,9 @@ module Deepstream
|
|
160
155
|
|
161
156
|
def on_connection_ack
|
162
157
|
@state = CONNECTION_STATE::AUTHENTICATING
|
163
|
-
|
158
|
+
@message_buffer.delete_if { |msg| msg.action == ACTION::PATCH }
|
159
|
+
@record_handler.reinitialize unless @never_connected_before
|
160
|
+
login
|
164
161
|
end
|
165
162
|
|
166
163
|
def on_ping
|
@@ -169,15 +166,22 @@ module Deepstream
|
|
169
166
|
end
|
170
167
|
|
171
168
|
def on_login
|
169
|
+
@never_connected_before = false
|
172
170
|
@state = CONNECTION_STATE::OPEN
|
173
|
-
@message_buffer.each { |message| send_message(message) unless message.expired? }.clear
|
174
171
|
every(@options[:heartbeat_interval]) { check_heartbeat } if @options[:heartbeat_interval]
|
175
172
|
resubscribe
|
176
173
|
end
|
177
174
|
|
178
175
|
def on_rejection
|
179
176
|
@challenge_denied = true
|
180
|
-
|
177
|
+
on_close
|
178
|
+
end
|
179
|
+
|
180
|
+
def on_close
|
181
|
+
@log.info 'Websocket connection closed' if @verbose
|
182
|
+
@state = CONNECTION_STATE::CLOSED
|
183
|
+
rescue => e
|
184
|
+
on_exception(e)
|
181
185
|
end
|
182
186
|
|
183
187
|
def check_heartbeat
|
@@ -187,46 +191,64 @@ module Deepstream
|
|
187
191
|
end
|
188
192
|
|
189
193
|
def on_redirection(message)
|
190
|
-
|
191
|
-
|
194
|
+
on_close
|
195
|
+
@url = message.data.last
|
192
196
|
end
|
193
197
|
|
194
|
-
def connect(
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
@connection_requested = false
|
201
|
-
reraise ? raise : on_exception(e)
|
198
|
+
def connect(in_thread = @options[:in_thread])
|
199
|
+
if in_thread
|
200
|
+
Thread.start { connection_loop }
|
201
|
+
else
|
202
|
+
connection_loop
|
203
|
+
end
|
202
204
|
end
|
203
205
|
|
204
|
-
def
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
206
|
+
def connection_loop
|
207
|
+
Async do |task|
|
208
|
+
@task = task
|
209
|
+
loop do
|
210
|
+
if @deliberate_close
|
211
|
+
sleep 5
|
212
|
+
next
|
213
|
+
end
|
214
|
+
_connect
|
215
|
+
sleep 5
|
214
216
|
end
|
215
|
-
else
|
216
|
-
@state = CONNECTION_STATE::ERROR
|
217
217
|
end
|
218
|
-
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
|
219
|
-
@failed_reconnect_attempts += 1
|
220
|
-
on_error("Can't connect! Deepstream server unreachable on #{@url}")
|
221
|
-
info("Can't connect. Next attempt in #{reconnect_interval} seconds.")
|
222
|
-
sleep(reconnect_interval)
|
223
|
-
retry
|
224
|
-
rescue => e
|
225
|
-
on_exception(e)
|
226
218
|
end
|
227
219
|
|
228
|
-
def
|
229
|
-
|
220
|
+
def _connect(url = @url)
|
221
|
+
@log.info "Trying to connect to #{url}" if @verbose
|
222
|
+
endpoint = Async::HTTP::Endpoint.parse(url)
|
223
|
+
Async::WebSocket::Client.connect(endpoint) do |connection|
|
224
|
+
on_open
|
225
|
+
@task.async do
|
226
|
+
loop do
|
227
|
+
break if ( connection.closed? || @deliberate_close )
|
228
|
+
while !@message_buffer.empty? && (logged_in? || !@message_buffer[0].needs_authentication?)
|
229
|
+
msg = @message_buffer.shift
|
230
|
+
next if message.expired?
|
231
|
+
encoded_msg = msg.to_s.encode(Encoding::UTF_8)
|
232
|
+
@log.info "Sending msg = #{msg.inspect}" if @verbose
|
233
|
+
connection.write(encoded_msg)
|
234
|
+
connection.flush rescue @message_buffer.unshift(msg)
|
235
|
+
end
|
236
|
+
@task.sleep 0.001
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
loop do
|
241
|
+
on_message(connection.read)
|
242
|
+
break if ( connection.closed? || @deliberate_close )
|
243
|
+
end
|
244
|
+
|
245
|
+
rescue => e
|
246
|
+
@log.error "Connection error #{e.message}"
|
247
|
+
on_exception(e)
|
248
|
+
ensure
|
249
|
+
connection.close
|
250
|
+
end
|
251
|
+
on_close
|
230
252
|
end
|
231
253
|
end
|
232
254
|
end
|
@@ -14,7 +14,7 @@ module Deepstream
|
|
14
14
|
|
15
15
|
def on(event, &block)
|
16
16
|
unless @callbacks[event]
|
17
|
-
@client.send_message(TOPIC::EVENT, ACTION::SUBSCRIBE, event)
|
17
|
+
@client.send_message(TOPIC::EVENT, ACTION::SUBSCRIBE, event) if @client.state == CONNECTION_STATE::OPEN
|
18
18
|
@ack_timeout_registry.add(event, "No ACK message received in time for #{event}")
|
19
19
|
end
|
20
20
|
@callbacks[event] = block
|
@@ -75,7 +75,7 @@ module Deepstream
|
|
75
75
|
|
76
76
|
def fire_event_callback(message)
|
77
77
|
event, data = message.data
|
78
|
-
|
78
|
+
@callbacks[event].call(Helpers.to_type(data))
|
79
79
|
end
|
80
80
|
|
81
81
|
def fire_listen_callback(message)
|
data/lib/deepstream/helpers.rb
CHANGED
@@ -4,7 +4,7 @@ module Deepstream
|
|
4
4
|
module Helpers
|
5
5
|
SCHEME = 'ws://'
|
6
6
|
DEFAULT_PORT = 6020
|
7
|
-
DEFAULT_PATH = 'deepstream'
|
7
|
+
DEFAULT_PATH = 'deepstream-v3'
|
8
8
|
|
9
9
|
def self.to_deepstream_type(value)
|
10
10
|
case value
|
@@ -34,13 +34,9 @@ module Deepstream
|
|
34
34
|
def self.default_options
|
35
35
|
{
|
36
36
|
ack_timeout: nil,
|
37
|
-
autologin: true,
|
38
37
|
credentials: {},
|
39
38
|
heartbeat_interval: nil,
|
40
|
-
|
41
|
-
max_reconnect_interval: 30,
|
42
|
-
reconnect_interval: 1,
|
43
|
-
emit_timeout: 0,
|
39
|
+
in_thread: true,
|
44
40
|
verbose: false,
|
45
41
|
debug: false
|
46
42
|
}
|
@@ -48,7 +44,7 @@ module Deepstream
|
|
48
44
|
|
49
45
|
def self.url(url)
|
50
46
|
url.tap do |url|
|
51
|
-
url.prepend(SCHEME) unless url.start_with?(
|
47
|
+
url.prepend(SCHEME) unless url.start_with?(/ws(s|)\:\/\//)
|
52
48
|
url.concat(":#{DEFAULT_PORT}") unless url[/\:\d+/]
|
53
49
|
url.concat("/#{DEFAULT_PATH}") unless url[/\/\w+$/]
|
54
50
|
end
|
data/lib/deepstream/list.rb
CHANGED
@@ -21,7 +21,7 @@ module Deepstream
|
|
21
21
|
data = JSON.parse(data)
|
22
22
|
if data.is_a?(Array)
|
23
23
|
@data.concat(data).uniq!
|
24
|
-
set
|
24
|
+
set if @data.size > data.size
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -37,6 +37,12 @@ module Deepstream
|
|
37
37
|
@data.map { |record_name| @client.get(record_name) }
|
38
38
|
end
|
39
39
|
|
40
|
+
def end_reinitializing
|
41
|
+
reset_version
|
42
|
+
set
|
43
|
+
@is_reinitializing = false
|
44
|
+
end
|
45
|
+
|
40
46
|
private
|
41
47
|
|
42
48
|
def set
|
data/lib/deepstream/message.rb
CHANGED
@@ -9,18 +9,24 @@ module Deepstream
|
|
9
9
|
args.first.is_a?(self) ? args.first : new(*args)
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize(*args
|
12
|
+
def initialize(*args)
|
13
13
|
if args.one?
|
14
14
|
args = args.first.delete(MESSAGE_SEPARATOR).split(MESSAGE_PART_SEPARATOR)
|
15
15
|
end
|
16
|
-
@sending_deadline =
|
16
|
+
@sending_deadline = nil
|
17
17
|
@topic, @action = args.take(2).map(&:to_sym)
|
18
18
|
@data = args.drop(2)
|
19
|
+
rescue
|
20
|
+
''
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_timeout(timeout)
|
24
|
+
@sending_deadline = Time.now + timeout
|
19
25
|
end
|
20
26
|
|
21
27
|
def to_s
|
22
28
|
args = [@topic, @action]
|
23
|
-
args << @data unless @data.empty?
|
29
|
+
args << @data unless (@data.nil? || @data.empty?)
|
24
30
|
args.join(MESSAGE_PART_SEPARATOR).concat(MESSAGE_SEPARATOR)
|
25
31
|
end
|
26
32
|
|
data/lib/deepstream/record.rb
CHANGED
@@ -9,11 +9,29 @@ module Deepstream
|
|
9
9
|
@name = name
|
10
10
|
@data = {}
|
11
11
|
@version = nil
|
12
|
+
@is_reinitializing = false
|
13
|
+
@data_cache = {}
|
12
14
|
@client.send_message(TOPIC::RECORD, ACTION::CREATEORREAD, @name)
|
13
15
|
end
|
14
16
|
|
15
|
-
def
|
16
|
-
@
|
17
|
+
def reset_version
|
18
|
+
@version = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_reinitializing?
|
22
|
+
@is_reinitializing
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_reinitializing
|
26
|
+
@is_reinitializing = true
|
27
|
+
@data_cache = @data
|
28
|
+
@client.send_message(TOPIC::RECORD, ACTION::CREATEORREAD, @name, priority: true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def end_reinitializing
|
32
|
+
reset_version
|
33
|
+
set(@data_cache)
|
34
|
+
@is_reinitializing = false
|
17
35
|
end
|
18
36
|
|
19
37
|
def inspect
|
@@ -62,7 +80,7 @@ module Deepstream
|
|
62
80
|
|
63
81
|
def method_missing(name, *args)
|
64
82
|
name = name.to_s
|
65
|
-
return @data.fetch(name, nil) if args.empty?
|
83
|
+
return @data.fetch(@data.is_a?(Array) ? name.to_i : name, nil) if args.empty?
|
66
84
|
return set(name[0..-2], *args) if name.end_with?('=') && !args.empty?
|
67
85
|
raise(NoMethodError, name)
|
68
86
|
end
|
@@ -10,6 +10,13 @@ module Deepstream
|
|
10
10
|
@records = {}
|
11
11
|
end
|
12
12
|
|
13
|
+
def reinitialize
|
14
|
+
@records.map do |record|
|
15
|
+
name, rec = record
|
16
|
+
rec.start_reinitializing
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
13
20
|
def on_message(message)
|
14
21
|
case message.action
|
15
22
|
when ACTION::ACK then nil
|
@@ -21,7 +28,7 @@ module Deepstream
|
|
21
28
|
end
|
22
29
|
|
23
30
|
def get(name, list: nil)
|
24
|
-
name = name.to_s
|
31
|
+
name = name.dup.to_s
|
25
32
|
if list
|
26
33
|
name.prepend("#{list}/")
|
27
34
|
@records[list] ||= List.new(@client, list)
|
@@ -55,6 +62,7 @@ module Deepstream
|
|
55
62
|
|
56
63
|
def read(message)
|
57
64
|
name, *data = message.data
|
65
|
+
return @records[name].end_reinitializing if @records[name]&.is_reinitializing?
|
58
66
|
@records[name]&.read(*data)
|
59
67
|
end
|
60
68
|
|
metadata
CHANGED
@@ -1,29 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deepstream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Currency-One S.A.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: async
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.28.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.28.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: async-io
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.30.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.30.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: async-http
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.54.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.54.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: async-websocket
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.16.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.16.0
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: cucumber
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,7 +138,7 @@ dependencies:
|
|
96
138
|
version: '0'
|
97
139
|
description: Basic ruby client for the deepstream.io server
|
98
140
|
email:
|
99
|
-
-
|
141
|
+
- ruby@currency-one.com
|
100
142
|
executables: []
|
101
143
|
extensions: []
|
102
144
|
extra_rdoc_files: []
|
@@ -110,6 +152,7 @@ files:
|
|
110
152
|
- deepstream.gemspec
|
111
153
|
- lib/deepstream.rb
|
112
154
|
- lib/deepstream/ack_timeout_registry.rb
|
155
|
+
- lib/deepstream/async_patch.rb
|
113
156
|
- lib/deepstream/client.rb
|
114
157
|
- lib/deepstream/constants.rb
|
115
158
|
- lib/deepstream/error_handler.rb
|
@@ -139,8 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
182
|
- !ruby/object:Gem::Version
|
140
183
|
version: '0'
|
141
184
|
requirements: []
|
142
|
-
|
143
|
-
rubygems_version: 2.6.8
|
185
|
+
rubygems_version: 3.0.3
|
144
186
|
signing_key:
|
145
187
|
specification_version: 4
|
146
188
|
summary: deepstream.io ruby client
|