zold 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|