ducts-client 0.2.0 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4c3b4b409de5782a0a17ff6be86f8a2a567508f7c6ac3c0baf6f4c0808301c2
4
- data.tar.gz: 628e413f6fe4399fb51c288850a36503b62e9ce810114bbf93d6cea8b9c479f9
3
+ metadata.gz: 74c85c4fbbb4e225d647251a22a526545a3f4921b88921fb6fb779705b1fe4f1
4
+ data.tar.gz: f5396e8363fb5c31159be810b0631d45bfaca068143f136beb8a52e82f54ba93
5
5
  SHA512:
6
- metadata.gz: caa94df4e3324917d66e1186dd158c8acf964eb5325f485e158ed5b1eee597d57ff5faef95dde812fe7a1d40a758a077f2cd8852c2f784657c9e9562861eced3
7
- data.tar.gz: 06111104f2f3a82de9586f57551de285f810a06b54034642638822087b3044edfc3db69cb5d89be420a0272a95da5c8aed53939f571f5febdb8d26b18f79e001
6
+ metadata.gz: 2627825a0174c77e7070ae62a57bd6a74563fc35fb2882bc53fcee11434cb3341145c4735fc2deb7c2fc88bb5f624a776bff7e3110d0ca273b3fc93784882fb3
7
+ data.tar.gz: 040e53690914465287f0f59e275f9711454c46994cef7aaa68c9687c9e2d87e6d53bb31500aff28fa73aee1315581738dab025bc80ac06519838b24bdd72217e
data/lib/ducts/client.rb CHANGED
@@ -6,6 +6,7 @@ require 'timeout'
6
6
  require 'uri'
7
7
  require 'net/http'
8
8
  require 'json'
9
+ require 'stringio'
9
10
  require 'faye/websocket'
10
11
  require 'faye/websocket/api/event'
11
12
  require 'msgpack'
@@ -56,6 +57,8 @@ module Ducts
56
57
  end
57
58
  end
58
59
 
60
+ DuctEventHandlerReturnValue = Struct.new(:source_rid, :source_eid, :source_data)
61
+
59
62
  class ConnectionEventListener < DuctEventListener
60
63
  attr_writer :onopen, :onclose, :onerror, :onmessage
61
64
  def onopen(event)
@@ -118,7 +121,10 @@ module Ducts
118
121
 
119
122
  @_last_rid = nil
120
123
  @_ws = nil
121
- @_waiting_completion = Hash.new
124
+ @_waiting_message_completion = Hash.new
125
+ @_waiting_closed_completion = Array.new
126
+ @_loop_queues = Hash.new
127
+ @_divided_buffers = Hash.new
122
128
  end
123
129
 
124
130
  def next_rid
@@ -130,29 +136,13 @@ module Ducts
130
136
  next_id
131
137
  end
132
138
 
133
- def open(wsd_url, uuid = nil, **params)
134
- _open(wsd_url, uuid, **params)
135
- end
136
-
137
- def reconnect
138
- _reconnect
139
- end
140
-
141
- def event_send(rid, eid, data)
142
- _send(rid, eid, data)
143
- end
144
-
145
- def event_call(eid, data)
146
- _call(eid, data)
147
- end
148
-
149
- def close
150
- _close
151
- end
152
-
153
139
  def set_event_handler(event_id, &handler)
154
140
  @_event_handler ||= {}
155
- @_event_handler[event_id] = handler
141
+ if handler
142
+ @_event_handler.store(event_id, handler)
143
+ else
144
+ @_event_handler.delete(event_id)
145
+ end
156
146
  end
157
147
 
158
148
  def state
@@ -163,16 +153,16 @@ module Ducts
163
153
  end
164
154
  end
165
155
 
166
- private
167
- def _reconnect(wsd)
168
- if wsd
169
- @WSD = wsd
170
- @EVENT = @WSD['EVENT']
156
+ def reconnect
157
+ completion = EM::Completion.new
158
+ if @_ws
159
+ completion.succeed(self)
160
+ return completion;
171
161
  end
172
- return if @_ws
173
162
  Faye::WebSocket::Client.new(@WSD['websocket_url_reconnect']).tap do |ws|
174
163
  ws.on(:open) do |event|
175
164
  @_ws = ws
165
+ completion.succeed(self)
176
166
  connection_event = DuctConnectionEvent.new('onopen', event)
177
167
  _onreconnect(connection_event)
178
168
  @connection_listener.onopen(connection_event)
@@ -192,10 +182,15 @@ module Ducts
192
182
  @connection_listener.onerror(connection_event)
193
183
  end
194
184
  end
185
+ completion
195
186
  end
196
187
 
197
- def _open(wsd_url, uuid, **params)
198
- return if @_ws
188
+ def open(wsd_url, uuid = nil, **params)
189
+ completion = EM::Completion.new
190
+ if @_ws
191
+ completion.succeed(self)
192
+ return completion;
193
+ end
199
194
  begin
200
195
  query = '?uuid=' + (uuid || 'dummy') + params.map{ |k, v| "&#{k}=#{v}" }.join
