From c2907fd3d2ad6c1c2854b74736b7ac9e04fa8e9c Mon Sep 17 00:00:00 2001 From: jon4hz Date: Sat, 13 Aug 2022 03:41:58 +0200 Subject: [PATCH] feat: option to disable the interactive console (#22) * feat: option to disable the interactive console * feat: print summary --- cmd/root.go | 19 ++++- internal/config/config.go | 9 ++- internal/dero-stratum-miner/console.go | 75 +----------------- internal/dero-stratum-miner/miner.go | 30 +++++--- internal/dero-stratum-miner/stats.go | 102 +++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 89 deletions(-) create mode 100644 internal/dero-stratum-miner/stats.go diff --git a/cmd/root.go b/cmd/root.go index 14c459e..54d39a5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,6 +3,7 @@ package cmd import ( "context" "fmt" + "io" "log" "os" "os/signal" @@ -11,6 +12,7 @@ import ( "syscall" "time" + "github.com/chzyer/readline" "github.com/deroproject/derohe/rpc" "github.com/go-logr/logr" "github.com/muesli/coral" @@ -42,6 +44,7 @@ func init() { rootCmd.Flags().BoolVarP(&cfg.Miner.Testnet, "testnet", "t", false, "use testnet") rootCmd.Flags().StringVarP(&cfg.Miner.PoolURL, "daemon-rpc-address", "r", "pool.whalesburg.com:4300", "stratum pool url") rootCmd.Flags().IntVarP(&cfg.Miner.Threads, "mining-threads", "m", runtime.GOMAXPROCS(0), "number of threads to use") + rootCmd.Flags().BoolVar(&cfg.Miner.NonInteractive, "non-interactive", false, "non-interactive mode") rootCmd.Flags().BoolVar(&cfg.Logger.Debug, "debug", false, "enable debug mode") rootCmd.Flags().Int8Var(&cfg.Logger.CLogLevel, "console-log-level", 0, "console log level") @@ -94,9 +97,17 @@ func rootHandler(cmd *coral.Command, args []string) error { done := make(chan os.Signal, 1) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - cli, err := console.New() - if err != nil { - log.Fatalln("failed to create console:", err) + var ( + cli *readline.Instance + out io.Writer = os.Stdout + ) + if !cfg.Miner.NonInteractive { + var err error + cli, err = console.New() + if err != nil { + log.Fatalln("failed to create console:", err) + } + out = cli.Stdout() } exename, err := os.Executable() @@ -107,7 +118,7 @@ func rootHandler(cmd *coral.Command, args []string) error { if err != nil { return fmt.Errorf("Error while opening log file err: %s filename %s", err, exename+".log") } - logger := logging.New(cli.Stdout(), f, cfg.Logger) + logger := logging.New(out, f, cfg.Logger) ctx, cancel := context.WithCancel(cmd.Context()) stc := newStratumClient(ctx, cfg.Miner.PoolURL, cfg.Miner.Wallet, logger) diff --git a/internal/config/config.go b/internal/config/config.go index b99cf73..1f819c5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,10 +7,11 @@ type Config struct { } type Miner struct { - Wallet string - Testnet bool - PoolURL string - Threads int + Wallet string + Testnet bool + PoolURL string + Threads int + NonInteractive bool } type Logger struct { diff --git a/internal/dero-stratum-miner/console.go b/internal/dero-stratum-miner/console.go index 82d66a3..6376762 100644 --- a/internal/dero-stratum-miner/console.go +++ b/internal/dero-stratum-miner/console.go @@ -7,10 +7,8 @@ import ( "runtime" "strconv" "strings" - "time" "github.com/chzyer/readline" - "github.com/jon4hz/hashconv" "github.com/whalesburg/dero-stratum-miner/internal/version" ) @@ -75,77 +73,10 @@ func (c *Client) startConsole() { } } -func (c *Client) refreshConsole() { - lastCounter := uint64(0) - lastCounterTime := time.Now() - - var ( - lastUpdate = time.Now() - mining bool - - miningString string - heightString string - diffString string - ) - - for { - select { - case <-c.ctx.Done(): - return - default: - } - - // we assume that the miner stopped if the conolse wasn't updated within the last five seconds. - if time.Since(lastUpdate) > time.Second*5 { - if mining { - miningString = "\033[31mNot Mining" - testnetString := "" - if c.config.Testnet { - testnetString = "\033[31m Testnet" - } - c.setPrompt(heightString, diffString, miningString, testnetString) - mining = false - } - } else { - mining = true - } - - // only update prompt if needed - if lastCounter != c.counter { - if mining { - heightString = fmt.Sprintf("\033[33mHeight %.0f", c.job.Height) - - switch { - case c.job.Difficulty > 1000000000: - diffString = fmt.Sprintf("\033[32mDiff %.1fG", float32(c.job.Difficulty)/1000000000.0) - case c.job.Difficulty > 1000000: - diffString = fmt.Sprintf("\033[32mDiff %.1fM", float32(c.job.Difficulty)/1000000.0) - case c.job.Difficulty > 1000: - diffString = fmt.Sprintf("\033[32mDiff %.1fK", float32(c.job.Difficulty)/1000.0) - case c.job.Difficulty > 0: - diffString = fmt.Sprintf("\033[32mDiff %d", c.job.Difficulty) - } - - miningSpeed := float64(c.counter-lastCounter) / (float64(uint64(time.Since(lastCounterTime))) / 1000000000.0) - c.hashrate = uint64(miningSpeed) - lastCounter = c.counter - lastCounterTime = time.Now() - miningString = fmt.Sprintf("Mining @ %s/s", hashconv.Format(int64(miningSpeed))) - } - - testnetString := "" - if c.config.Testnet { - testnetString = "\033[31m Testnet" - } - - c.setPrompt(heightString, diffString, miningString, testnetString) - lastUpdate = time.Now() - } - time.Sleep(1 * time.Second) - } -} - func (c *Client) setPrompt(heightString, diffString, miningString, testnetString string) { + if c.console == nil { + return + } c.console.SetPrompt(fmt.Sprintf("\033[1m\033[32mDero-Stratum-Miner: \033[0m%s %s \033[33mShares %d Rejected %d \033[32m%s>%s>>\033[0m ", heightString, diffString, c.GetTotalShares(), c.GetRejectedShares(), miningString, testnetString)) c.console.Refresh() } diff --git a/internal/dero-stratum-miner/miner.go b/internal/dero-stratum-miner/miner.go index c283b20..3f9684f 100644 --- a/internal/dero-stratum-miner/miner.go +++ b/internal/dero-stratum-miner/miner.go @@ -35,11 +35,15 @@ type Client struct { console *readline.Instance logger logr.Logger - mu sync.RWMutex - job *stratum.Job - jobCounter int64 - iterations int - hashrate uint64 + mu sync.RWMutex + job *stratum.Job + jobCounter int64 + iterations int + hashrate uint64 + mining bool + miningString string + diffString string + heightString string shareCounter uint64 rejectedCounter uint64 @@ -59,7 +63,10 @@ func New(ctx context.Context, cancel context.CancelFunc, config *config.Miner, s } func (c *Client) Close() error { - return c.console.Close() + if c.console != nil { + return c.console.Close() + } + return nil } func (c *Client) Start() error { @@ -71,7 +78,11 @@ func (c *Client) Start() error { c.config.Threads = 255 } - go c.refreshConsole() + go c.gatherStats() + if c.config.NonInteractive { + go c.noniSummary() + } + go c.getwork() for i := 0; i < c.config.Threads; i++ { @@ -80,8 +91,9 @@ func (c *Client) Start() error { go c.reportHashrate() - // this method will block until the context is canceled - c.startConsole() + if !c.config.NonInteractive { + c.startConsole() + } return nil } diff --git a/internal/dero-stratum-miner/stats.go b/internal/dero-stratum-miner/stats.go new file mode 100644 index 0000000..96e4a8f --- /dev/null +++ b/internal/dero-stratum-miner/stats.go @@ -0,0 +1,102 @@ +package miner + +import ( + "fmt" + "time" + + "github.com/jon4hz/hashconv" +) + +func (c *Client) gatherStats() { + var ( + lastCounter = uint64(0) + lastCounterTime = time.Now() + lastUpdate = time.Now() + miningString string + diffString string + heightString string + ) + + for { + select { + case <-c.ctx.Done(): + return + default: + } + + // we assume that the miner stopped if the conolse wasn't updated within the last five seconds. + if time.Since(lastUpdate) > time.Second*5 { + if c.mining { + miningString = "\033[31mNot Mining" + testnetString := "" + if c.config.Testnet { + testnetString = "\033[31m Testnet" + } + c.setPrompt(heightString, diffString, miningString, testnetString) + c.mining = false + } + } else { + c.mining = true + } + + // only update prompt if needed + if lastCounter != c.counter { + if c.mining { + c.heightString = fmt.Sprintf("%.0f", c.job.Height) + heightString = fmt.Sprintf("\033[33mHeight %s", c.heightString) + + switch { + case c.job.Difficulty > 1_000_000_000: + c.diffString = fmt.Sprintf("%.1fG", float32(c.job.Difficulty)/1_000_000_000.0) + diffString = fmt.Sprintf("\033[32mDiff %s", c.diffString) + case c.job.Difficulty > 1_000_000: + c.diffString = fmt.Sprintf("%.1fM", float32(c.job.Difficulty)/1_000_000.0) + diffString = fmt.Sprintf("\033[32mDiff %s", c.diffString) + case c.job.Difficulty > 1000: + c.diffString = fmt.Sprintf("%.1fK", float32(c.job.Difficulty)/1000.0) + diffString = fmt.Sprintf("\033[32mDiff %s", c.diffString) + case c.job.Difficulty > 0: + c.diffString = fmt.Sprintf("%d", c.job.Difficulty) + diffString = fmt.Sprintf("\033[32mDiff %s", c.diffString) + } + + miningSpeed := float64(c.counter-lastCounter) / (float64(uint64(time.Since(lastCounterTime))) / 1_000_000_000.0) + c.hashrate = uint64(miningSpeed) + lastCounter = c.counter + lastCounterTime = time.Now() + c.miningString = fmt.Sprintf("%s/s", hashconv.Format(int64(miningSpeed))) + miningString = fmt.Sprintf("Mining @ %s", c.miningString) + } + + testnetString := "" + if c.config.Testnet { + testnetString = "\033[31m Testnet" + } + + c.setPrompt(heightString, diffString, miningString, testnetString) + lastUpdate = time.Now() + } + time.Sleep(1 * time.Second) + } +} +func (c *Client) noniSummary() { + ticker := time.NewTicker(time.Second * 30) + for { + select { + case <-ticker.C: + c.printSummary() + case <-c.ctx.Done(): + return + } + } +} + +func (c *Client) printSummary() { + c.logger.Info("Summary", + "height", c.heightString, + "diff", c.diffString, + "accepted", c.GetAcceptedShares(), + "rejected", c.GetRejectedShares(), + "hashrate", c.miningString, + ) +}