hakuban 0.5.0 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79db90522bce42223139845bf81169a9e75a2997a90e71952b0b00d852272ff6
4
- data.tar.gz: 35d50834b1a5a2626e9e3ad62c063b04acfc86569f887e57afe2578125d994cc
3
+ metadata.gz: aca4a31cd75c69917785c7d5d3110c9db07d44c9be8394b37714fcae3019b5f6
4
+ data.tar.gz: a3c81f4d62a36fbac4bbdf6cf709909bcc132b4330e62de9b2fb39ddd4e48e72
5
5
  SHA512:
6
- metadata.gz: 5d74f9761c28495c9d6caed241fb907147aff987d8c9d5526ded5d15f6e43ac781354baae9894fc74684ecad374646d8fde4cf90b26550a2e954f6bbf95f5ecb
7
- data.tar.gz: 2c48edc2b71800bf19e3a1f267de234493e1e54aa6ae6fb4042ba1fc79f22a35aa28015e2d0b37f6ddb5c491817cf6698330b609dba96077e6d26ddcd441cb28
6
+ metadata.gz: 3a59840edfda985efda0031603f8901a24026b6edcc044f6ac61f3c04d6e8c4cae9199eb2b10b8496810b4182f85337907ee518f3d136c4a8bb829f10f66eb9d
7
+ data.tar.gz: bf7e24798ea39f0524075fcacc5a47bf8f060d72a797d2b7b92827be1b6cda252df2e8da8e64cd4c8e937b2ef08f5ae21e87ff15e3174ed9164ef2a6b64d7642
data/lib/hakuban/ffi.rb CHANGED
@@ -32,6 +32,7 @@ module Hakuban::FFI
32
32
 
33
33
  class FFIObjectExposeState < FFI::Struct
34
34
  layout :version_length, :size_t, :version, :pointer, :data_type_length, :size_t, :data_type, :pointer, :raw_length, :size_t, :raw, :pointer
35
+ attr_accessor :data_type_strings
35
36
 
36
37
  def self.construct(version, data_type, data)
37
38
  state = FFIObjectExposeState::new
@@ -40,7 +41,8 @@ module Hakuban::FFI
40
41
  state[:version].write_array_of_int64(version)
41
42
  state[:data_type_length] = data_type.size
42
43
  state[:data_type] = FFI::MemoryPointer.new(:pointer, data_type.size)
43
- state[:data_type].write_array_of_pointer(data_type.map {|string| FFI::MemoryPointer.from_string(string)})
44
+ state.data_type_strings = data_type.map {|string| FFI::MemoryPointer.from_string(string)}
45
+ state[:data_type].write_array_of_pointer(state.data_type_strings)
44
46
  state[:raw] = FFI::MemoryPointer.from_string(data)
45
47
  state[:raw_length] = data.size
46
48
  state
@@ -61,7 +63,8 @@ module Hakuban::FFI
61
63
 
62
64
  class FFIObjectDescriptor < FFI::Struct
63
65
  layout :tags_count, :size_t, :tags, :pointer, :json, :pointer
64
-
66
+ attr_accessor :tags_strings
67
+
65
68
  def tags
66
69
  self[:tags].read_array_of_pointer(self[:tags_count]).map { |string| JSON.parse(string.read_string()) } # does this copy the string?
67
70
  end
@@ -71,12 +74,11 @@ module Hakuban::FFI
71
74
  end
72
75
 
73
76
  def self.construct(tags,json)
74
- tags_strings = tags.map { |tag| JSON.dump(tag) }
75
- tags_strings_array = FFI::MemoryPointer.new(:pointer, tags_strings.size)
76
- tags_strings_array.write_array_of_pointer(tags_strings.map {|string| FFI::MemoryPointer.from_string(string)})
77
77
  descriptor = FFIObjectDescriptor.new
78
78
  descriptor[:tags_count] = tags.size
79
- descriptor[:tags] = tags_strings_array
79
+ descriptor.tags_strings = tags.map { |tag| FFI::MemoryPointer.from_string(JSON.dump(tag)) }
80
+ descriptor[:tags] = FFI::MemoryPointer.new(:pointer, descriptor.tags_strings.size)
81
+ descriptor[:tags].write_array_of_pointer(descriptor.tags_strings)
80
82
  descriptor[:json] = FFI::MemoryPointer.from_string(JSON.dump(json))
81
83
  descriptor
