lib/zold/node/front.rb in zold-0.16.2 vs lib/zold/node/front.rb in zold-0.16.3

- old
+ new

@@ -20,13 +20,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. STDOUT.sync = true +require 'eventmachine' +require 'thin' require 'json' require 'sinatra/base' -require 'webrick' require 'cachy' require 'moneta' require 'get_process_mem' require 'diffy' require 'usagewatch_ext' @@ -54,11 +55,11 @@ set :bind, '0.0.0.0' set :suppress_messages, true set :start, Time.now set :lock, false set :show_exceptions, false - set :server, :puma + set :server, :thin set :log, nil? # to be injected at node.rb set :trace, nil? # to be injected at node.rb set :halt, '' # to be injected at node.rb set :dump_errors, false # to be injected at node.rb set :version, VERSION # to be injected at node.rb @@ -80,23 +81,24 @@ set :node_alias, nil? # to be injected at node.rb end use Rack::Deflater before do + @start = Time.now if !settings.halt.empty? && params[:halt] && params[:halt] == settings.halt settings.log.error('Halt signal received, shutting the front end down...') Front.stop! end check_header(Http::NETWORK_HEADER) do |header| if header != settings.network - raise "Network name mismatch at #{request.url}, #{request.ip} is in '#{header}', \ -while #{settings.address} is in '#{settings.network}'" + error(400, "Network name mismatch at #{request.url}, #{request.ip} is in '#{header}', \ +while #{settings.address} is in '#{settings.network}'") end end check_header(Http::PROTOCOL_HEADER) do |header| if header != settings.protocol.to_s - raise "Protocol mismatch, you are in '#{header}', we are in '#{settings.protocol}'" + error(400, "Protocol mismatch, you are in '#{header}', we are in '#{settings.protocol}'") end end check_header(Http::SCORE_HEADER) do |header| if settings.remotes.all.empty? settings.log.debug("#{request.url}: we are in standalone mode, won't update remotes") @@ -107,55 +109,61 @@ if settings.address == "#{s.host}:#{s.port}" && !settings.ignore_score_weakness error(400, 'Self-requests are prohibited') end require_relative '../commands/remote' cmd = Remote.new(remotes: settings.remotes, log: settings.log) - cmd.run(['remote', 'add', s.host, s.port.to_s, "--network=#{settings.network}"]) + begin + cmd.run(['remote', 'add', s.host, s.port.to_s, "--network=#{settings.network}"]) + rescue StandardError => e + error(400, e.message) + end end - @start = Time.now end # @todo #357:30min Test that the headers are being set correctly. # Currently there are no tests at all that would verify the headers. after do headers['Cache-Control'] = 'no-cache' headers['X-Zold-Version'] = settings.version headers[Http::PROTOCOL_HEADER] = settings.protocol.to_s headers['Access-Control-Allow-Origin'] = '*' headers[Http::SCORE_HEADER] = score.reduced(16).to_s - headers['X-Zold-Thread'] = Thread.current.name.to_s - headers['X-Zold-Milliseconds'] = ((Time.now - @start) * 1000).round.to_s + headers['X-Zold-Thread'] = Thread.current.object_id.to_s + unless @start.nil? + settings.log.info("Slow response to #{request.url} in #{Age.new(@start, limit: 1)}") if Time.now - @start > 1 + headers['X-Zold-Milliseconds'] = ((Time.now - @start) * 1000).round.to_s + end end get '/robots.txt' do - content_type 'text/plain' + content_type('text/plain') 'User-agent: *' end get '/version' do - content_type 'text/plain' + content_type('text/plain') settings.version end get '/pid' do - content_type 'text/plain' + content_type('text/plain') Process.pid.to_s end get '/score' do - content_type 'text/plain' + content_type('text/plain') score.to_s end get '/trace' do - content_type 'text/plain' + content_type('text/plain') settings.trace.to_s end get '/nohup_log' do raise 'Run it with --nohup in order to see this log' if settings.nohup_log.nil? - raise "Log not found at #{settings.nohup_log}" unless File.exist?(settings.nohup_log) + error(400, "Log not found at #{settings.nohup_log}") unless File.exist?(settings.nohup_log) response.headers['Content-Type'] = 'text/plain' response.headers['Content-Disposition'] = "attachment; filename='#{File.basename(settings.nohup_log)}'" IO.read(settings.nohup_log) end @@ -168,11 +176,11 @@ redirect 'https://www.zold.io/images/logo-red.png' end end get '/' do - content_type 'application/json' + content_type('application/json') JSON.pretty_generate( version: settings.version, alias: settings.node_alias, network: settings.network, protocol: settings.protocol, @@ -193,22 +201,21 @@ home: 'https://www.zold.io' ) end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? - content_type 'application/json' + content_type('application/json') JSON.pretty_generate( version: settings.version, alias: settings.node_alias, protocol: settings.protocol, id: wallet.id.to_s, score: score.to_h, - wallets: settings.wallets.all.count, + wallets: Cachy.cache(:a_wallets, expires_in: 5 * 60) { settings.wallets.all.count }, mtime: wallet.mtime.utc.iso8601, size: File.size(wallet.path), digest: wallet.digest, copies: Copies.new(File.join(settings.copies, id)).all.count, balance: wallet.balance.to_i, @@ -216,15 +223,14 @@ ) end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16}).json} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? - content_type 'application/json' + content_type('application/json') JSON.pretty_generate( version: settings.version, alias: settings.node_alias, protocol: settings.protocol, id: wallet.id.to_s, @@ -238,54 +244,49 @@ ) end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/balance} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' wallet.balance.to_i.to_s end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/key} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' wallet.key.to_pub end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/mtime} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' wallet.mtime.utc.iso8601.to_s end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/digest} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' wallet.digest end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.txt} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' [ wallet.network, wallet.protocol, wallet.id.to_s, @@ -302,24 +303,22 @@ ].join("\n") end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})\.bin} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) copy_of(id) do |wallet| - error 404 unless wallet.exists? content_type 'text/plain' IO.read(wallet.path) end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/copies} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) - copy_of(id) do |wallet| - error 404 unless wallet.exists? + copy_of(id) do content_type 'text/plain' copies = Copies.new(File.join(settings.copies, id)) copies.load.map do |c| "#{c[:name]}: #{c[:host]}:#{c[:port]} #{c[:score]} #{c[:time].utc.iso8601}" end.join("\n") + @@ -331,28 +330,27 @@ end.join("\n") end end get %r{/wallet/(?<id>[A-Fa-f0-9]{16})/copy/(?<name>[0-9]+)} do - error 404 if settings.disable_fetch + error(404, 'FETCH is disabled with --disable-fetch') if settings.disable_fetch id = Id.new(params[:id]) name = params[:name] - copy_of(id) do |wallet| - error 404 unless wallet.exists? + copy_of(id) do copy = Copies.new(File.join(settings.copies, id)).all.find { |c| c[:name] == name } error 404 if copy.nil? content_type 'text/plain' IO.read(copy[:path]) end end put %r{/wallet/(?<id>[A-Fa-f0-9]{16})/?} do - error 404 if settings.disable_push + error(404, 'PUSH is disabled with --disable-push') if settings.disable_fetch request.body.rewind modified = settings.entrance.push(Id.new(params[:id]), request.body.read.to_s) if modified.empty? - status 304 + status(304) return end JSON.pretty_generate( version: settings.version, alias: settings.node_alias, @@ -360,32 +358,32 @@ wallets: settings.wallets.all.count ) end get '/remotes' do - content_type 'application/json' + content_type('application/json') JSON.pretty_generate( version: settings.version, alias: settings.node_alias, score: score.to_h, all: settings.remotes.all, mtime: settings.remotes.mtime.utc.iso8601 ) end get '/farm' do - content_type 'text/plain' + content_type('text/plain') settings.farm.to_text end get '/metronome' do - content_type 'text/plain' + content_type('text/plain') settings.metronome.to_text end get '/threads' do - content_type 'text/plain' + content_type('text/plain') [ "Total threads: #{Thread.list.count}", Thread.list.map do |t| [ "#{t.name}: status=#{t.status}; alive=#{t.alive?}", @@ -394,26 +392,28 @@ end ].flatten.join("\n\n") end not_found do - status 404 - content_type 'text/plain' + status(404) + content_type('text/plain') "Page not found: #{request.url}" end error 400 do - status 400 - content_type 'text/plain' + status(400) + content_type('text/plain') env['sinatra.error'] ? env['sinatra.error'].message : 'Invalid request' end error do status 503 e = env['sinatra.error'] content_type 'text/plain' headers['X-Zold-Error'] = e.message + headers['X-Zold-Path'] = request.url + settings.log.error(Backtrace.new(e).to_s) Backtrace.new(e).to_s end private @@ -431,14 +431,13 @@ end def copy_of(id) Tempfile.open([id.to_s, Wallet::EXT]) do |f| settings.wallets.find(id) do |wallet| - IO.write(f, IO.read(wallet.path)) if File.exist?(wallet.path) + error(404, "Wallet ##{id} doesn't exist on the node") unless wallet.exists? + IO.write(f, IO.read(wallet.path)) end - path = f.path - f.delete if File.size(f.path).zero? - yield Wallet.new(path) + yield Wallet.new(f.path) end end end end