201
196
  uri = URI.parse(wsd_url + query)
@@ -210,6 +205,7 @@ module Ducts
210
205
  Faye::WebSocket::Client.new(@WSD['websocket_url']).tap do |ws|
211
206
  ws.on(:open) do |event|
212
207
  @_ws = ws
208
+ completion.succeed(self)
213
209
  connection_event = DuctConnectionEvent.new('onopen', event)
214
210
  _onopen(connection_event)
215
211
  @connection_listener.onopen(connection_event)
@@ -225,6 +221,19 @@ module Ducts
225
221
  @connection_listener.onerror(connection_event)
226
222
  end
227
223
  ws.on(:close) do |event|
224
+ @_ws = nil
225
+ case event.code
226
+ when 1000
227
+ @_waiting_closed_completion.each do |waiting_closed_completion|
228
+ waiting_closed_completion.succeed(event)
229
+ end
230
+ else
231
+ p event.code
232
+ @_waiting_closed_completion.each do |waiting_closed_completion|
233
+ waiting_closed_completion.fail(event)
234
+ end
235
+ end
236
+ @_waiting_closed_completion.clear
228
237
  connection_event = DuctConnectionEvent.new('onclose', event)
229
238
  @connection_listener.onclose(connection_event)
230
239
  end
@@ -232,62 +241,70 @@ module Ducts
232
241
  rescue => error
233
242
  @connection_listener.onerror(DuctConnectionEvent.new('onerror', error))
234
243
  end
244
+ completion
235
245
  end
236
246
 
247
+ def event_send(rid, eid, data)
248
+ msgpack = [ rid, eid, data ].to_msgpack
249
+ @_ws.send(msgpack.chars.map(&:ord))
250
+ rid
251
+ end
252
+
253
+ def event_call(eid, data)
254
+ rid = next_rid
255
+ event_send(rid, eid, data)
256
+ warn Message.construct(Message::Level::WARNING, 'request ID is duplicated.') if @_waiting_message_completion.keys.include? rid
257
+ EM::Completion.new.tap { |completion| @_waiting_message_completion[rid] = completion }
258
+ end
259
+
260
+ def close
261
+ completion = EM::Completion.new
262
+ if @_ws
263
+ @_ws.close
264
+ @_waiting_closed_completion.push(completion)
265
+ else
266
+ completion.succeed(nil)
267
+ end
268
+ completion
269
+ end
270
+
271
+ private
237
272
  def _onopen(event)
238
273
  @_send_timestamp = Time.now.to_f
239
274
  @_time_offset = 0
240
275
  @_time_latency = 0
241
276
  @_time_count = 0
242
- set_event_handler(@EVENT['ALIVE_MONITORING']) do |rid, eid, data|
243
- client_received = Time.now.to_f
244
- server_sent, server_received = data
245
- client_sent = @_send_timestamp
246
- new_offset = ((server_received - client_sent) - (client_received - server_sent)) / 2
247
- new_latency = ((client_received - client_sent) - (server_sent - server_received)) / 2
248
- @_time_offset = (@_time_offset * @_time_count + new_offset) / (@_time_count + 1)
249
- @_time_latency = (@_time_latency * @_time_count + new_latency) / (@_time_count + 1)
250
- @_time_count += 1
251
- end
277
+ set_event_handler(@EVENT['ALIVE_MONITORING'], &method(:_alive_monitoring_handler))
278
+ set_event_handler(@EVENT['LOOP_RESPONSE_START'], &method(:_loop_response_handler))
279
+ set_event_handler(@EVENT['LOOP_RESPONSE_NEXT'], &method(:_loop_response_handler))
280
+ set_event_handler(@EVENT['LOOP_RESPONSE_END'], &method(:_loop_response_end_handler))
281
+ set_event_handler(@EVENT['DIVIDED_RESPONSE_APPEND'], &method(:_divided_response_append_handler))
282
+ set_event_handler(@EVENT['DIVIDED_RESPONSE_END'], &method(:_divided_response_end_handler))
252
283
  rid = next_rid
253
284
  eid = @EVENT['ALIVE_MONITORING']
254
285
  value = @_send_timestamp
255
- _send(rid, eid, value)
286
+ event_send(rid, eid, value)
256
287
  end
257
288
 
258
289
  def _onreconnect(connection_event)
259
290
  end
260
291
 
261
- def _send(rid, eid, data)
262
- msgpack = [ rid, eid, data ].to_msgpack
263
- @_ws.send(msgpack.chars.map(&:ord))
264
- rid
265
- end
266
-
267
- def _call(eid, data)
268
- rid = next_rid
269
- _send(rid, eid, data)
270
- raise if @_waiting_completion.keys.include? rid
271
- EM::Completion.new.tap { |completion| @_waiting_completion[rid] = completion }
272
- end
273
-
274
- def _close
275
- begin
276
- @_ws.close if @_ws
277
- ensure
278
- @_ws = nil
279
- end
280
- end
281
-
282
292
  def _onmessage(connection_event)
283
293
  begin
284
294
  rid, eid, data = %i(rid eid data).map{ |name| connection_event.source.public_send(name) }
285
295
  begin
286
296
  @catchall_event_handler.call(rid, eid, data)
287
297
  handle = @_event_handler[eid]
288
- handle = @uncaught_event_handler unless handle
289
- handle.call(rid, eid, data)
290
- completion = @_waiting_completion.delete(rid)
298
+ handle ||= @uncaught_event_handler
299
+ handle.call(rid, eid, data).tap do |ret|
300
+ if ret.instance_of? DuctEventHandlerReturnValue
301
+ rid = ret.source_rid
302
+ eid = ret.source_eid
303
+ data = ret.source_data
304
+ end
305
+ end
306
+ return if rid.nil?
307
+ completion = @_waiting_message_completion.delete(rid)
291
308
  if completion
292
309
  if eid > 0
293
310
  completion.succeed(data)
@@ -302,5 +319,63 @@ module Ducts
302
319
  @event_error_handler.call(-1, -1, nil, error)
303
320
  end
304
321
  end
322
+
323
+ def _alive_monitoring_handler(rid, eid, data)
324
+ client_received = Time.now.to_f
325
+ server_sent, server_received = data
326
+ client_sent = @_send_timestamp
327
+ new_offset = ((server_received - client_sent) - (client_received - server_sent)) / 2
328
+ new_latency = ((client_received - client_sent) - (server_sent - server_received)) / 2
329
+ @_time_offset = (@_time_offset * @_time_count + new_offset) / (@_time_count + 1)
330
+ @_time_latency = (@_time_latency * @_time_count + new_latency) / (@_time_count + 1)
331
+ @_time_count += 1
332
+ end
333
+
334
+ def _loop_response_handler(rid, eid, data)
335
+ warn Message.construct(Message::Level::WARNING, 'loop response has error.') if eid.negative?
336
+ source_eid = data[1]
337
+ source_data = data[2]
338
+ @catchall_event_handler.call(rid, source_eid, source_data)
339
+ handle = @_event_handler[source_eid.abs]
340
+ handle ||= @uncaught_event_handler
341
+ ret = handle.call(rid, source_eid, source_data)
342
+ handled_source_data = (ret.instance_of? DuctEventHandlerReturnValue)? ret.source_data : source_data
343
+ @_loop_queues[rid] ||= EM::Queue.new
344
+ queue = @_loop_queues[rid]
345
+ queue.push(handled_source_data) if handled_source_data
346
+ DuctEventHandlerReturnValue.new(rid, source_eid, queue)
347
+ end
348
+
349
+ def _loop_response_end_handler(rid, eid, data)
350
+ warn Message.construct(Message::Level::WARNING, 'loop response end has error.') if eid.negative?
351
+ source_eid = data[1]
352
+ source_data = data[2]
353
+ warn Message.construct(Message::Level::WARNING, "loop response end has data: #{source_data}.") if source_data
354
+ @catchall_event_handler.call(rid, source_eid, source_data)
355
+ handle = @_event_handler[source_eid.abs]
356
+ handle ||= @uncaught_event_handler
357
+ handle.call(rid, source_eid, source_data)
358
+ queue = @_loop_queues.delete(rid)
359
+ queue.push(nil)
360
+ DuctEventHandlerReturnValue.new(rid, source_eid, source_eid)
361
+ end
362
+
363
+ def _divided_response_append_handler(rid, eid, data)
364
+ @_divided_buffers[rid] ||= StringIO.new('', 'wb').set_encoding(Encoding::ASCII_8BIT)
365
+ divided_buffer = @_divided_buffers[rid]
366
+ divided_buffer.write(data)
367
+ DuctEventHandlerReturnValue.new(nil, eid, nil)
368
+ end
369
+
370
+ def _divided_response_end_handler(rid, eid, data)
371
+ divided_buffer = @_divided_buffers.delete(rid)
372
+ divided_buffer.write(data)
373
+ source_rid, source_eid, source_data = MessagePack.unpack(divided_buffer.string)
374
+ @catchall_event_handler.call(source_rid, source_eid, source_data)
375
+ handle = @_event_handler[source_eid]
376
+ handle ||= @uncaught_event_handler
377
+ handle.call(source_rid, source_eid, source_data)
378
+ DuctEventHandlerReturnValue.new(source_rid, source_eid, source_data)
379
+ end
305
380
  end
306
381
  end
@@ -4,8 +4,8 @@ module Ducts
4
4
  class Client
5
5
  module Version
6
6
  MAJOR = 0
7
- MINOR = 2
8
- PATCH = 0
7
+ MINOR = 4
8
+ PATCH = 5
9
9
  end
10
10
 
11
11
  VERSION = [ Version::MAJOR, Version::MINOR, Version::PATCH ].map(&:to_s).join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ducts-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenshiro Ueda
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-21 00:00:00.000000000 Z
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faye-websocket