82
84
  end
@@ -146,7 +148,9 @@ module Hakuban::FFI
146
148
  attach_function :hakuban_object_callback_unregister, [ :pointer ], :void, blocking: true
147
149
 
148
150
  attach_function :hakuban_tokio_init_multi_thread, [ :size_t ], :pointer
149
- attach_function :hakuban_tokio_websocket_connector_new, [ :pointer, :string ], FFITokioWebsocketConnectorNewResult.by_value
150
- attach_function :hakuban_tokio_websocket_connector_start, [ :pointer, :pointer, :pointer ], :void
151
+ attach_function :hakuban_tokio_websocket_connector_new, [ :pointer, :pointer, :string ], FFITokioWebsocketConnectorNewResult.by_value
152
+ attach_function :hakuban_tokio_websocket_connector_drop, [ :pointer, :pointer ], :void
153
+
154
+ attach_function :hakuban_logger_initialize, [ :string ], :uint8
151
155
 
152
156
  end
@@ -4,6 +4,8 @@ require_relative './ffi.rb'
4
4
 
5
5
  #TODO: explicit drops?
6
6
  #TODO: privative methods
7
+ #TODO: error classes
8
+
7
9
 
8
10
  module Hakuban
9
11
 
@@ -28,6 +30,19 @@ module Hakuban
28
30
  end
29
31
 
30
32
 
33
+ @@logger_initialized = false
34
+
35
+ def self.logger_initialize(default_level, skip_if_already_initialized = false)
36
+ if @@logger_initialized and !skip_if_already_initialized
37
+ raise "Logger already initialized. This can't be done more than once. Make sure logger_initialize is called before any LocalNode gets constructed."
38
+ end
39
+ if not @@logger_initialized
40
+ raise "Invalid default log level string" if FFI::hakuban_logger_initialize(default_level) != 0
41
+ @@logger_initialized = true
42
+ end
43
+ end
44
+
45
+
31
46
  class LocalNode
32
47
 
33
48
  #TODO: explicit drop
@@ -35,7 +50,8 @@ module Hakuban
35
50
  attr_reader :local_node_pointer #todo: hide
36
51
 
37
52
  def initialize(name=nil)
38
- result = FFI::hakuban_local_node_new(name || "local")
53
+ Hakuban::logger_initialize("hakuban=warn", true)
54
+ result = FFI::hakuban_local_node_new(name || File.basename(caller_locations(0..1)[1].path))
39
55
  Hakuban::raise_if_error(result)
40
56
  @local_node_pointer = ::FFI::AutoPointer.new(result[:local_node_pointer], FFI::method(:hakuban_local_node_drop))
41
57
  end
@@ -111,6 +127,11 @@ module Hakuban
111
127
  def hash
112
128
  [@tags.hash, @json.hash].hash
113
129
  end
130
+
131
+ def inspect
132
+ "#<ObjectDescriptor @tags={%s}, @json=%p>"%[self.tags.map(&:inspect).join(","), self.json]
133
+ end
134
+
114
135
  end
115
136
 
116
137
 
@@ -213,12 +234,13 @@ module Hakuban
213
234
  def drop
214
235
  @object_observe_pointer.free
215
236
  @object_observe_pointer = nil
216
- @queues.values.each { |pointer| pointer.free }
217
237
  @queues.clear
218
238
  end
219
239
 
220
- def manage(object_class, *object_constructor_params)
221
- object_class::new(self, @descriptor, *object_constructor_params)
240
+ def manage(manager=nil)
241
+ manager ||= ObjectManager.new
242
+ manager.contract = self
243
+ manager
222
244
  end
223
245
 
224
246
  end
@@ -264,15 +286,20 @@ module Hakuban
264
286
  @queues.delete(queue)
265
287
  end
266
288
 
289
+ def inspect
290
+ "#<ObjectExpose #{@descriptor}>"
291
+ end
292
+
267
293
  def drop
268
294
  @object_expose_pointer.free
269
295
  @object_expose_pointer = nil
270
- @queues.values.each { |pointer| pointer.free }
271
296
  @queues.clear
272
297
  end
273
298
 
274
- def manage(object_class, *object_constructor_params)
275
- object_class::new(self, @descriptor, *object_constructor_params)
299
+ def manage(manager=nil)
300
+ manager ||= ObjectManager.new
301
+ manager.contract = self
302
+ manager
276
303
  end
