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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 19349592bdbaac460eacf4a7dcb6d5815adb4c95
4
- data.tar.gz: a8dcbc34dfdd0206075ba30fd7c738c59a590747
3
+ metadata.gz: ffdbb36409b1e6f281cd278d24e6c2994da8a845
4
+ data.tar.gz: 10e1b526ef486b2e77d225b42c8fc550c0f5c9fc
5
5
  SHA512:
6
- metadata.gz: ae0cc88be90477961fec60dd68a1157118dac2f1e7bddecc276b26c5115015c8a1c281198dd18fc6ff2a2d79824d93640c922ca4ab1b4c699845cff88607f393
7
- data.tar.gz: 670dedb53ebc3d1fc62872ad88684337e9ddddf35f64013033f6b0ba463c0335ec9660ec3b388cde516c1db27825a33174b93855d50b07fcabb1795c1dfcefd8
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 --trace --verbose --invoice=5f96e731e48ae21f --host=4.4.4.4
93
+ $ zold node --invoice=5f96e731e48ae21f
95
94
  ```
96
95
 
97
- Then, open the page `4.4.4.4:4096` in your browser
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 instead
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-nohup node --trace --verbose --invoice=5f96e731e48ae21f --host=4.4.4.4
103
+ $ zold node --nohup --invoice=5f96e731e48ae21f > log.txt
106
104
  ```
107
105
 
108
- Now you can close console, it will work in the background, saving the
109
- output logs to `nohup.out`. The software will update itself automatically to new versions.
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 '-d', '--dir',
91
- 'The directory where wallets are stored (default: .)',
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
- wallets = Zold::Wallets.new(opts['dir'])
121
- remotes = Zold::Remotes.new(File.join(opts['dir'], '.zoldata/remotes'))
122
- copies = File.join(opts['dir'], '.zoldata/copies')
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)
@@ -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,8 +1,3 @@
1
1
  #!/bin/bash
2
- set -x
3
- set -e
4
- shopt -s expand_aliases
5
-
6
- alias zold="$1 --ignore-global-config --trace --network=test"
7
2
 
8
3
  zold score --host=zold.io --port=4096 --invoice=NOSUFFIX@ffffffffffffffff --strength=2 --max=5
@@ -1,9 +1,4 @@
1
1
  #!/bin/bash
2
- set -x
3
- set -e
4
- shopt -s expand_aliases
5
-
6
- alias zold="$1 --ignore-global-config --trace --network=test"
7
2
 
8
3
  zold --help
9
4
  declare -a commands=(node create invoice remote pay show fetch clean diff merge propagate pull push taxes)
@@ -1,11 +1,6 @@
1
1
  #!/bin/bash
2
- set -x
3
- set -e
4
- shopt -s expand_aliases
5
2
 
6
- alias zold="$1 --ignore-global-config --trace --ignore-this-stupid-option --network=test"
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=`zold create --public-key=id_rsa.pub`
31
- invoice=`zold invoice ${target}`
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
@@ -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 '../routines'
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[:invoice]
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
- FileUtils.mkdir_p(opts[:home])
93
- Front.set(:home, opts[:home])
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
- wallets = Wallets.new(File.join(opts[:home], 'zold-wallets'))
107
- Front.set(:wallets, wallets)
108
- Front.set(:remotes, remotes)
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(opts[:home], 'farm'), log: @log)
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
- routines = routines(wallets, remotes, copies, farm, opts)
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
- routines.stop
161
+ metronome.stop
139
162
  end
140
163
  end
141
164
 
142
165
  private
143
166
 
144
- def routines(wallets, remotes, copies, farm, opts)
145
- routines = Routines.new(@log)
146
- routines.add do
147
- require_relative 'remote'
148
- Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote add b1.zold.io 80 --force])
149
- Remote.new(remotes: remotes, log: @log, farm: farm).run(%w[remote trim])
150
- Remote.new(remotes: remotes, log: @log, farm: farm).run(
151
- %w[remote update] + (opts['never-reboot'] ? [] : ['--reboot'])
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
- if opts['bonus-wallet']
155
- routines.add(60) do
156
- require_relative 'remote'
157
- winners = Remote.new(remotes: remotes, log: @log, farm: farm).run(
158
- ['remote', 'elect', opts['bonus-wallet'], '--private-key', opts['private-key']]
159
- )
160
- if winners.empty?
161
- @log.info('No winners elected, won\'t pay any bonuses')
162
- else
163
- winners.each do |score|
164
- Pull.new(wallets: wallets, remotes: remotes, copies: copies, log: @log).run(
165
- ['pull', opts['bonus-wallet']]
166
- )
167
- Pay.new(wallets: wallets, remotes: remotes, log: @log).run(
168
- [
169
- 'pay', opts['bonus-wallet'], score.invoice, opts['bonus-amount'],
170
- "Hosting bonus for #{score.host}:#{score.port} #{score.value}",
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
- routines
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)
@@ -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.info("#{host}:#{port} already exists in the list")
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.info("#{host}:#{port} is not in the list")
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
- # NODE command
30
- class Routines
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(minutes = 1)
36
+ def add(routine)
37
37
  @threads << Thread.start do
38
38
  VerboseThread.new(@log).run(true) do
39
- Thread.current.name = 'routines'
40
- count = 0
39
+ Thread.current.name = routine.class.name
40
+ step = 0
41
41
  loop do
42
- sleep(minutes * 60)
43
- yield count
44
- count += 1
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
@@ -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'] = 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
- VERSION
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: 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: 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: 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: VERSION,
184
+ version: settings.version,
184
185
  score: score.to_h,
185
186
  all: settings.remotes.all
186
187
  )
@@ -23,5 +23,5 @@
23
23
  # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
24
  # License:: MIT
25
25
  module Zold
26
- VERSION = '0.12.1'.freeze
26
+ VERSION = '0.13.0'.freeze
27
27
  end
@@ -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
@@ -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
- FakeNode.new(log: test_log).run do |port|
42
- Dir.mktmpdir 'test' do |dir|
43
- id = Zold::Id.new
44
- wallets = Zold::Wallets.new(dir)
45
- wallet = wallets.find(id)
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: File.join(dir, '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
@@ -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
- Dir.mktmpdir 'test' do |dir|
39
- id = Zold::Id.new
40
- wallets = Zold::Wallets.new(dir)
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 = Zold::Remotes.new(File.join(dir, 'a/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
@@ -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 = Dir.pwd)
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
 
@@ -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.mktmpdir 'test' do |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 = File.join(dir, 'node-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
- home = "http://localhost:#{port}/"
60
- while Zold::Http.new(home).get.code == '599' && node.alive?
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 #{home}...")
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
@@ -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/routines'
23
+ require_relative '../lib/zold/metronome'
24
24
 
25
- # Routines test.
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 TestRoutines < Minitest::Test
29
+ class TestMetronome < Minitest::Test
30
30
  def test_start_and_stop
31
- routines = Zold::Routines.new
31
+ routines = Zold::Metronome.new(test_log)
32
32
  list = []
33
- routines.add(0) do |i|
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
@@ -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
- FileUtils.cp("fixtures/scripts/#{f}", script)
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.12.1
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-10 00:00:00.000000000 Z
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/with-nohup.sh
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
@@ -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)
@@ -1,8 +0,0 @@
1
- #!/bin/bash
2
- set -x
3
- set -e
4
- shopt -s expand_aliases
5
-
6
- alias zold="$1-nohup"
7
-
8
- zold --help