hakuban 0.6.5 → 0.8.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.
- checksums.yaml +4 -4
- data/bin/{hakuban-thread-engine → hakuban-engine} +12 -11
- data/bin/hakuban-observe +61 -0
- data/lib/hakuban/contract.rb +148 -0
- data/lib/hakuban/descriptor.rb +85 -0
- data/lib/hakuban/engine.rb +73 -29
- data/lib/hakuban/exchange.rb +115 -0
- data/lib/hakuban/ffi-object.rb +123 -0
- data/lib/hakuban/ffi.rb +133 -150
- data/lib/hakuban/logger.rb +16 -0
- data/lib/hakuban/object_state.rb +105 -0
- data/lib/hakuban/object_state_sink.rb +56 -0
- data/lib/hakuban/object_state_stream.rb +39 -0
- data/lib/hakuban/refinements.rb +23 -0
- data/lib/hakuban/stream.rb +189 -0
- data/lib/hakuban/tokio-websocket-connector.rb +39 -0
- data/lib/hakuban/version.rb +1 -1
- data/lib/hakuban.rb +21 -6
- metadata +40 -20
- data/bin/hakuban-observer +0 -64
- data/lib/hakuban/async.rb +0 -38
- data/lib/hakuban/event-queue.rb +0 -75
- data/lib/hakuban/hakuban.rb +0 -545
- data/lib/hakuban/manager.rb +0 -398
- data/lib/hakuban/thread.rb +0 -35
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'hakuban/refinements'
|
2
|
+
|
3
|
+
#TODO: bring back Async variants
|
4
|
+
|
5
|
+
module Hakuban
|
6
|
+
|
7
|
+
module Stream
|
8
|
+
|
9
|
+
using ThreadExt
|
10
|
+
|
11
|
+
class NextItemInterrupt < Exception
|
12
|
+
def ==(other)
|
13
|
+
other.object_id == self.object_id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# next may be called in CLI context, so, every return branch should process interrupts explicitly
|
19
|
+
private def process_item(future_constructor, item_constructor, &block)
|
20
|
+
Thread.handle_interrupt(Object => :never) do
|
21
|
+
future_pointer = begin
|
22
|
+
with_pointer(&future_constructor)
|
23
|
+
rescue FFIObject::PointerAlreadyDropped
|
24
|
+
Thread.process_interrupts
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
|
28
|
+
result, error = Hakuban::FFI::FFIFuture.await(future_pointer)
|
29
|
+
item = if pointer = result.unwrap
|
30
|
+
item_constructor.call(pointer)
|
31
|
+
end
|
32
|
+
|
33
|
+
raise error if error
|
34
|
+
return item if block.nil?
|
35
|
+
|
36
|
+
if item.nil?
|
37
|
+
Thread.process_interrupts
|
38
|
+
nil
|
39
|
+
else
|
40
|
+
Thread.handle_interrupt(Object => :immediate) {
|
41
|
+
block.call(item)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
ensure
|
46
|
+
item.drop if !!block and !!item
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def each(*args, **kwargs, &block)
|
51
|
+
for_each(*args, **kwargs, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def for_each(*args, **kwargs, &block)
|
55
|
+
if kwargs[:interrupt_on_next]
|
56
|
+
for_each_till_next(*args, **kwargs, &block)
|
57
|
+
else
|
58
|
+
while self.next { |new_item| sync_call(new_item, args, kwargs, block); true }; end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def for_each_till_next(*args, **kwargs, &block)
|
64
|
+
for_each_in_thread(*args,**kwargs.merge(kill_previous_on_next: true), &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def for_each_concurrent(*args, **kwargs, &block)
|
69
|
+
for_each_in_thread(*args, **kwargs, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def for_each_in_thread(*args, **kwargs, &block)
|
74
|
+
Thread.handle_interrupt(Object => :never) {
|
75
|
+
|
76
|
+
# we poll the stream in a separate thread because we sometimes want to interrupt the polling thread from an item-handling thread, and, without the wrapper-thread, we could end up raising exception in a random place of code, if Async is being used. maybe?
|
77
|
+
stream_polling_thread = Thread.new {
|
78
|
+
begin
|
79
|
+
item_threads = ObjectSpace::WeakMap.new
|
80
|
+
exception_to_rescue = NextItemInterrupt.new
|
81
|
+
|
82
|
+
while new_item = self.next
|
83
|
+
if kwargs[:kill_previous_on_next]
|
84
|
+
item_threads.keys.each { |item_thread|
|
85
|
+
item_thread.raise(exception_to_rescue)
|
86
|
+
item_thread.join
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
item_threads[Thread.new(new_item, Thread.current) do |item, parent_thread|
|
91
|
+
sync_call(item, args, kwargs, block)
|
92
|
+
rescue Object => error
|
93
|
+
if error != exception_to_rescue
|
94
|
+
if kwargs[:propagate_exceptions].nil? or kwargs[:propagate_exceptions]
|
95
|
+
parent_thread.raise(error)
|
96
|
+
else
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
end
|
100
|
+
ensure
|
101
|
+
item_threads.delete Thread.current
|
102
|
+
end] = true
|
103
|
+
end
|
104
|
+
|
105
|
+
if kwargs[:kill_previous_on_next]
|
106
|
+
item_threads.keys.each { |item_thread|
|
107
|
+
item_thread.raise(exception_to_rescue)
|
108
|
+
item_thread.join
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
Thread.handle_interrupt(Object => :immediate) {
|
113
|
+
item_threads.keys.each { |item_thread|
|
114
|
+
item_thread.join
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
nil
|
119
|
+
rescue Object => error
|
120
|
+
exception_to_rescue = error
|
121
|
+
item_threads.keys.each { |item_thread| item_thread.raise(error) }
|
122
|
+
error
|
123
|
+
ensure
|
124
|
+
item_threads.keys.each { |item_thread|
|
125
|
+
begin
|
126
|
+
item_thread.join_with_warning(60)
|
127
|
+
rescue Object => error
|
128
|
+
# it's probably better to not re-raise here, so this one doesn't obscure the original. but lets at least print it out.
|
129
|
+
$stderr.puts "Item thread exception: \n"+error.inspect
|
130
|
+
end
|
131
|
+
}
|
132
|
+
end
|
133
|
+
}
|
134
|
+
|
135
|
+
begin
|
136
|
+
Thread.handle_interrupt(Object => :immediate) {
|
137
|
+
value = stream_polling_thread.join.value
|
138
|
+
raise value if !value.nil?
|
139
|
+
}
|
140
|
+
rescue Object => error
|
141
|
+
stream_polling_thread.raise(error)
|
142
|
+
raise
|
143
|
+
ensure
|
144
|
+
begin
|
145
|
+
stream_polling_thread.join_with_warning(60)
|
146
|
+
rescue Object => error
|
147
|
+
# it's probably better to not re-raise here, so this one doesn't obscure the original. but lets at least print it out.
|
148
|
+
$stderr.puts "Item thread exception: \n"+error.inspect
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
## blocks can't be sanely passed to ractors :(
|
157
|
+
# def for_each_in_ractor(*args, **kwargs, &block)
|
158
|
+
# Thread.handle_interrupt(Object => :never) {
|
159
|
+
# begin
|
160
|
+
# Thread.handle_interrupt(Object => :immediate) {
|
161
|
+
# while new_item = self.next
|
162
|
+
# Ractor.new(new_item, args, kwargs, runner ) { |item, args, kwargs, runner|
|
163
|
+
# sync_call(item, args, kwargs, runner)
|
164
|
+
# }
|
165
|
+
# end
|
166
|
+
# }
|
167
|
+
# ensure
|
168
|
+
# #TODO: should we kill still-running sub-tasks here, or await? or maybe kill on exception, and await otherwise?
|
169
|
+
# end
|
170
|
+
# }
|
171
|
+
# end
|
172
|
+
|
173
|
+
|
174
|
+
private def sync_call(item, args, kwargs, block)
|
175
|
+
Thread.handle_interrupt(Object => :never) {
|
176
|
+
begin
|
177
|
+
Thread.handle_interrupt(Object => :immediate) {
|
178
|
+
block.call(item, *args, **kwargs)
|
179
|
+
}
|
180
|
+
ensure
|
181
|
+
item.drop
|
182
|
+
end
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hakuban/ffi-object.rb'
|
2
|
+
|
3
|
+
module Hakuban
|
4
|
+
|
5
|
+
class Tokio
|
6
|
+
|
7
|
+
@@pointer = nil
|
8
|
+
|
9
|
+
def Tokio.init(workers_count=0)
|
10
|
+
Hakuban::hakuban_initialize
|
11
|
+
@@pointer ||= FFI::hakuban_tokio_init_multi_thread(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def Tokio.pointer
|
15
|
+
Tokio.init if not @@pointer
|
16
|
+
@@pointer
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class WebsocketConnector < FFIObject
|
23
|
+
|
24
|
+
def initialize(exchange, url, &block)
|
25
|
+
super()
|
26
|
+
Thread.handle_interrupt(Object => :never) {
|
27
|
+
pointer = exchange.with_pointer { |exchange_pointer| FFI::hakuban_tokio_websocket_connector_new(Tokio.pointer, exchange_pointer, url) }.unwrap
|
28
|
+
initialize_pointer(pointer, :hakuban_tokio_websocket_connector_drop, nil)
|
29
|
+
self.do_and_drop_or_return(&block)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.default_name
|
38
|
+
"#{Socket.gethostname}:#{File.basename(caller_locations(0..1)[1].path)}:#{$$}"
|
39
|
+
end
|
data/lib/hakuban/version.rb
CHANGED
data/lib/hakuban.rb
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "hakuban/version"
|
4
|
-
require_relative "hakuban/hakuban"
|
5
|
-
require_relative "hakuban/engine"
|
6
|
-
#require_relative "hakuban/async"
|
7
|
-
#require_relative "hakuban/thread"
|
8
|
-
|
9
3
|
module Hakuban
|
4
|
+
|
5
|
+
def self.hakuban_initialize
|
6
|
+
require_relative 'hakuban/ffi.rb'
|
7
|
+
end
|
8
|
+
|
10
9
|
end
|
10
|
+
|
11
|
+
|
12
|
+
require_relative 'hakuban/contract.rb'
|
13
|
+
require_relative 'hakuban/descriptor.rb'
|
14
|
+
require_relative "hakuban/engine.rb"
|
15
|
+
require_relative 'hakuban/exchange.rb'
|
16
|
+
require_relative 'hakuban/ffi-object.rb'
|
17
|
+
require_relative 'hakuban/logger.rb'
|
18
|
+
require_relative 'hakuban/object_state_sink.rb'
|
19
|
+
require_relative 'hakuban/object_state_stream.rb'
|
20
|
+
require_relative 'hakuban/object_state.rb'
|
21
|
+
require_relative 'hakuban/tokio-websocket-connector.rb'
|
22
|
+
require_relative "hakuban/version"
|
23
|
+
|
24
|
+
|
25
|
+
#TODO: error classes
|
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.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yunta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -16,78 +16,98 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.13'
|
20
20
|
type: :development
|
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: '3.
|
26
|
+
version: '3.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: simplecov
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.22'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.22'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: ffi
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
47
|
+
version: '1.17'
|
34
48
|
type: :runtime
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
54
|
+
version: '1.17'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: json
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '2.
|
61
|
+
version: '2.9'
|
48
62
|
type: :runtime
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '2.
|
68
|
+
version: '2.9'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: slop
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '4.
|
75
|
+
version: '4.10'
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '4.
|
82
|
+
version: '4.10'
|
69
83
|
description: Ruby binding for convenient data-object sharing library - Hakuban.
|
70
84
|
email:
|
71
85
|
- maciej.blomberg@mikoton.com
|
72
86
|
executables:
|
73
|
-
- hakuban-
|
74
|
-
- hakuban-
|
87
|
+
- hakuban-observe
|
88
|
+
- hakuban-engine
|
75
89
|
extensions: []
|
76
90
|
extra_rdoc_files: []
|
77
91
|
files:
|
78
92
|
- MIT-LICENSE
|
79
93
|
- README.md
|
80
94
|
- Rakefile
|
81
|
-
- bin/hakuban-
|
82
|
-
- bin/hakuban-
|
95
|
+
- bin/hakuban-engine
|
96
|
+
- bin/hakuban-observe
|
83
97
|
- lib/hakuban.rb
|
84
|
-
- lib/hakuban/
|
98
|
+
- lib/hakuban/contract.rb
|
99
|
+
- lib/hakuban/descriptor.rb
|
85
100
|
- lib/hakuban/engine.rb
|
86
|
-
- lib/hakuban/
|
101
|
+
- lib/hakuban/exchange.rb
|
102
|
+
- lib/hakuban/ffi-object.rb
|
87
103
|
- lib/hakuban/ffi.rb
|
88
|
-
- lib/hakuban/
|
89
|
-
- lib/hakuban/
|
90
|
-
- lib/hakuban/
|
104
|
+
- lib/hakuban/logger.rb
|
105
|
+
- lib/hakuban/object_state.rb
|
106
|
+
- lib/hakuban/object_state_sink.rb
|
107
|
+
- lib/hakuban/object_state_stream.rb
|
108
|
+
- lib/hakuban/refinements.rb
|
109
|
+
- lib/hakuban/stream.rb
|
110
|
+
- lib/hakuban/tokio-websocket-connector.rb
|
91
111
|
- lib/hakuban/version.rb
|
92
112
|
homepage: https://gitlab.com/yunta/hakuban-ruby
|
93
113
|
licenses:
|
@@ -108,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
128
|
- !ruby/object:Gem::Version
|
109
129
|
version: '0'
|
110
130
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
131
|
+
rubygems_version: 3.5.22
|
112
132
|
signing_key:
|
113
133
|
specification_version: 4
|
114
134
|
summary: Ruby binding for Hakuban library
|
data/bin/hakuban-observer
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/bin/env ruby
|
2
|
-
|
3
|
-
require 'slop'
|
4
|
-
require 'pp'
|
5
|
-
require 'hakuban/thread'
|
6
|
-
|
7
|
-
|
8
|
-
OPTIONS = Slop.parse { |o|
|
9
|
-
o.string '-c', '--connect', "Hakuban upstream address (default: ws://127.0.0.1:3001)", default: "ws://127.0.0.1:3001"
|
10
|
-
o.string '-o', '--object', "Object descriptor"
|
11
|
-
o.array '-t', '--tag', "Tag descriptor(s)"
|
12
|
-
o.bool '-d', '--debug', 'Show debug messages'
|
13
|
-
o.on '-h', '--help' do puts o; exit end
|
14
|
-
}
|
15
|
-
|
16
|
-
Hakuban.logger_initialize("hakuban=debug") if OPTIONS.debug?
|
17
|
-
hakuban = Hakuban::LocalNode.new(name: OPTIONS["name"])
|
18
|
-
connector = Hakuban::WebsocketConnector.new(hakuban, OPTIONS["connect"])
|
19
|
-
|
20
|
-
observe_contract = if OPTIONS["object"]
|
21
|
-
json = JSON.load(OPTIONS["object"])
|
22
|
-
tags = OPTIONS["tag"].map { |tag| JSON.load(tag) }
|
23
|
-
hakuban.object(tags, json).observe
|
24
|
-
else
|
25
|
-
tag = OPTIONS["tag"].map { |tag| JSON.load(tag) }
|
26
|
-
hakuban.tag(tag[0]).observe
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
def print_event(descriptor, event, more)
|
31
|
-
if $subsequent
|
32
|
-
puts ','
|
33
|
-
else
|
34
|
-
$subsequent = true
|
35
|
-
end
|
36
|
-
puts '{'
|
37
|
-
puts '"event": "%s",'%[event]
|
38
|
-
puts '"descriptor_json": %s,'%[JSON.dump(descriptor.json)]
|
39
|
-
puts '"descriptor_tags": [%s],'%[descriptor.tags.map { |tag| JSON.dump(tag.json) }.join(",")]
|
40
|
-
puts more if more
|
41
|
-
puts '}'
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
puts "["
|
46
|
-
|
47
|
-
contract = observe_contract.manage.with_thread { |object|
|
48
|
-
print_event(object.descriptor, "create", nil)
|
49
|
-
while object.next_change
|
50
|
-
print_event(object.descriptor, "change",
|
51
|
-
if state = object.state
|
52
|
-
[
|
53
|
-
'"version": %s,'%[JSON.dump(state.version)],
|
54
|
-
'"last_sync_ms_ago": %s,'%[JSON.dump(state.synchronized)],
|
55
|
-
'"data": %s,'%[JSON.dump(state.data)],
|
56
|
-
].join("\n")
|
57
|
-
end
|
58
|
-
)
|
59
|
-
end
|
60
|
-
print_event(object.descriptor, "drop", nil)
|
61
|
-
}
|
62
|
-
|
63
|
-
$stdin.read(1)
|
64
|
-
puts "]"
|
data/lib/hakuban/async.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'hakuban'
|
2
|
-
require 'hakuban/manager'
|
3
|
-
require 'async'
|
4
|
-
|
5
|
-
module Hakuban
|
6
|
-
|
7
|
-
class AsyncObjectManager < ObjectManager
|
8
|
-
|
9
|
-
def async_run
|
10
|
-
Async { yield }
|
11
|
-
end
|
12
|
-
|
13
|
-
def async_join(task)
|
14
|
-
task.wait
|
15
|
-
end
|
16
|
-
|
17
|
-
def async_stop(task)
|
18
|
-
task.stop
|
19
|
-
end
|
20
|
-
|
21
|
-
def async_filter_out_stop_exception
|
22
|
-
yield
|
23
|
-
rescue Async::Stop
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
|
30
|
-
class ObjectManagerBuilder
|
31
|
-
|
32
|
-
def with_async(&block)
|
33
|
-
build(AsyncObjectManager, block)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
data/lib/hakuban/event-queue.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
#TODO: rebuild to handle event squashing on rust side
|
2
|
-
|
3
|
-
require 'ostruct'
|
4
|
-
|
5
|
-
|
6
|
-
module Hakuban
|
7
|
-
|
8
|
-
class Event < OpenStruct; end
|
9
|
-
|
10
|
-
class ObjectDescriptorCallbackEventQueue
|
11
|
-
|
12
|
-
def initialize(pointer)
|
13
|
-
@events_pointer = ::FFI::AutoPointer.new(pointer, proc { |ptr| FFI.hakuban_object_descriptor_events_return(ptr) })
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
# WARNING: this callback may be run from a separate, non-ruby, thread
|
18
|
-
def callback_register(&callback)
|
19
|
-
ffi_callback = proc { |_userdata, ffi_descriptor, ffi_action|
|
20
|
-
action = Hakuban::action_int_to_symbol(ffi_action)
|
21
|
-
descriptor = ObjectDescriptor.from_ffi(ffi_descriptor)
|
22
|
-
callback.call(descriptor, action)
|
23
|
-
}
|
24
|
-
@callback_pointer = ::FFI::AutoPointer.new(
|
25
|
-
FFI::hakuban_object_descriptor_events_callback_register(@events_pointer, ffi_callback, ::FFI::Pointer::NULL),
|
26
|
-
proc { |ptr| FFI::hakuban_object_descriptor_events_callback_unregister(ptr) }
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
def callback_unregister
|
32
|
-
@callback_pointer.free
|
33
|
-
@callback_pointer = nil
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
def drop
|
38
|
-
@events_pointer.free
|
39
|
-
@events_pointer = nil
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
class ObjectDescriptorEventQueue
|
46
|
-
|
47
|
-
def initialize(contract)
|
48
|
-
@contract = contract
|
49
|
-
@queue = Queue.new
|
50
|
-
@ffi_callback = proc { |descriptor, action|
|
51
|
-
@queue << Hakuban::Event.new(action: action, descriptor: descriptor)
|
52
|
-
}
|
53
|
-
@ffi_events = @contract.new_callback_event_queue
|
54
|
-
@ffi_events.callback_register(&@ffi_callback)
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
#def push(event)
|
59
|
-
# @queue << event
|
60
|
-
#end
|
61
|
-
|
62
|
-
|
63
|
-
def next_event; next_change; end
|
64
|
-
def next_change
|
65
|
-
@queue.pop
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
def close
|
70
|
-
@queue.close
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|