277
304
 
278
305
  end
@@ -280,7 +307,7 @@ module Hakuban
280
307
 
281
308
  class ObjectObserveState
282
309
 
283
- attr_reader :data, :data_type, :data_version
310
+ attr_reader :data, :data_type, :data_version, :synchronized
284
311
 
285
312
  def initialize(raw_state)
286
313
  @raw_state = raw_state
@@ -302,7 +329,7 @@ module Hakuban
302
329
  end
303
330
 
304
331
  def inspect
305
- "#<ObjectObserveState version=#{@data_version}>"
332
+ "#<ObjectObserveState @synchronized=%p @version=%p>"%[@synchronized, @data_version]
306
333
  end
307
334
 
308
335
  end
@@ -357,12 +384,13 @@ module Hakuban
357
384
  def drop
358
385
  @tag_observe_pointer.free
359
386
  @tag_observe_pointer = nil
360
- @queues.values.each { |pointer| pointer.free }
361
387
  @queues.clear
362
388
  end
363
389
 
364
- def manage(object_class, *object_constructor_params)
365
- ObjectManager::new(self, object_class, *object_constructor_params)
390
+ def manage(manager=nil)
391
+ manager ||= ObjectManager.new
392
+ manager.contract = self
393
+ manager
366
394
  end
367
395
 
368
396
  end
@@ -418,12 +446,13 @@ module Hakuban
418
446
  def drop
419
447
  @tag_expose_pointer.free
420
448
  @tag_expose_pointer = nil
421
- @queues.values.each { |pointer| pointer.free }
422
449
  @queues.clear
423
450
  end
424
451
 
425
- def manage(object_class, *object_constructor_params)
426
- ObjectManager::new(self, object_class, *object_constructor_params)
452
+ def manage(manager=nil)
453
+ manager ||= ObjectManager.new
454
+ manager.contract = self
455
+ manager
427
456
  end
428
457
 
429
458
  end
@@ -452,10 +481,10 @@ module Hakuban
452
481
 
453
482
  #TODO: drop
454
483
 
455
- def initialize(url)
456
- result = FFI::hakuban_tokio_websocket_connector_new(Tokio.pointer, url)
484
+ def initialize(local_node, url)
485
+ result = FFI::hakuban_tokio_websocket_connector_new(Tokio.pointer, local_node.local_node_pointer, url)
457
486
  Hakuban::raise_if_error(result)
458
- @websocket_connector_pointer = result[:websocket_connector_pointer]
487
+ @websocket_connector_pointer = ::FFI::AutoPointer.new(result[:websocket_connector_pointer], WebsocketConnector.generate_drop)
459
488
  end
460
489
 
461
490
  def start(local_node)
@@ -464,38 +493,99 @@ module Hakuban
464
493
  self
465
494
  end
466
495
 
496
+ def self.generate_drop
497
+ proc { |pointer|
498
+ FFI::hakuban_tokio_websocket_connector_drop(Tokio.pointer, pointer)
499
+ }
500
+ end
501
+
467
502
  end
468
503
 
469
504
 
470
505
  # convenience utils
471
506
 
472
- class ObjectManager
507
+ #TODO: replace this mess (<Hash, dynamic mixings) with some "deref"
508
+ class ObjectManager < Hash
509
+
510
+ module ObservedObjectManager
511
+ def descriptor; self.values.first.descriptor; end
512
+ def state; self.values.first.state; end
513
+ def data; self.values.first.data; end
514
+ def version; self.values.first.verison; end
515
+ def synchronized; self.values.first.synchronized; end
516
+ def construct_object(contract, descriptor); ObservedObject.new(contract, descriptor); end
517
+ end
518
+
519
+ module ExposedObjectManager
520
+ def descriptor; self.values.first.descriptor; end
521
+ def state=(params); self.values.first.state = params; end
522
+ def data=(params); self.values.first.data = params; end
523
+ def state_set(params); self.values.first.state_set(params); end
524
+ def data_set(params); self.values.first.data_set(params); end
525
+ def construct_object(contract, descriptor); ExposedObject.new(contract, descriptor); end
526
+ end
527
+
528
+ module ObservedTagManager
529
+ def construct_object(contract, descriptor); ObservedObject.new(contract, descriptor); end
530
+ end
531
+
532
+ module ExposedTagManager
533
+ def construct_object(contract, descriptor); ExposedObject.new(contract, descriptor); end
534
+ end
473
535
 
