ciri 0.0.0 → 0.0.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 +4 -4
- data/.gitmodules +14 -0
- data/.rspec +2 -1
- data/.travis.yml +11 -4
- data/Gemfile.lock +3 -0
- data/README.md +44 -34
- data/Rakefile +47 -4
- data/ciri.gemspec +13 -12
- data/docker/Base +34 -0
- data/lib/ciri/actor.rb +223 -0
- data/lib/ciri/chain.rb +293 -0
- data/lib/ciri/chain/block.rb +47 -0
- data/lib/ciri/chain/header.rb +62 -0
- data/lib/ciri/chain/transaction.rb +145 -0
- data/lib/ciri/crypto.rb +58 -5
- data/lib/ciri/db/backend/memory.rb +68 -0
- data/lib/ciri/db/backend/rocks.rb +104 -0
- data/lib/ciri/db/backend/rocks_db.rb +278 -0
- data/lib/ciri/devp2p/peer.rb +10 -2
- data/lib/ciri/devp2p/protocol.rb +11 -3
- data/lib/ciri/devp2p/protocol_io.rb +6 -3
- data/lib/ciri/devp2p/rlpx.rb +1 -0
- data/lib/ciri/devp2p/rlpx/encryption_handshake.rb +1 -1
- data/lib/ciri/devp2p/rlpx/frame_io.rb +1 -1
- data/lib/ciri/devp2p/rlpx/message.rb +4 -4
- data/lib/ciri/devp2p/server.rb +14 -13
- data/lib/ciri/eth.rb +33 -0
- data/lib/ciri/eth/peer.rb +64 -0
- data/lib/ciri/eth/protocol_manage.rb +122 -0
- data/lib/ciri/eth/protocol_messages.rb +158 -0
- data/lib/ciri/eth/synchronizer.rb +188 -0
- data/lib/ciri/ethash.rb +123 -0
- data/lib/ciri/evm.rb +140 -0
- data/lib/ciri/evm/account.rb +50 -0
- data/lib/ciri/evm/block_info.rb +31 -0
- data/lib/ciri/evm/forks/frontier.rb +183 -0
- data/lib/ciri/evm/instruction.rb +92 -0
- data/lib/ciri/evm/machine_state.rb +81 -0
- data/lib/ciri/evm/op.rb +536 -0
- data/lib/ciri/evm/serialize.rb +60 -0
- data/lib/ciri/evm/sub_state.rb +64 -0
- data/lib/ciri/evm/vm.rb +379 -0
- data/lib/ciri/forks.rb +38 -0
- data/lib/ciri/forks/frontier.rb +43 -0
- data/lib/ciri/key.rb +7 -1
- data/lib/ciri/pow.rb +95 -0
- data/lib/ciri/rlp.rb +3 -53
- data/lib/ciri/rlp/decode.rb +100 -40
- data/lib/ciri/rlp/encode.rb +95 -34
- data/lib/ciri/rlp/serializable.rb +61 -91
- data/lib/ciri/types/address.rb +70 -0
- data/lib/ciri/types/errors.rb +36 -0
- data/lib/ciri/utils.rb +45 -13
- data/lib/ciri/utils/lib_c.rb +46 -0
- data/lib/ciri/utils/logger.rb +99 -0
- data/lib/ciri/utils/number.rb +67 -0
- data/lib/ciri/version.rb +1 -1
- metadata +67 -7
- data/lib/ciri/devp2p/actor.rb +0 -224
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
require 'logger'
|
25
|
+
|
26
|
+
module Ciri
|
27
|
+
module Utils
|
28
|
+
|
29
|
+
# Logger
|
30
|
+
# Example:
|
31
|
+
#
|
32
|
+
# class A
|
33
|
+
# include Logger
|
34
|
+
#
|
35
|
+
# def initialize(name)
|
36
|
+
# @name = name
|
37
|
+
# debug("initial with name")
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# def greet
|
41
|
+
# puts "hello"
|
42
|
+
# debug("greeting hello")
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # customize logging name
|
46
|
+
# def logging_name
|
47
|
+
# "#{super}:#{@name}"
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# # don't forget initialize global logger
|
52
|
+
# Ciri::Utils::Logger.setup(level: :debug)
|
53
|
+
#
|
54
|
+
module Logger
|
55
|
+
|
56
|
+
class << self
|
57
|
+
attr_reader :global_logger
|
58
|
+
|
59
|
+
def setup(level:)
|
60
|
+
@global_logger = ::Logger.new(STDERR, level: level)
|
61
|
+
global_logger.datetime_format = '%Y-%m-%d %H:%M:%S'
|
62
|
+
set_concurrent_logger(level: global_logger.level)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def set_concurrent_logger(level:)
|
68
|
+
require 'concurrent'
|
69
|
+
Concurrent.use_simple_logger(level = level)
|
70
|
+
rescue LoadError
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def debug(message)
|
76
|
+
add(::Logger::DEBUG, message)
|
77
|
+
end
|
78
|
+
|
79
|
+
def info(message)
|
80
|
+
add(::Logger::INFO, message)
|
81
|
+
end
|
82
|
+
|
83
|
+
def error(message)
|
84
|
+
add(::Logger::ERROR, message)
|
85
|
+
end
|
86
|
+
|
87
|
+
def logging_name
|
88
|
+
self.class.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def add(severity, message = nil, progname = logging_name)
|
94
|
+
Logger.global_logger.add(severity, message, progname)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
module Ciri
|
25
|
+
module Utils
|
26
|
+
module Number
|
27
|
+
extend self
|
28
|
+
|
29
|
+
def big_endian_encode(n, zero = ''.b)
|
30
|
+
if n == 0
|
31
|
+
zero
|
32
|
+
elsif n > 0
|
33
|
+
big_endian_encode(n / 256) + (n % 256).chr
|
34
|
+
else
|
35
|
+
raise ArgumentError.new("can't encode negative number #{n}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def big_endian_encode_to_size(n, zero = ''.b, size:)
|
40
|
+
big_endian_encode(n, zero).rjust(size, "\x00".b)
|
41
|
+
end
|
42
|
+
|
43
|
+
def big_endian_decode(input)
|
44
|
+
input.each_byte.reduce(0) {|s, i| s * 256 + i}
|
45
|
+
end
|
46
|
+
|
47
|
+
UINT_256_MAX = 2 ** 256 - 1
|
48
|
+
UINT_256_CEILING = 2 ** 256
|
49
|
+
UINT_255_MAX = 2 ** 255 - 1
|
50
|
+
UINT_255_CEILING = 2 ** 255
|
51
|
+
|
52
|
+
def unsigned_to_signed(n)
|
53
|
+
n <= UINT_255_MAX ? n : n - UINT_256_CEILING
|
54
|
+
end
|
55
|
+
|
56
|
+
def signed_to_unsigned(n)
|
57
|
+
n >= 0 ? n : n + UINT_256_CEILING
|
58
|
+
end
|
59
|
+
|
60
|
+
def ceil_div(n, ceil)
|
61
|
+
size, m = n.divmod ceil
|
62
|
+
m.zero? ? size : size + 1
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/ciri/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ciri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jiang Jinyang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.9.23
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.9.23
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: lru_redux
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.1.0
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: digest-sha3
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,8 +136,7 @@ dependencies:
|
|
108
136
|
- - "~>"
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '3.0'
|
111
|
-
description: Ciri project intent to implement full feature set
|
112
|
-
ruby, to provide both usable cli and well documented ruby library.
|
139
|
+
description: Ciri project intent to implement a full feature set ethereum client.
|
113
140
|
email:
|
114
141
|
- jjyruby@gmail.com
|
115
142
|
executables: []
|
@@ -117,6 +144,7 @@ extensions: []
|
|
117
144
|
extra_rdoc_files: []
|
118
145
|
files:
|
119
146
|
- ".gitignore"
|
147
|
+
- ".gitmodules"
|
120
148
|
- ".rspec"
|
121
149
|
- ".travis.yml"
|
122
150
|
- CODE_OF_CONDUCT.md
|
@@ -128,9 +156,17 @@ files:
|
|
128
156
|
- bin/console
|
129
157
|
- bin/setup
|
130
158
|
- ciri.gemspec
|
159
|
+
- docker/Base
|
131
160
|
- lib/ciri.rb
|
161
|
+
- lib/ciri/actor.rb
|
162
|
+
- lib/ciri/chain.rb
|
163
|
+
- lib/ciri/chain/block.rb
|
164
|
+
- lib/ciri/chain/header.rb
|
165
|
+
- lib/ciri/chain/transaction.rb
|
132
166
|
- lib/ciri/crypto.rb
|
133
|
-
- lib/ciri/
|
167
|
+
- lib/ciri/db/backend/memory.rb
|
168
|
+
- lib/ciri/db/backend/rocks.rb
|
169
|
+
- lib/ciri/db/backend/rocks_db.rb
|
134
170
|
- lib/ciri/devp2p/peer.rb
|
135
171
|
- lib/ciri/devp2p/protocol.rb
|
136
172
|
- lib/ciri/devp2p/protocol_io.rb
|
@@ -145,14 +181,38 @@ files:
|
|
145
181
|
- lib/ciri/devp2p/rlpx/protocol_messages.rb
|
146
182
|
- lib/ciri/devp2p/rlpx/secrets.rb
|
147
183
|
- lib/ciri/devp2p/server.rb
|
184
|
+
- lib/ciri/eth.rb
|
185
|
+
- lib/ciri/eth/peer.rb
|
186
|
+
- lib/ciri/eth/protocol_manage.rb
|
187
|
+
- lib/ciri/eth/protocol_messages.rb
|
188
|
+
- lib/ciri/eth/synchronizer.rb
|
189
|
+
- lib/ciri/ethash.rb
|
190
|
+
- lib/ciri/evm.rb
|
191
|
+
- lib/ciri/evm/account.rb
|
192
|
+
- lib/ciri/evm/block_info.rb
|
193
|
+
- lib/ciri/evm/forks/frontier.rb
|
194
|
+
- lib/ciri/evm/instruction.rb
|
195
|
+
- lib/ciri/evm/machine_state.rb
|
196
|
+
- lib/ciri/evm/op.rb
|
197
|
+
- lib/ciri/evm/serialize.rb
|
198
|
+
- lib/ciri/evm/sub_state.rb
|
199
|
+
- lib/ciri/evm/vm.rb
|
200
|
+
- lib/ciri/forks.rb
|
201
|
+
- lib/ciri/forks/frontier.rb
|
148
202
|
- lib/ciri/key.rb
|
203
|
+
- lib/ciri/pow.rb
|
149
204
|
- lib/ciri/rlp.rb
|
150
205
|
- lib/ciri/rlp/decode.rb
|
151
206
|
- lib/ciri/rlp/encode.rb
|
152
207
|
- lib/ciri/rlp/serializable.rb
|
208
|
+
- lib/ciri/types/address.rb
|
209
|
+
- lib/ciri/types/errors.rb
|
153
210
|
- lib/ciri/utils.rb
|
211
|
+
- lib/ciri/utils/lib_c.rb
|
212
|
+
- lib/ciri/utils/logger.rb
|
213
|
+
- lib/ciri/utils/number.rb
|
154
214
|
- lib/ciri/version.rb
|
155
|
-
homepage: https://github.com/
|
215
|
+
homepage: https://github.com/ciri-ethereum/ciri
|
156
216
|
licenses:
|
157
217
|
- MIT
|
158
218
|
metadata: {}
|
@@ -175,5 +235,5 @@ rubyforge_project:
|
|
175
235
|
rubygems_version: 2.7.3
|
176
236
|
signing_key:
|
177
237
|
specification_version: 4
|
178
|
-
summary:
|
238
|
+
summary: Ciri ethereum client.
|
179
239
|
test_files: []
|
data/lib/ciri/devp2p/actor.rb
DELETED
@@ -1,224 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright (c) 2018, by Jiang Jinyang. <https://justjjy.com>
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
22
|
-
|
23
|
-
|
24
|
-
require 'logger'
|
25
|
-
|
26
|
-
module Ciri
|
27
|
-
module DevP2P
|
28
|
-
|
29
|
-
# simple actor model implementation
|
30
|
-
# Example:
|
31
|
-
#
|
32
|
-
# class Hello
|
33
|
-
# include Actor
|
34
|
-
#
|
35
|
-
# def say_hello
|
36
|
-
# puts 'hello world'
|
37
|
-
# 'hello world'
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# actor = Hello.new
|
42
|
-
# # start actor loop
|
43
|
-
# actor.start
|
44
|
-
# # push message to actor inbox
|
45
|
-
# actor << :say_hello
|
46
|
-
# # push message and wait until get response
|
47
|
-
# actor.call(:say_hello).value
|
48
|
-
#
|
49
|
-
# # raise error
|
50
|
-
# actor.call(:hello).value # NoMethodError
|
51
|
-
#
|
52
|
-
# # stop actor
|
53
|
-
# actor.send_stop
|
54
|
-
# actor.wait
|
55
|
-
#
|
56
|
-
module Actor
|
57
|
-
|
58
|
-
LOGGER = Logger.new(STDERR, datetime_format: '%Y-%m-%d %H:%M:%S', level: Logger::INFO)
|
59
|
-
|
60
|
-
# future, use this to wait actor msg respond
|
61
|
-
class Future
|
62
|
-
def initialize
|
63
|
-
@value = nil
|
64
|
-
@done = false
|
65
|
-
end
|
66
|
-
|
67
|
-
def value=(val)
|
68
|
-
if @done
|
69
|
-
raise RuntimeError.new('future value duplicated set')
|
70
|
-
end
|
71
|
-
@done = true
|
72
|
-
@queue << :done if @queue
|
73
|
-
@value = val
|
74
|
-
end
|
75
|
-
|
76
|
-
def value
|
77
|
-
loop do
|
78
|
-
if @done
|
79
|
-
return @value
|
80
|
-
elsif @error
|
81
|
-
raise @error
|
82
|
-
else
|
83
|
-
queue.pop
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def raise_error(error)
|
89
|
-
error.set_backtrace(caller) if error.backtrace.nil?
|
90
|
-
@error = error
|
91
|
-
@queue << :error if @queue
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
def queue
|
96
|
-
@queue ||= Queue.new
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
class Error < StandardError
|
101
|
-
end
|
102
|
-
|
103
|
-
# stop actor
|
104
|
-
class StopError < Error
|
105
|
-
end
|
106
|
-
|
107
|
-
class StateError < Error
|
108
|
-
end
|
109
|
-
|
110
|
-
attr_accessor :executor
|
111
|
-
|
112
|
-
def initialize(executor: nil)
|
113
|
-
@inbox = Queue.new
|
114
|
-
@executor = executor
|
115
|
-
@future = Future.new
|
116
|
-
@running = false
|
117
|
-
end
|
118
|
-
|
119
|
-
# async call
|
120
|
-
def enqueue(method, *args)
|
121
|
-
self << [method, *args]
|
122
|
-
end
|
123
|
-
|
124
|
-
def <<(args)
|
125
|
-
@inbox << args
|
126
|
-
end
|
127
|
-
|
128
|
-
# sync call, push msg to inbox, and return future
|
129
|
-
#
|
130
|
-
# Example:
|
131
|
-
# future = actor.call(:result) # future
|
132
|
-
# future.value # blocking and wait for result
|
133
|
-
#
|
134
|
-
def call(method, *args)
|
135
|
-
future = Future.new
|
136
|
-
self << [future, method, *args]
|
137
|
-
future
|
138
|
-
end
|
139
|
-
|
140
|
-
# start actor
|
141
|
-
def start
|
142
|
-
raise Error.new("must set executor before start") unless executor
|
143
|
-
|
144
|
-
@running = true
|
145
|
-
executor.post do
|
146
|
-
start_loop
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# send stop to actor
|
151
|
-
#
|
152
|
-
# Example:
|
153
|
-
# actor.send_stop
|
154
|
-
# # wait for actor actually stopped
|
155
|
-
# actor.wait
|
156
|
-
#
|
157
|
-
def send_stop
|
158
|
-
self << [:raise_error, StopError.new]
|
159
|
-
end
|
160
|
-
|
161
|
-
# wait until an error occurs
|
162
|
-
def wait
|
163
|
-
raise StateError.new('actor not running!') unless @running
|
164
|
-
@future.value
|
165
|
-
end
|
166
|
-
|
167
|
-
# start loop
|
168
|
-
def start_loop
|
169
|
-
loop_callback do |wait_message: true|
|
170
|
-
# check inbox
|
171
|
-
next Thread.pass if @inbox.empty? && !wait_message
|
172
|
-
msg = @inbox.pop
|
173
|
-
|
174
|
-
# extract sync or async call
|
175
|
-
future = nil
|
176
|
-
method, *args = msg
|
177
|
-
if method.is_a?(Future)
|
178
|
-
future = method
|
179
|
-
method, *args = args
|
180
|
-
end
|
181
|
-
begin
|
182
|
-
val = send(method, *args)
|
183
|
-
rescue StandardError => e
|
184
|
-
future.raise_error(e) if future
|
185
|
-
raise
|
186
|
-
end
|
187
|
-
# if future not nil, set value
|
188
|
-
future.value = val if future
|
189
|
-
end while true
|
190
|
-
|
191
|
-
rescue StopError
|
192
|
-
# actor stop
|
193
|
-
@future.value = nil
|
194
|
-
rescue StandardError => e
|
195
|
-
@future.raise_error e
|
196
|
-
LOGGER.error("Actor #{self}") {"#{e}\n#{e.backtrace.join("\n")}"}
|
197
|
-
ensure
|
198
|
-
@running = false
|
199
|
-
end
|
200
|
-
|
201
|
-
# allow inject callback into actor loop
|
202
|
-
# Example:
|
203
|
-
#
|
204
|
-
# class A
|
205
|
-
# include Actor
|
206
|
-
#
|
207
|
-
# def loop_callback
|
208
|
-
# # before handle msg
|
209
|
-
# yield
|
210
|
-
# # after handle msg
|
211
|
-
# end
|
212
|
-
# end
|
213
|
-
#
|
214
|
-
def loop_callback
|
215
|
-
yield
|
216
|
-
end
|
217
|
-
|
218
|
-
def raise_error(e)
|
219
|
-
raise e
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
end
|
224
|
-
end
|