zold 0.12.1 → 0.13.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/README.md +8 -9
- data/bin/zold +9 -6
- data/features/cli.feature +0 -5
- data/fixtures/scripts/_head.sh +11 -0
- data/fixtures/scripts/calculate-scores.sh +0 -5
- data/fixtures/scripts/print-helps.sh +0 -5
- data/fixtures/scripts/push-and-pull.sh +3 -8
- data/fixtures/scripts/redeploy-on-upgrade.sh +40 -0
- data/lib/zold/commands/node.rb +103 -59
- data/lib/zold/commands/remote.rb +3 -4
- data/lib/zold/commands/routines/bonuses.rb +74 -0
- data/lib/zold/commands/routines/reconnect.rb +50 -0
- data/lib/zold/{routines.rb → metronome.rb} +11 -8
- data/lib/zold/node/front.rb +7 -6
- data/lib/zold/version.rb +1 -1
- data/test/commands/routines/test_bonuses.rb +48 -0
- data/test/commands/routines/test_reconnect.rb +43 -0
- data/test/commands/test_node.rb +7 -10
- data/test/commands/test_taxes.rb +6 -8
- data/test/fake_home.rb +5 -3
- data/test/node/fake_node.rb +9 -7
- data/test/test__helper.rb +5 -6
- data/test/{test_routines.rb → test_metronome.rb} +16 -8
- data/test/test_zold.rb +2 -2
- metadata +13 -8
- data/bin/zold-nohup +0 -96
- data/fixtures/scripts/with-nohup.sh +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffdbb36409b1e6f281cd278d24e6c2994da8a845
|
4
|
+
data.tar.gz: 10e1b526ef486b2e77d225b42c8fc550c0f5c9fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b20bde3757d4b7de91f9e1b911449b25d83b67dd23c721a92271f602f23fa41073f6ab2444e9a0895a8efe315372278b944480ace64e0714787c9b3912cc6a49
|
7
|
+
data.tar.gz: 264d6b0401753c5b4460b035a88d2cdaab06d58b9f5c5e9976f5a8c27c25142a4a556708b70945c80176c20040795e1af1f5ad8a05bda14b83e0dc8bea1274f6
|
data/README.md
CHANGED
@@ -87,26 +87,25 @@ $ zold push 5f96e731e48ae21f
|
|
87
87
|
That's it.
|
88
88
|
|
89
89
|
You also can contribute to Zold by running a node on your server.
|
90
|
-
In order to do that just run (with your own wallet ID, of course
|
91
|
-
and your own public IP address instead of `4.4.4.4`):
|
90
|
+
In order to do that just run (with your own wallet ID, of course):
|
92
91
|
|
93
92
|
```bash
|
94
|
-
$ zold node --
|
93
|
+
$ zold node --invoice=5f96e731e48ae21f
|
95
94
|
```
|
96
95
|
|
97
|
-
Then, open the page `
|
96
|
+
Then, open the page `localhost:4096` in your browser
|
98
97
|
(you may need to open the inbound port at your
|
99
98
|
[IP firewall](https://www.howtogeek.com/177621/the-beginners-guide-to-iptables-the-linux-firewall/)).
|
100
99
|
If you see a simple JSON document, everything is fine.
|
101
|
-
Next, hit <kbd>Ctrl</kbd>+<kbd>c</kbd> and run it again, but
|
102
|
-
of `zold` say `zold-nohup`:
|
100
|
+
Next, hit <kbd>Ctrl</kbd>+<kbd>c</kbd> and run it again, but with `--nohup`:
|
103
101
|
|
104
102
|
```bash
|
105
|
-
$ zold
|
103
|
+
$ zold node --nohup --invoice=5f96e731e48ae21f > log.txt
|
106
104
|
```
|
107
105
|
|
108
|
-
Now you can close
|
109
|
-
|
106
|
+
Now you can close the console;
|
107
|
+
the softsare will work in the background, saving the output logs to `log.txt`.
|
108
|
+
The software will update itself automatically to new versions.
|
110
109
|
|
111
110
|
Grateful users of the system will pay "taxes" to your wallet
|
112
111
|
for the maintenance of their wallets, and the system will occasionally
|
data/bin/zold
CHANGED
@@ -87,8 +87,8 @@ Available commands:
|
|
87
87
|
#{Rainbow('score').green} host port strength [options]
|
88
88
|
Generate score for the given host and port
|
89
89
|
Available options:"
|
90
|
-
o.string '
|
91
|
-
|
90
|
+
o.string '--home',
|
91
|
+
"Home directory (default: #{Dir.pwd})",
|
92
92
|
default: Dir.pwd
|
93
93
|
o.bool '-h', '--help', 'Show these instructions'
|
94
94
|
o.bool '--trace', 'Show full stack trace in case of a problem'
|
@@ -117,14 +117,17 @@ Available options:"
|
|
117
117
|
args = opts.arguments
|
118
118
|
args << '--help' if opts.help?
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
FileUtils.mkdir_p(opts[:home])
|
121
|
+
Dir.chdir(opts[:home])
|
122
|
+
|
123
|
+
wallets = Zold::Wallets.new('.')
|
124
|
+
remotes = Zold::Remotes.new('./.zoldata/remotes')
|
125
|
+
copies = './.zoldata/copies'
|
123
126
|
|
124
127
|
case command
|
125
128
|
when 'node'
|
126
129
|
require_relative '../lib/zold/commands/node'
|
127
|
-
Zold::Node.new(log: log).run(args)
|
130
|
+
Zold::Node.new(wallets: wallets, remotes: remotes, copies: copies, log: log).run(args)
|
128
131
|
when 'create'
|
129
132
|
require_relative '../lib/zold/commands/create'
|
130
133
|
Zold::Create.new(wallets: wallets, log: log).run(args)
|
data/features/cli.feature
CHANGED
@@ -14,8 +14,3 @@ Feature: Command Line Processing
|
|
14
14
|
Scenario: Wallet can be created
|
15
15
|
When I run bin/zold with "--trace --public-key=id_rsa.pub create"
|
16
16
|
Then Exit code is zero
|
17
|
-
|
18
|
-
Scenario: Failure through nohup
|
19
|
-
When I run bin/zold-nohup with "badcommand --skip-install --log-file=log.txt; sleep 2; cat log.txt"
|
20
|
-
And Stdout contains "Command 'badcommand' is not supported"
|
21
|
-
Then Exit code is zero
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
set -x
|
4
|
+
shopt -s expand_aliases
|
5
|
+
|
6
|
+
alias zold="$1 --ignore-this-stupid-option --ignore-global-config --trace --network=test"
|
7
|
+
|
8
|
+
function reserve_port {
|
9
|
+
python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'
|
10
|
+
}
|
11
|
+
|
@@ -1,11 +1,6 @@
|
|
1
1
|
#!/bin/bash
|
2
|
-
set -x
|
3
|
-
set -e
|
4
|
-
shopt -s expand_aliases
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
port=`python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()'`
|
3
|
+
port=$(reserve_port)
|
9
4
|
|
10
5
|
mkdir server
|
11
6
|
cd server
|
@@ -27,8 +22,8 @@ zold remote trim
|
|
27
22
|
zold remote show
|
28
23
|
|
29
24
|
zold --public-key=id_rsa.pub create 0000000000000000
|
30
|
-
target
|
31
|
-
invoice
|
25
|
+
target=$(zold create --public-key=id_rsa.pub)
|
26
|
+
invoice=$(zold invoice ${target})
|
32
27
|
zold pay --private-key=id_rsa 0000000000000000 ${invoice} 14.99 'To save the world!'
|
33
28
|
zold propagate 0000000000000000
|
34
29
|
zold show
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
function start_node {
|
4
|
+
mkdir $1
|
5
|
+
cd $1
|
6
|
+
zold remote clean
|
7
|
+
zold node $3 --nohup --nohup-command='touch restarted' --nohup-log=log \
|
8
|
+
--expose-version=$2 --save-pid=pid --routine-immediately \
|
9
|
+
--verbose --trace --invoice=NOPREFIX@ffffffffffffffff \
|
10
|
+
--host=localhost --port=$1 --bind-port=$1 --threads=0 > /dev/null 2>&1
|
11
|
+
while ! nc -z localhost $1; do
|
12
|
+
sleep 1
|
13
|
+
((c++)) && ((c==10)) && exit -1
|
14
|
+
done
|
15
|
+
cat pid
|
16
|
+
cd ..
|
17
|
+
}
|
18
|
+
|
19
|
+
high=$(reserve_port)
|
20
|
+
primary=$(start_node ${high} 9.9.9 --standalone)
|
21
|
+
|
22
|
+
low=$(reserve_port)
|
23
|
+
secondary=$(start_node ${low} 1.1.1)
|
24
|
+
zold remote add localhost ${high} --home=${low}
|
25
|
+
|
26
|
+
while [ ! -f ${low}/restarted ]; do
|
27
|
+
sleep 1
|
28
|
+
((c++)) && ((c==10)) && break
|
29
|
+
done
|
30
|
+
|
31
|
+
kill -9 ${primary} ${secondary}
|
32
|
+
|
33
|
+
echo "High node logs (port ${high}):"
|
34
|
+
cat ${high}/log
|
35
|
+
echo "Low node logs (port ${low}):"
|
36
|
+
cat ${low}/log
|
37
|
+
|
38
|
+
if [ ! -f ${low}/restarted ]; then
|
39
|
+
exit -1
|
40
|
+
fi
|
data/lib/zold/commands/node.rb
CHANGED
@@ -19,8 +19,9 @@
|
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
21
|
require 'slop'
|
22
|
+
require_relative '../version'
|
22
23
|
require_relative '../score'
|
23
|
-
require_relative '../
|
24
|
+
require_relative '../metronome'
|
24
25
|
require_relative '../wallets'
|
25
26
|
require_relative '../remotes'
|
26
27
|
require_relative '../verbose_thread'
|
@@ -38,7 +39,10 @@ require_relative 'pay'
|
|
38
39
|
module Zold
|
39
40
|
# NODE command
|
40
41
|
class Node
|
41
|
-
def initialize(log: Log::Quiet.new)
|
42
|
+
def initialize(wallets:, remotes:, copies:, log: Log::Quiet.new)
|
43
|
+
@wallets = wallets
|
44
|
+
@remotes = remotes
|
45
|
+
@copies = copies
|
42
46
|
@log = log
|
43
47
|
end
|
44
48
|
|
@@ -46,7 +50,8 @@ module Zold
|
|
46
50
|
opts = Slop.parse(args, help: true, suppress_errors: true) do |o|
|
47
51
|
o.banner = 'Usage: zold node [options]'
|
48
52
|
o.string '--invoice',
|
49
|
-
'The invoice you want to collect money to or the wallet ID'
|
53
|
+
'The invoice you want to collect money to or the wallet ID',
|
54
|
+
required: true
|
50
55
|
o.integer '--port',
|
51
56
|
"TCP port to open for the Net (default: #{Remotes::PORT})",
|
52
57
|
default: Remotes::PORT
|
@@ -55,8 +60,6 @@ module Zold
|
|
55
60
|
default: Remotes::PORT
|
56
61
|
o.string '--host', "Host name (default: #{ip})",
|
57
62
|
default: ip
|
58
|
-
o.string '--home', 'Home directory (default: .)',
|
59
|
-
default: Dir.pwd
|
60
63
|
o.integer '--strength',
|
61
64
|
"The strength of the score (default: #{Score::STRENGTH})",
|
62
65
|
default: Score::STRENGTH
|
@@ -69,9 +72,26 @@ module Zold
|
|
69
72
|
o.bool '--ignore-score-weakness',
|
70
73
|
'Ignore score weakness of incoming requests and register those nodes anyway',
|
71
74
|
default: false
|
75
|
+
o.boolean '--nohup',
|
76
|
+
'Run it in background, rebooting when a higher version is available in the network',
|
77
|
+
default: false
|
78
|
+
o.string '--nohup-command',
|
79
|
+
'The command to run in server "nohup" mode (default: "gem install zold")',
|
80
|
+
default: 'gem install zold'
|
81
|
+
o.string '--nohup-log',
|
82
|
+
'The file to log output into (default: zold.log)',
|
83
|
+
default: 'zold.log'
|
84
|
+
o.string '--save-pid',
|
85
|
+
'The file to save process ID into right after start (only in NOHUP mode)'
|
72
86
|
o.bool '--never-reboot',
|
73
87
|
'Don\'t reboot when a new version shows up in the network',
|
74
88
|
default: false
|
89
|
+
o.bool '--routine-immediately',
|
90
|
+
'Run all routines immediately, without waiting between executions (for testing mostly)',
|
91
|
+
default: false
|
92
|
+
o.string '--expose-version',
|
93
|
+
"The version of the software to expose in JSON (default: #{VERSION})",
|
94
|
+
default: VERSION
|
75
95
|
o.string '--bonus-wallet',
|
76
96
|
'The ID of the wallet to regularly send bonuses from (for nodes online)'
|
77
97
|
o.string '--bonus-amount',
|
@@ -86,31 +106,35 @@ module Zold
|
|
86
106
|
@log.info(opts.to_s)
|
87
107
|
return
|
88
108
|
end
|
89
|
-
raise '--invoice is mandatory' unless opts[
|
109
|
+
raise '--invoice is mandatory' unless opts['invoice']
|
110
|
+
if opts[:nohup]
|
111
|
+
pid = nohup(opts)
|
112
|
+
File.write(opts['save-pid'], pid) if opts['save-pid']
|
113
|
+
@log.debug("Process ID #{pid} saved into \"#{opts['save-pid']}\"")
|
114
|
+
@log.info(pid)
|
115
|
+
return
|
116
|
+
end
|
90
117
|
Front.set(:log, @log)
|
118
|
+
Front.set(:version, opts['expose-version'])
|
91
119
|
Front.set(:logging, @log.debug?)
|
92
|
-
|
93
|
-
|
120
|
+
Front.set(:home, Dir.pwd)
|
121
|
+
@log.info("Home directory: #{Dir.pwd}")
|
94
122
|
Front.set(
|
95
123
|
:server_settings,
|
96
124
|
Logger: WebrickLog.new(@log),
|
97
125
|
AccessLog: []
|
98
126
|
)
|
99
127
|
if opts['standalone']
|
100
|
-
remotes = Remotes::Empty.new
|
128
|
+
@remotes = Remotes::Empty.new
|
101
129
|
@log.debug('Running in standalone mode! (will never talk to other remotes)')
|
102
|
-
else
|
103
|
-
remotes = Remotes.new(File.join(opts[:home], 'zold-remotes'))
|
104
130
|
end
|
105
131
|
Front.set(:ignore_score_weakness, opts['ignore-score-weakness'])
|
106
|
-
|
107
|
-
Front.set(:
|
108
|
-
Front.set(:
|
109
|
-
copies = File.join(opts[:home], 'zold-copies')
|
110
|
-
Front.set(:copies, copies)
|
132
|
+
Front.set(:wallets, @wallets)
|
133
|
+
Front.set(:remotes, @remotes)
|
134
|
+
Front.set(:copies, @copies)
|
111
135
|
address = "#{opts[:host]}:#{opts[:port]}".downcase
|
112
136
|
Front.set(:address, address)
|
113
|
-
entrance = Entrance.new(wallets, remotes, copies, address, log: @log)
|
137
|
+
entrance = Entrance.new(@wallets, @remotes, @copies, address, log: @log)
|
114
138
|
Front.set(:entrance, entrance)
|
115
139
|
Front.set(:root, Dir.pwd)
|
116
140
|
Front.set(:port, opts['bind-port'])
|
@@ -118,67 +142,76 @@ module Zold
|
|
118
142
|
invoice = opts[:invoice]
|
119
143
|
unless invoice.include?('@')
|
120
144
|
require_relative 'pull'
|
121
|
-
Pull.new(wallets: wallets, remotes: remotes, copies: copies, log: @log).run(['pull', invoice])
|
145
|
+
Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(['pull', invoice])
|
122
146
|
require_relative 'invoice'
|
123
|
-
invoice = Invoice.new(wallets: wallets, log: @log).run(['invoice', invoice])
|
147
|
+
invoice = Invoice.new(wallets: @wallets, log: @log).run(['invoice', invoice])
|
124
148
|
end
|
125
|
-
farm = Farm.new(invoice, File.join(
|
149
|
+
farm = Farm.new(invoice, File.join(Dir.pwd, 'farm'), log: @log)
|
126
150
|
farm.start(
|
127
|
-
opts[:host],
|
128
|
-
opts[:port],
|
151
|
+
opts[:host], opts[:port],
|
129
152
|
threads: opts[:threads], strength: opts[:strength]
|
130
153
|
)
|
131
154
|
Front.set(:farm, farm)
|
132
|
-
|
133
|
-
@log.debug("Starting up the web front at http://#{opts[:host]}:#{opts[:port]}...")
|
155
|
+
metronome = metronome(farm, opts)
|
134
156
|
begin
|
157
|
+
@log.info("Starting up the web front at http://#{opts[:host]}:#{opts[:port]}...")
|
135
158
|
Front.run!
|
136
159
|
ensure
|
137
160
|
farm.stop
|
138
|
-
|
161
|
+
metronome.stop
|
139
162
|
end
|
140
163
|
end
|
141
164
|
|
142
165
|
private
|
143
166
|
|
144
|
-
def
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
167
|
+
def exec(cmd, nohup_log)
|
168
|
+
Open3.popen2e(cmd) do |stdin, stdout, thr|
|
169
|
+
nohup_log.print("Started process ##{thr.pid} from process ##{Process.pid}: #{cmd}\n")
|
170
|
+
stdin.close
|
171
|
+
until stdout.eof?
|
172
|
+
line = stdout.gets
|
173
|
+
nohup_log.print(line)
|
174
|
+
end
|
175
|
+
code = thr.value.to_i
|
176
|
+
nohup_log.print("Exit code of process ##{thr.pid} is #{code}: #{cmd}\n")
|
177
|
+
raise "Exit code #{code} (non zero)" unless code.zero?
|
153
178
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
'--private-key', opts['private-key']
|
172
|
-
]
|
173
|
-
)
|
174
|
-
Push.new(wallets: wallets, remotes: remotes, log: @log).run(
|
175
|
-
['push', opts['bonus-wallet']]
|
176
|
-
)
|
177
|
-
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def nohup(opts)
|
182
|
+
pid = fork do
|
183
|
+
nohup_log = NohupLog.new(opts['nohup-log'])
|
184
|
+
Signal.trap('HUP') do
|
185
|
+
nohup_log.print("Received HUP, ignoring...\n")
|
186
|
+
end
|
187
|
+
Signal.trap('TERM') do
|
188
|
+
nohup_log.print("Received TERM, terminating...\n")
|
189
|
+
exit(-1)
|
190
|
+
end
|
191
|
+
myself = File.expand_path($PROGRAM_NAME)
|
192
|
+
loop do
|
193
|
+
VerboseThread.new.run do
|
194
|
+
exec("#{myself} #{ARGV.delete_if { |a| a.start_with?('--nohup') }.join(' ')}", nohup_log)
|
195
|
+
exec(opts['nohup-command'], nohup_log)
|
178
196
|
end
|
179
197
|
end
|
180
198
|
end
|
181
|
-
|
199
|
+
Process.detach(pid)
|
200
|
+
pid
|
201
|
+
end
|
202
|
+
|
203
|
+
def metronome(farm, opts)
|
204
|
+
metronome = Metronome.new(@log)
|
205
|
+
unless opts[:standalone]
|
206
|
+
require_relative 'routines/reconnect'
|
207
|
+
metronome.add(Routines::Reconnect.new(opts, @remotes, log: @log))
|
208
|
+
end
|
209
|
+
if opts['bonus-wallet']
|
210
|
+
require_relative 'routines/bonuses'
|
211
|
+
metronome.add(Routines::Bonuses.new(opts, @wallets, @remotes, @copies, farm, log: @log))
|
212
|
+
end
|
213
|
+
@log.info('Metronome created')
|
214
|
+
metronome
|
182
215
|
end
|
183
216
|
|
184
217
|
def ip
|
@@ -188,6 +221,17 @@ module Zold
|
|
188
221
|
addr.nil? ? '127.0.0.1' : addr.ip_address
|
189
222
|
end
|
190
223
|
|
224
|
+
# Log facility for nohup
|
225
|
+
class NohupLog
|
226
|
+
def initialize(file)
|
227
|
+
@file = file
|
228
|
+
end
|
229
|
+
|
230
|
+
def print(data)
|
231
|
+
File.open(@file, 'a') { |f| f.print(data) }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
191
235
|
# Fake logging facility for Webrick
|
192
236
|
class WebrickLog
|
193
237
|
def initialize(log)
|
data/lib/zold/commands/remote.rb
CHANGED
@@ -127,7 +127,7 @@ Available options:"
|
|
127
127
|
def add(host, port, opts)
|
128
128
|
if @remotes.exists?(host, port)
|
129
129
|
raise "#{host}:#{port} already exists in the list" unless opts['force']
|
130
|
-
@log.
|
130
|
+
@log.debug("#{host}:#{port} already exists in the list")
|
131
131
|
else
|
132
132
|
@remotes.add(host, port)
|
133
133
|
@log.info("#{host}:#{port} added to the list, #{@remotes.all.count} total")
|
@@ -141,7 +141,7 @@ Available options:"
|
|
141
141
|
@log.info("#{host}:#{port} removed from the list")
|
142
142
|
else
|
143
143
|
raise "#{host}:#{port} is not in the list" unless opts['force']
|
144
|
-
@log.
|
144
|
+
@log.debug("#{host}:#{port} is not in the list")
|
145
145
|
end
|
146
146
|
@log.info("There are #{@remotes.all.count} remote nodes in the list")
|
147
147
|
end
|
@@ -209,8 +209,7 @@ it's recommended to reboot, but I don't do it because of --never-reboot")
|
|
209
209
|
end
|
210
210
|
total = @remotes.all.size
|
211
211
|
if total.zero?
|
212
|
-
@log.debug("The list of remotes is #{Rainbow('empty').red}!")
|
213
|
-
@log.debug("Run 'zold remote add b1.zold.io` and then `zold update`")
|
212
|
+
@log.debug("The list of remotes is #{Rainbow('empty').red}, run 'zold reset'!")
|
214
213
|
else
|
215
214
|
@log.debug("There are #{total} known remotes")
|
216
215
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require_relative '../remote'
|
22
|
+
require_relative '../pull'
|
23
|
+
require_relative '../pay'
|
24
|
+
require_relative '../push'
|
25
|
+
|
26
|
+
# Pay bonuses routine.
|
27
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
28
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
29
|
+
# License:: MIT
|
30
|
+
module Zold
|
31
|
+
# Routines module
|
32
|
+
module Routines
|
33
|
+
# Pay bonuses to random nodes
|
34
|
+
class Bonuses
|
35
|
+
def initialize(opts, wallets, remotes, copies, farm, log: Log::Quiet.new)
|
36
|
+
@opts = opts
|
37
|
+
@wallets = wallets
|
38
|
+
@remotes = remotes
|
39
|
+
@copies = copies
|
40
|
+
@farm = farm
|
41
|
+
@log = log
|
42
|
+
end
|
43
|
+
|
44
|
+
def exec(_ = 0)
|
45
|
+
sleep(60 * 60) unless @opts['routine-immediately']
|
46
|
+
raise '--private-key is required to pay bonuses' unless @opts['private-key']
|
47
|
+
raise '--bonus-wallet is required to pay bonuses' unless @opts['bonus-wallet']
|
48
|
+
raise '--bonus-amount is required to pay bonuses' unless @opts['bonus-amount']
|
49
|
+
winners = Remote.new(remotes: @remotes, log: @log, farm: @farm).run(
|
50
|
+
['remote', 'elect', @opts['bonus-wallet'], '--private-key', @opts['private-key']]
|
51
|
+
)
|
52
|
+
if winners.empty?
|
53
|
+
@log.info('No winners elected, won\'t pay any bonuses')
|
54
|
+
return
|
55
|
+
end
|
56
|
+
winners.each do |score|
|
57
|
+
Pull.new(wallets: @wallets, remotes: @remotes, copies: @copies, log: @log).run(
|
58
|
+
['pull', opts['bonus-wallet']]
|
59
|
+
)
|
60
|
+
Pay.new(wallets: @wallets, remotes: @remotes, log: @log).run(
|
61
|
+
[
|
62
|
+
'pay', @opts['bonus-wallet'], score.invoice, @opts['bonus-amount'],
|
63
|
+
"Hosting bonus for #{score.host}:#{score.port} #{score.value}",
|
64
|
+
'--private-key', @opts['private-key']
|
65
|
+
]
|
66
|
+
)
|
67
|
+
Push.new(wallets: @wallets, remotes: @remotes, log: @log).run(
|
68
|
+
['push', @opts['bonus-wallet']]
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require_relative '../remote'
|
22
|
+
|
23
|
+
# Reconnect routine.
|
24
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
25
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
26
|
+
# License:: MIT
|
27
|
+
module Zold
|
28
|
+
# Routines module
|
29
|
+
module Routines
|
30
|
+
# Reconnect to the network
|
31
|
+
class Reconnect
|
32
|
+
def initialize(opts, remotes, log: Log::Quiet.new)
|
33
|
+
@opts = opts
|
34
|
+
@remotes = remotes
|
35
|
+
@log = log
|
36
|
+
end
|
37
|
+
|
38
|
+
def exec(_ = 0)
|
39
|
+
sleep(60) unless @opts['routine-immediately']
|
40
|
+
unless @opts['routine-immediately']
|
41
|
+
Remote.new(remotes: @remotes, log: @log).run(%w[remote add b1.zold.io 80 --force])
|
42
|
+
end
|
43
|
+
Remote.new(remotes: @remotes, log: @log).run(%w[remote trim])
|
44
|
+
Remote.new(remotes: @remotes, log: @log).run(
|
45
|
+
%w[remote update] + (@opts['never-reboot'] ? [] : ['--reboot'])
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -26,25 +26,28 @@ require_relative 'verbose_thread'
|
|
26
26
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
27
27
|
# License:: MIT
|
28
28
|
module Zold
|
29
|
-
#
|
30
|
-
class
|
29
|
+
# Metronome
|
30
|
+
class Metronome
|
31
31
|
def initialize(log = Log::Quiet.new)
|
32
32
|
@log = log
|
33
33
|
@threads = []
|
34
34
|
end
|
35
35
|
|
36
|
-
def add(
|
36
|
+
def add(routine)
|
37
37
|
@threads << Thread.start do
|
38
38
|
VerboseThread.new(@log).run(true) do
|
39
|
-
Thread.current.name =
|
40
|
-
|
39
|
+
Thread.current.name = routine.class.name
|
40
|
+
step = 0
|
41
41
|
loop do
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
start = Time.now
|
43
|
+
routine.exec(step)
|
44
|
+
sleep(1)
|
45
|
+
step += 1
|
46
|
+
@log.debug("Routine #{routine.class.name} ##{step} done in #{((Time.now - start) / 60).round(2)}s)")
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
50
|
+
@log.info("Added #{routine.class.name} to the metronome")
|
48
51
|
end
|
49
52
|
|
50
53
|
def stop
|
data/lib/zold/node/front.rb
CHANGED
@@ -47,6 +47,7 @@ module Zold
|
|
47
47
|
set :lock, false
|
48
48
|
set :show_exceptions, false
|
49
49
|
set :server, 'webrick'
|
50
|
+
set :version, VERSION # to be injected at node.rb
|
50
51
|
set :ignore_score_weakness, false # to be injected at node.rb
|
51
52
|
set :reboot, false # to be injected at node.rb
|
52
53
|
set :home, nil? # to be injected at node.rb
|
@@ -84,7 +85,7 @@ module Zold
|
|
84
85
|
after do
|
85
86
|
headers['Cache-Control'] = 'no-cache'
|
86
87
|
headers['Connection'] = 'close'
|
87
|
-
headers['X-Zold-Version'] =
|
88
|
+
headers['X-Zold-Version'] = settings.version
|
88
89
|
headers['Access-Control-Allow-Origin'] = '*'
|
89
90
|
headers[Http::SCORE_HEADER] = score.reduced(16).to_s
|
90
91
|
end
|
@@ -96,7 +97,7 @@ module Zold
|
|
96
97
|
|
97
98
|
get '/version' do
|
98
99
|
content_type 'text/plain'
|
99
|
-
|
100
|
+
settings.version
|
100
101
|
end
|
101
102
|
|
102
103
|
get '/score' do
|
@@ -117,7 +118,7 @@ module Zold
|
|
117
118
|
get '/' do
|
118
119
|
content_type 'application/json'
|
119
120
|
JSON.pretty_generate(
|
120
|
-
version:
|
121
|
+
version: settings.version,
|
121
122
|
score: score.to_h,
|
122
123
|
pid: Process.pid,
|
123
124
|
cpus: Concurrent.processor_count,
|
@@ -139,7 +140,7 @@ module Zold
|
|
139
140
|
error 404 unless wallet.exists?
|
140
141
|
content_type 'application/json'
|
141
142
|
{
|
142
|
-
version:
|
143
|
+
version: settings.version,
|
143
144
|
score: score.to_h,
|
144
145
|
body: AtomicFile.new(wallet.path).read
|
145
146
|
}.to_json
|
@@ -172,7 +173,7 @@ module Zold
|
|
172
173
|
settings.log.info("Wallet #{id} is new: #{before.length}b != #{after.length}b")
|
173
174
|
settings.entrance.push(id, after, sync: !params[:sync].nil?)
|
174
175
|
JSON.pretty_generate(
|
175
|
-
version:
|
176
|
+
version: settings.version,
|
176
177
|
score: score.to_h
|
177
178
|
)
|
178
179
|
end
|
@@ -180,7 +181,7 @@ module Zold
|
|
180
181
|
get '/remotes' do
|
181
182
|
content_type 'application/json'
|
182
183
|
JSON.pretty_generate(
|
183
|
-
version:
|
184
|
+
version: settings.version,
|
184
185
|
score: score.to_h,
|
185
186
|
all: settings.remotes.all
|
186
187
|
)
|
data/lib/zold/version.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'minitest/autorun'
|
22
|
+
require_relative '../../test__helper'
|
23
|
+
require_relative '../../fake_home'
|
24
|
+
require_relative '../../../lib/zold/node/farm.rb'
|
25
|
+
require_relative '../../../lib/zold/commands/routines/bonuses.rb'
|
26
|
+
|
27
|
+
# Bonuses test.
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class TestBonuses < Minitest::Test
|
32
|
+
def test_pays_bonuses
|
33
|
+
FakeHome.new.run do |home|
|
34
|
+
wallet = home.create_wallet
|
35
|
+
opts = {
|
36
|
+
'routine-immediately' => true,
|
37
|
+
'private-key' => 'fixtures/id_rsa',
|
38
|
+
'bonus-wallet' => wallet.id.to_s,
|
39
|
+
'bonus-amount' => 1
|
40
|
+
}
|
41
|
+
routine = Zold::Routines::Bonuses.new(
|
42
|
+
opts, home.wallets, home.remotes, home.copies(wallet).root,
|
43
|
+
Zold::Farm::Empty, log: test_log
|
44
|
+
)
|
45
|
+
routine.exec
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Copyright (c) 2018 Yegor Bugayenko
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in all
|
11
|
+
# copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
require 'minitest/autorun'
|
22
|
+
require 'tmpdir'
|
23
|
+
require 'webmock/minitest'
|
24
|
+
require_relative '../../test__helper'
|
25
|
+
require_relative '../../../lib/zold/remotes'
|
26
|
+
require_relative '../../../lib/zold/commands/routines/reconnect.rb'
|
27
|
+
|
28
|
+
# Reconnect test.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
class TestReconnect < Minitest::Test
|
33
|
+
def test_reconnects
|
34
|
+
Dir.mktmpdir 'test' do |dir|
|
35
|
+
remotes = Zold::Remotes.new(File.join(dir, 'remotes.csv'))
|
36
|
+
remotes.clean
|
37
|
+
stub_request(:get, 'http://b1.zold.io:80/remotes').to_return(status: 404)
|
38
|
+
opts = { 'never-reboot' => true, 'routine-immediately' => true }
|
39
|
+
routine = Zold::Routines::Reconnect.new(opts, remotes, log: test_log)
|
40
|
+
routine.exec
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/test/commands/test_node.rb
CHANGED
@@ -38,21 +38,18 @@ require_relative '../node/fake_node'
|
|
38
38
|
# License:: MIT
|
39
39
|
class TestNode < Minitest::Test
|
40
40
|
def test_push_and_fetch
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
wallet.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
47
|
-
remotes = Zold::Remotes.new(File.join(dir, 'remotes.csv'))
|
48
|
-
remotes.clean
|
41
|
+
FakeHome.new.run do |home|
|
42
|
+
FakeNode.new(log: test_log).run do |port|
|
43
|
+
wallets = home.wallets
|
44
|
+
wallet = home.create_wallet
|
45
|
+
remotes = home.remotes
|
49
46
|
remotes.add('localhost', port)
|
50
47
|
Zold::Push.new(wallets: wallets, remotes: remotes, log: test_log).run(['push', '--sync'])
|
48
|
+
copies = home.copies(wallet)
|
51
49
|
Zold::Fetch.new(
|
52
|
-
wallets: wallets, copies:
|
50
|
+
wallets: wallets, copies: copies.root,
|
53
51
|
remotes: remotes, log: test_log
|
54
52
|
).run(['fetch'])
|
55
|
-
copies = Zold::Copies.new(File.join(dir, "copies/#{id}"))
|
56
53
|
assert_equal(1, copies.all.count)
|
57
54
|
assert_equal('1', copies.all[0][:name])
|
58
55
|
end
|
data/test/commands/test_taxes.rb
CHANGED
@@ -22,6 +22,7 @@ require 'minitest/autorun'
|
|
22
22
|
require 'tmpdir'
|
23
23
|
require 'webmock/minitest'
|
24
24
|
require_relative '../test__helper'
|
25
|
+
require_relative '../fake_home'
|
25
26
|
require_relative '../../lib/zold/wallets'
|
26
27
|
require_relative '../../lib/zold/amount'
|
27
28
|
require_relative '../../lib/zold/key'
|
@@ -35,11 +36,9 @@ require_relative '../../lib/zold/commands/taxes'
|
|
35
36
|
# License:: MIT
|
36
37
|
class TestTaxes < Minitest::Test
|
37
38
|
def test_pays_taxes
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
wallet = wallets.find(id)
|
42
|
-
wallet.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
39
|
+
FakeHome.new.run do |home|
|
40
|
+
wallets = home.wallets
|
41
|
+
wallet = home.create_wallet
|
43
42
|
wallet.add(
|
44
43
|
Zold::Txn.new(
|
45
44
|
1,
|
@@ -48,8 +47,7 @@ class TestTaxes < Minitest::Test
|
|
48
47
|
'NOPREFIX', Zold::Id.new, '-'
|
49
48
|
)
|
50
49
|
)
|
51
|
-
remotes =
|
52
|
-
remotes.clean
|
50
|
+
remotes = home.remotes
|
53
51
|
zero = Zold::Score::ZERO
|
54
52
|
remotes.add(zero.host, zero.port)
|
55
53
|
stub_request(:get, "http://#{zero.host}:#{zero.port}/").to_return(
|
@@ -60,7 +58,7 @@ class TestTaxes < Minitest::Test
|
|
60
58
|
)
|
61
59
|
Zold::Taxes.new(
|
62
60
|
wallets: wallets, remotes: remotes, log: test_log
|
63
|
-
).run(['taxes', '--private-key=fixtures/id_rsa', id.to_s])
|
61
|
+
).run(['taxes', '--private-key=fixtures/id_rsa', wallet.id.to_s])
|
64
62
|
assert_equal(Zold::Amount.new(coins: 85_856_396_247), wallet.balance)
|
65
63
|
end
|
66
64
|
end
|
data/test/fake_home.rb
CHANGED
@@ -21,6 +21,7 @@
|
|
21
21
|
require 'tmpdir'
|
22
22
|
require_relative '../lib/zold/id'
|
23
23
|
require_relative '../lib/zold/wallet'
|
24
|
+
require_relative '../lib/zold/wallets'
|
24
25
|
require_relative '../lib/zold/key'
|
25
26
|
|
26
27
|
# Fake home dir.
|
@@ -29,12 +30,13 @@ require_relative '../lib/zold/key'
|
|
29
30
|
# License:: MIT
|
30
31
|
class FakeHome
|
31
32
|
attr_reader :dir
|
32
|
-
def initialize(dir =
|
33
|
+
def initialize(dir = __dir__)
|
33
34
|
@dir = dir
|
34
35
|
end
|
35
36
|
|
36
37
|
def run
|
37
38
|
Dir.mktmpdir 'test' do |dir|
|
39
|
+
FileUtils.copy(File.join(__dir__, '../fixtures/id_rsa'), File.join(dir, 'id_rsa'))
|
38
40
|
yield FakeHome.new(dir)
|
39
41
|
end
|
40
42
|
end
|
@@ -45,11 +47,11 @@ class FakeHome
|
|
45
47
|
|
46
48
|
def create_wallet(id = Zold::Id.new)
|
47
49
|
wallet = Zold::Wallet.new(File.join(@dir, id.to_s))
|
48
|
-
wallet.init(id, Zold::Key.new(file: 'fixtures/id_rsa.pub'))
|
50
|
+
wallet.init(id, Zold::Key.new(file: File.join(__dir__, '../fixtures/id_rsa.pub')))
|
49
51
|
wallet
|
50
52
|
end
|
51
53
|
|
52
|
-
def copies(wallet)
|
54
|
+
def copies(wallet = create_wallet)
|
53
55
|
Zold::Copies.new(File.join(@dir, "copies/#{wallet.id}"))
|
54
56
|
end
|
55
57
|
|
data/test/node/fake_node.rb
CHANGED
@@ -20,6 +20,7 @@
|
|
20
20
|
|
21
21
|
require 'tmpdir'
|
22
22
|
require 'webmock/minitest'
|
23
|
+
require_relative '../fake_home'
|
23
24
|
require_relative '../../lib/zold/log'
|
24
25
|
require_relative '../../lib/zold/http'
|
25
26
|
require_relative '../../lib/zold/verbose_thread'
|
@@ -35,36 +36,37 @@ class FakeNode
|
|
35
36
|
|
36
37
|
def run(args = ['--standalone'])
|
37
38
|
WebMock.allow_net_connect!
|
38
|
-
Dir.
|
39
|
+
start = Dir.pwd
|
40
|
+
FakeHome.new.run do |home|
|
39
41
|
server = TCPServer.new('127.0.0.1', 0)
|
40
42
|
port = server.addr[1]
|
41
43
|
server.close
|
42
44
|
node = Thread.new do
|
43
45
|
Zold::VerboseThread.new(@log).run do
|
44
46
|
Thread.current.abort_on_exception = true
|
45
|
-
home
|
47
|
+
Dir.chdir(home.dir)
|
46
48
|
require_relative '../../lib/zold/commands/node'
|
47
|
-
Zold::Node.new(log: @log).run(
|
49
|
+
Zold::Node.new(wallets: home.wallets, remotes: home.remotes, copies: home.copies.root, log: @log).run(
|
48
50
|
[
|
49
51
|
'--port', port.to_s,
|
50
52
|
'--host=localhost',
|
51
53
|
'--bind-port', port.to_s,
|
52
54
|
'--threads=1',
|
53
|
-
'--home', home,
|
54
55
|
'--invoice=NOPREFIX@ffffffffffffffff'
|
55
56
|
] + args
|
56
57
|
)
|
57
58
|
end
|
58
59
|
end
|
59
|
-
|
60
|
-
while Zold::Http.new(
|
60
|
+
uri = "http://localhost:#{port}/"
|
61
|
+
while Zold::Http.new(uri).get.code == '599' && node.alive?
|
61
62
|
sleep 1
|
62
|
-
@log.debug("Waiting for #{
|
63
|
+
@log.debug("Waiting for #{uri}...")
|
63
64
|
end
|
64
65
|
begin
|
65
66
|
yield port
|
66
67
|
ensure
|
67
68
|
node.exit
|
69
|
+
Dir.chdir(start)
|
68
70
|
end
|
69
71
|
end
|
70
72
|
end
|
data/test/test__helper.rb
CHANGED
@@ -18,6 +18,11 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
19
|
# SOFTWARE.
|
20
20
|
|
21
|
+
gem 'openssl'
|
22
|
+
require 'openssl'
|
23
|
+
require 'minitest/autorun'
|
24
|
+
require_relative '../lib/zold'
|
25
|
+
|
21
26
|
STDOUT.sync = true
|
22
27
|
|
23
28
|
ENV['RACK_ENV'] = 'test'
|
@@ -29,12 +34,6 @@ if ENV['CI'] == 'true'
|
|
29
34
|
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
30
35
|
end
|
31
36
|
|
32
|
-
require 'minitest/autorun'
|
33
|
-
require_relative '../lib/zold'
|
34
|
-
|
35
|
-
gem 'openssl'
|
36
|
-
require 'openssl'
|
37
|
-
|
38
37
|
module Minitest
|
39
38
|
class Test
|
40
39
|
def test_log
|
@@ -20,22 +20,30 @@
|
|
20
20
|
|
21
21
|
require 'minitest/autorun'
|
22
22
|
require_relative 'test__helper'
|
23
|
-
require_relative '../lib/zold/
|
23
|
+
require_relative '../lib/zold/metronome'
|
24
24
|
|
25
|
-
#
|
25
|
+
# Metronome test.
|
26
26
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
27
27
|
# Copyright:: Copyright (c) 2018 Yegor Bugayenko
|
28
28
|
# License:: MIT
|
29
|
-
class
|
29
|
+
class TestMetronome < Minitest::Test
|
30
30
|
def test_start_and_stop
|
31
|
-
routines = Zold::
|
31
|
+
routines = Zold::Metronome.new(test_log)
|
32
32
|
list = []
|
33
|
-
routines.add(
|
34
|
-
list << i
|
35
|
-
sleep(6000)
|
36
|
-
end
|
33
|
+
routines.add(FakeRoutine.new(list))
|
37
34
|
sleep 0.1 while list.empty?
|
38
35
|
routines.stop
|
39
36
|
assert_equal(1, list.count)
|
40
37
|
end
|
38
|
+
|
39
|
+
class FakeRoutine
|
40
|
+
def initialize(list)
|
41
|
+
@list = list
|
42
|
+
end
|
43
|
+
|
44
|
+
def exec(i)
|
45
|
+
@list << i
|
46
|
+
sleep(6000)
|
47
|
+
end
|
48
|
+
end
|
41
49
|
end
|
data/test/test_zold.rb
CHANGED
@@ -29,12 +29,12 @@ require_relative 'test__helper'
|
|
29
29
|
# License:: MIT
|
30
30
|
class TestZold < Minitest::Test
|
31
31
|
def test_all_scripts
|
32
|
-
Dir.new('fixtures/scripts').each.select { |f| f =~ /\.sh$/ }.each do |f|
|
32
|
+
Dir.new('fixtures/scripts').each.select { |f| f =~ /\.sh$/ && !f.start_with?('_') }.each do |f|
|
33
33
|
Dir.mktmpdir 'test' do |dir|
|
34
34
|
FileUtils.cp('fixtures/id_rsa.pub', dir)
|
35
35
|
FileUtils.cp('fixtures/id_rsa', dir)
|
36
36
|
script = File.join(dir, f)
|
37
|
-
|
37
|
+
File.write(script, File.read('fixtures/scripts/_head.sh') + File.read(File.join('fixtures/scripts', f)))
|
38
38
|
bin = File.join(Dir.pwd, 'bin/zold')
|
39
39
|
Dir.chdir(dir) do
|
40
40
|
stdout = `/bin/bash #{f} #{bin} 2>&1`
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zold
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -277,7 +277,6 @@ description: |-
|
|
277
277
|
email: yegor256@gmail.com
|
278
278
|
executables:
|
279
279
|
- zold
|
280
|
-
- zold-nohup
|
281
280
|
extensions: []
|
282
281
|
extra_rdoc_files:
|
283
282
|
- README.md
|
@@ -300,7 +299,6 @@ files:
|
|
300
299
|
- Rakefile
|
301
300
|
- appveyor.yml
|
302
301
|
- bin/zold
|
303
|
-
- bin/zold-nohup
|
304
302
|
- cucumber.yml
|
305
303
|
- deploy.sh
|
306
304
|
- features/cli.feature
|
@@ -314,10 +312,11 @@ files:
|
|
314
312
|
- fixtures/keys/1.pub
|
315
313
|
- fixtures/keys/2
|
316
314
|
- fixtures/keys/2.pub
|
315
|
+
- fixtures/scripts/_head.sh
|
317
316
|
- fixtures/scripts/calculate-scores.sh
|
318
317
|
- fixtures/scripts/print-helps.sh
|
319
318
|
- fixtures/scripts/push-and-pull.sh
|
320
|
-
- fixtures/scripts/
|
319
|
+
- fixtures/scripts/redeploy-on-upgrade.sh
|
321
320
|
- heroku.yml
|
322
321
|
- lib/zold.rb
|
323
322
|
- lib/zold/amount.rb
|
@@ -337,6 +336,8 @@ files:
|
|
337
336
|
- lib/zold/commands/pull.rb
|
338
337
|
- lib/zold/commands/push.rb
|
339
338
|
- lib/zold/commands/remote.rb
|
339
|
+
- lib/zold/commands/routines/bonuses.rb
|
340
|
+
- lib/zold/commands/routines/reconnect.rb
|
340
341
|
- lib/zold/commands/show.rb
|
341
342
|
- lib/zold/commands/taxes.rb
|
342
343
|
- lib/zold/copies.rb
|
@@ -345,6 +346,7 @@ files:
|
|
345
346
|
- lib/zold/id.rb
|
346
347
|
- lib/zold/key.rb
|
347
348
|
- lib/zold/log.rb
|
349
|
+
- lib/zold/metronome.rb
|
348
350
|
- lib/zold/node/emission.rb
|
349
351
|
- lib/zold/node/entrance.rb
|
350
352
|
- lib/zold/node/farm.rb
|
@@ -352,7 +354,6 @@ files:
|
|
352
354
|
- lib/zold/patch.rb
|
353
355
|
- lib/zold/prefixes.rb
|
354
356
|
- lib/zold/remotes.rb
|
355
|
-
- lib/zold/routines.rb
|
356
357
|
- lib/zold/score.rb
|
357
358
|
- lib/zold/signature.rb
|
358
359
|
- lib/zold/tax.rb
|
@@ -362,6 +363,8 @@ files:
|
|
362
363
|
- lib/zold/wallet.rb
|
363
364
|
- lib/zold/wallets.rb
|
364
365
|
- resources/remotes
|
366
|
+
- test/commands/routines/test_bonuses.rb
|
367
|
+
- test/commands/routines/test_reconnect.rb
|
365
368
|
- test/commands/test_calculate.rb
|
366
369
|
- test/commands/test_clean.rb
|
367
370
|
- test/commands/test_create.rb
|
@@ -391,10 +394,10 @@ files:
|
|
391
394
|
- test/test_http.rb
|
392
395
|
- test/test_id.rb
|
393
396
|
- test/test_key.rb
|
397
|
+
- test/test_metronome.rb
|
394
398
|
- test/test_patch.rb
|
395
399
|
- test/test_prefixes.rb
|
396
400
|
- test/test_remotes.rb
|
397
|
-
- test/test_routines.rb
|
398
401
|
- test/test_score.rb
|
399
402
|
- test/test_signature.rb
|
400
403
|
- test/test_tax.rb
|
@@ -434,6 +437,8 @@ test_files:
|
|
434
437
|
- features/gem_package.feature
|
435
438
|
- features/step_definitions/steps.rb
|
436
439
|
- features/support/env.rb
|
440
|
+
- test/commands/routines/test_bonuses.rb
|
441
|
+
- test/commands/routines/test_reconnect.rb
|
437
442
|
- test/commands/test_calculate.rb
|
438
443
|
- test/commands/test_clean.rb
|
439
444
|
- test/commands/test_create.rb
|
@@ -463,10 +468,10 @@ test_files:
|
|
463
468
|
- test/test_http.rb
|
464
469
|
- test/test_id.rb
|
465
470
|
- test/test_key.rb
|
471
|
+
- test/test_metronome.rb
|
466
472
|
- test/test_patch.rb
|
467
473
|
- test/test_prefixes.rb
|
468
474
|
- test/test_remotes.rb
|
469
|
-
- test/test_routines.rb
|
470
475
|
- test/test_score.rb
|
471
476
|
- test/test_signature.rb
|
472
477
|
- test/test_tax.rb
|
data/bin/zold-nohup
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# Copyright (c) 2018 Yegor Bugayenko
|
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 all
|
13
|
-
# 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 NONINFINGEMENT. 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 THE
|
21
|
-
# SOFTWARE.
|
22
|
-
|
23
|
-
STDOUT.sync = true
|
24
|
-
|
25
|
-
require 'slop'
|
26
|
-
require 'tempfile'
|
27
|
-
require 'open3'
|
28
|
-
|
29
|
-
$opts = Slop.parse(ARGV, strict: false, suppress_errors: true) do |o|
|
30
|
-
o.banner = "Usage: zold-nohup [options] ...
|
31
|
-
Run 'zold --help' for the full list of options and commands"
|
32
|
-
o.bool '-h', '--help', 'Show these instructions'
|
33
|
-
o.string '--log-file',
|
34
|
-
'The file to save logs into (default: ./zold-nohup.log)',
|
35
|
-
default: './zold-nohup.log'
|
36
|
-
o.bool '--skip-log-trim',
|
37
|
-
'Don\'t trim the log file before start (default: false)',
|
38
|
-
default: false
|
39
|
-
o.bool '--skip-install',
|
40
|
-
'Don\'t re-install Zold gem (default: false)',
|
41
|
-
default: false
|
42
|
-
o.bool '--sudo-install',
|
43
|
-
'Install Zold gem via sudo (default: false)',
|
44
|
-
default: false
|
45
|
-
end
|
46
|
-
|
47
|
-
if $opts.help?
|
48
|
-
puts($opts.to_s)
|
49
|
-
exit(0)
|
50
|
-
end
|
51
|
-
|
52
|
-
def log(line)
|
53
|
-
File.open($opts['log-file'], 'a') { |f| f.print(line) }
|
54
|
-
end
|
55
|
-
|
56
|
-
def exec(cmd)
|
57
|
-
Open3.popen2e(cmd) do |stdin, stdout, thr|
|
58
|
-
log("Started: #{cmd}\n")
|
59
|
-
stdin.close
|
60
|
-
until stdout.eof?
|
61
|
-
begin
|
62
|
-
data = stdout.read_nonblock(1024) unless stdout.eof?
|
63
|
-
rescue EOFError => _
|
64
|
-
break
|
65
|
-
end
|
66
|
-
log(data)
|
67
|
-
end
|
68
|
-
code = thr.value.to_i
|
69
|
-
log("Exit code is #{code}: #{cmd}\n")
|
70
|
-
raise "Exit code #{code} (non zero)" unless code.zero?
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
File.delete($opts['log-file']) if File.exist?($opts['log-file']) && !$opts['skip-log-trim']
|
75
|
-
|
76
|
-
$pid = fork do
|
77
|
-
Signal.trap('HUP') do
|
78
|
-
log("Received HUP, ignoring...\n")
|
79
|
-
end
|
80
|
-
Signal.trap('TERM') do
|
81
|
-
log("Received TERM, terminating...\n")
|
82
|
-
exit(-1)
|
83
|
-
end
|
84
|
-
loop do
|
85
|
-
begin
|
86
|
-
exec("zold #{$opts.arguments.join(' ')}")
|
87
|
-
exec(($opts['sudo-install'] ? 'sudo ' : '') + 'gem install zold') unless $opts['skip-install']
|
88
|
-
rescue StandardError => e
|
89
|
-
log("#{e.class.name}: #{e.message}\n#{e.backtrace.join("\n\t")}\n")
|
90
|
-
raise e
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
Process.detach($pid)
|
95
|
-
|
96
|
-
puts($pid)
|