474
536
  attr_reader :objects, :contract
475
537
 
476
- def initialize(contract, object_class, *object_constructor_params)
538
+ def contract=(contract)
539
+ raise "You can't change contracts, sorry." if @contract
477
540
  @contract = contract
478
- @objects = {}
541
+ case @contract.class.name
542
+ when "Hakuban::ObjectObserve" then singleton_class.include(ObservedObjectManager)
543
+ when "Hakuban::ObjectExpose" then singleton_class.include(ExposedObjectManager)
544
+ when "Hakuban::TagObserve" then singleton_class.include(ObservedTagManager)
545
+ when "Hakuban::TagExpose" then singleton_class.include(ExposedTagManager)
546
+ else raise
547
+ end
548
+
479
549
  @queue = Queue.new
480
- contract.send_events_to(@queue, :object)
550
+ @contract.send_events_to(@queue, :object)
551
+ if @contract.kind_of?(ObjectObserve) or @contract.kind_of?(ObjectExpose)
552
+ event, param, descriptor = @queue.pop
553
+ raise if event != :object or param != :insert or not descriptor
554
+ self[descriptor] = self.construct_object(@contract, descriptor)
555
+ end
556
+
481
557
  @thread = Thread.new {
482
558
  loop {
483
- event = @queue.shift
484
- case event[0..1]
559
+ event,param,descriptor = @queue.shift
560
+ case [event, param]
485
561
  when [:control, :quit]
486
562
  break
487
563
  when [:object, :insert]
488
- @objects[event[2]] = object_class.new(@contract, event[2], *object_constructor_params)
564
+ self[descriptor] = construct_object(@contract, descriptor)
565
+ object_insert(self[descriptor])
489
566
  when [:object, :change]
490
- @objects[event[2]].change if @objects[event[2]].respond_to?(:change)
567
+ object_change(self[descriptor])
491
568
  when [:object, :remove]
492
- raise if not deleted = @objects.delete(event[2])
493
- deleted.drop if deleted.respond_to?(:drop)
569
+ object_remove(delete(descriptor))
494
570
  end
495
571
  }
496
572
  }
497
573
  end
498
574
 
575
+
576
+ def object_insert(object)
577
+ # noop default
578
+ end
579
+
580
+ def object_change(object)
581
+ # noop default
582
+ end
583
+
584
+ def object_remove(object)
585
+ # noop default
586
+ end
587
+
588
+
499
589
  def drop
500
590
  @contract.stop_sending_objects_events_to(@queue)
501
591
  @queue.push [:control, :quit]
@@ -509,11 +599,10 @@ module Hakuban
509
599
  def initialize(contract, descriptor)
510
600
  @contract, @descriptor = contract, descriptor
511
601
  end
512
- end
513
-
602
+ end
514
603
 
515
- #TODO: fix the arity thing...
516
- module ObservedObject
604
+ #TODO: remove the arity thing...
605
+ class ObservedObject < ManagedObject
517
606
  def state
518
607
  if @contract.method(:object_state).arity == 1
519
608
  @contract.object_state(@descriptor)
@@ -530,22 +619,28 @@ module Hakuban
530
619
  end
531
620
  end
532
621
 
533
- module ExposedObject
534
- def state=(state)
622
+ class ExposedObject < ManagedObject
623
+ def state_set(state)
535
624
  if @contract.method(:set_object_state).arity == 4
536
625
  @contract.set_object_state(@descriptor, *state)
537
626
  else
538
627
  @contract.set_object_state(*state)
539
628
  end
540
629
  end
541
- def data=(value)
542
- timestamp = Time.new.to_f.floor
630
+ def state=(state)
631
+ state_set(state)
632
+ end
633
+ def data_set(value)
634
+ timestamp = Time.new.to_f
543
635
  if @contract.method(:set_object_state).arity == 4
544
636
  @contract.set_object_state(@descriptor,[1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
545
637
  else
546
638
  @contract.set_object_state([1, timestamp.floor, ((timestamp - timestamp.floor)*1000000000).floor, 0],[],value)
547
639
  end
548
640
  end
641
+ def data=(value)
642
+ data_set(value)
643
+ end
549
644
  end
550
645
  end
551
646
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hakuban
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hakuban
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - yunta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-13 00:00:00.000000000 Z
11
+ date: 2021-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec