#!/usr/bin/env ruby # encoding: utf-8 # # Copyright (c) 2018 Yegor Bugayenko # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the 'Software'), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. STDOUT.sync = true require 'slop' require 'rainbow' require_relative '../lib/zold' require_relative '../lib/zold/version' require_relative '../lib/zold/wallet' require_relative '../lib/zold/wallets' require_relative '../lib/zold/log' require_relative '../lib/zold/key' require_relative '../lib/zold/amount' require_relative '../lib/zold/copies' require_relative '../lib/zold/remotes' Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 log = Zold::Log.new args = [] config = File.expand_path('~/.zold') if File.exist?(config) body = File.read(config) extra = body.split(/[\r\n]+/).map(&:strip) args += extra log.debug("Found #{body.split(/\n/).length} lines in #{config}") else log.debug("Default config file #{config} not found") end args += ARGV begin opts = Slop.parse(args, strict: false, suppress_errors: true) do |o| o.banner = "Usage: zold [options] command [arguments] Available commands: #{Rainbow('remote').green} Manage remote nodes #{Rainbow('create').green} Creates a new wallet with a random ID #{Rainbow('fetch').green} [ID...] Fetch wallet copies from remote nodes #{Rainbow('clean').green} [ID...] Remove expired local copies #{Rainbow('merge').green} [ID...] Merge remote copies with the HEAD #{Rainbow('propagate').green} [ID...] Propagate transactions to receiving wallets #{Rainbow('pull').green} [ID...] Fetch and then merge #{Rainbow('show').green} [ID...] Show all available information about the wallet #{Rainbow('pay').green} from to amount details Pay ZOLD from one wallet to another #{Rainbow('invoice').green} ID Generate invoice unique ID for a payment #{Rainbow('status').green} Show status of local copies #{Rainbow('push').green} [ID...] Push all/some local wallets or the ones required #{Rainbow('node').green} port Run node at the given TCP port #{Rainbow('score').green} host port strength Generate score for the given host and port Available options:" o.string '-d', '--dir', 'The directory where wallets are stored (default: .)', default: Dir.pwd o.string '--private-key', 'The location of RSA private key (default: ~/.ssh/id_rsa)', default: '~/.ssh/id_rsa' o.string '--public-key', 'The location of RSA public key (default: ~/.ssh/id_rsa.pub)', default: '~/.ssh/id_rsa.pub' o.bool '-h', '--help', 'Show these instructions' o.bool '--trace', 'Show full stack trace in case of a problem' o.on '--no-colors', 'Disable colors in the ouput' do Rainbow.enabled = false end o.on '--verbose', 'Enable extra logging information' do log = Zold::Log::Verbose.new end o.on '-v', '--version', 'Show current version' do log.info(Zold::VERSION) exit end end raise 'Try --help' if opts.arguments.empty? && !opts.help? if opts.help? && opts.arguments.empty? log.info(opts.to_s) exit end command = opts.arguments[0] args = args[(args.index(command) + 1)..-1] wallets = Zold::Wallets.new(opts['dir']) remotes = Zold::Remotes.new(File.join(opts['dir'], '.zoldata/remotes')) copies = File.join(opts['dir'], '.zoldata/copies') case command when 'node' require_relative '../lib/zold/commands/node' Zold::Node.new(log: log).run(args) when 'create' require_relative '../lib/zold/commands/create' Zold::Create.new( wallets: wallets, pubkey: Zold::Key.new(file: opts['public-key']), log: log ).run(args) when 'remote' require_relative '../lib/zold/commands/remote' Zold::Remote.new(remotes: remotes, log: log).run(args) when 'invoice' require_relative '../lib/zold/commands/invoice' Zold::Invoice.new(wallets: wallets, log: log).run(args) when 'pay' require_relative '../lib/zold/commands/pay' Zold::Pay.new( wallets: wallets, pvtkey: Zold::Key.new(file: opts['private-key']), log: log ).run(args) when 'show' require_relative '../lib/zold/commands/show' Zold::Show.new(wallets: wallets, log: log).run(args) when 'fetch' require_relative '../lib/zold/commands/fetch' Zold::Fetch.new(remotes: remotes, copies: copies, log: log).run(args) when 'clean' require_relative '../lib/zold/commands/clean' Zold::Clean.new(copies: copies, log: log).run(args) when 'diff' require_relative '../lib/zold/commands/diff' Zold::Diff.new(wallets: wallets, copies: copies, log: log).run(args) when 'merge' require_relative '../lib/zold/commands/merge' Zold::Merge.new(wallets: wallets, copies: copies, log: log).run(args) when 'propagate' require_relative '../lib/zold/commands/propagate' Zold::Propagate.new(wallets: wallets, log: log).run(args) when 'pull' require_relative '../lib/zold/commands/fetch' Zold::Fetch.new(remotes: remotes, copies: copies, log: log).run(args) require_relative '../lib/zold/commands/merge' Zold::Merge.new(wallets: wallets, copies: copies, log: log).run(args) when 'push' require_relative '../lib/zold/commands/push' Zold::Push.new(wallets: wallets, remotes: remotes, log: log).run(args) when 'score' require_relative '../lib/zold/score' if args.length != 3 raise 'Exactly three args required: host, port, strength' end host = args[0] raise "Invalid host name: #{host}" unless host =~ /[a-z0-9\.-]+/ port = args[1].to_i raise "Invalid TCP port: #{port}" if port <= 0 || port > 65535 strength = args[2].to_i raise "Invalid strength: #{strength}" if strength <= 0 || strength > 8 score = Zold::Score.new( Time.now, host, port, strength: strength ) loop do log.info(score.to_s) score = score.next end else raise "Command '#{command}' is not supported" end rescue StandardError => ex log.error("#{ex.message} (#{ex.class.name})") puts ex.backtrace if opts['trace'] exit -1 end