From f6afeee800eaae4cfe98ddadb72d8bf5156cc28b Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 26 Aug 2019 12:46:53 +1000 Subject: [PATCH] Minor improvements 1) gen_otp supports single use OTP secrets 2) improve database config check logic 3) reconnect websocket routine to engine (apart from the exchange pair syncer) 4) ImPrOvE CoNsIsTeNcY wItH LoG OuTpUt --- cmd/gen_otp/otp_gen.go | 47 +++++++++++++++++++++++++++++++++++------- config/config.go | 6 +++++- engine/database.go | 14 ++++++------- engine/engine.go | 5 +++++ engine/routines.go | 10 +++++++++ 5 files changed, 66 insertions(+), 16 deletions(-) diff --git a/cmd/gen_otp/otp_gen.go b/cmd/gen_otp/otp_gen.go index dbf9b438..f6b37348 100644 --- a/cmd/gen_otp/otp_gen.go +++ b/cmd/gen_otp/otp_gen.go @@ -2,13 +2,17 @@ package main import ( "flag" + "fmt" "log" "time" "github.com/pquerna/otp/totp" "github.com/thrasher-corp/gocryptotrader/config" + "github.com/thrasher-corp/gocryptotrader/core" ) +const defaultSleepTime = time.Second * 30 + func containsOTP(cfg *config.Config) bool { for x := range cfg.Exchanges { if cfg.Exchanges[x].API.Credentials.OTPSecret != "" { @@ -19,39 +23,66 @@ func containsOTP(cfg *config.Config) bool { } func main() { - var inFile string + var cfgFile, code string + var single bool + var err error + defaultCfg, err := config.GetFilePath("") if err != nil { log.Fatal(err) } - flag.StringVar(&inFile, "infile", defaultCfg, "The config input file to process.") + flag.StringVar(&cfgFile, "config", defaultCfg, "The config input file to process.") + flag.BoolVar(&single, "single", false, "prompt for single use OTP code gen") flag.Parse() log.Println("GoCryptoTrader: OTP code generator tool.") + log.Println(core.Copyright) + // Handle single use OTP code gen + if single { + var input string + for { + log.Println("Please enter in your OTP secret:") + fmt.Scanln(&input) + if input != "" { + break + } + } + + for { + code, err = totp.GenerateCode(input, time.Now()) + if err != nil { + log.Fatalf("Unable to generate OTP code. Err: %s", err) + } + log.Printf("OTP code: %s\n", code) + time.Sleep(defaultSleepTime) + } + } + + // Otherwise default to loading the config file and generating OTP codes from it var cfg config.Config - err = cfg.LoadConfig(inFile) + err = cfg.LoadConfig(cfgFile) if err != nil { log.Fatal(err) } log.Println("Loaded config file.") if !containsOTP(&cfg) { - log.Println("No exchanges with OTP code stored. Exiting.") + log.Fatal("No exchanges with OTP code stored. Exiting.") } for { for x := range cfg.Exchanges { if cfg.Exchanges[x].API.Credentials.OTPSecret != "" { - code, err := totp.GenerateCode(cfg.Exchanges[x].API.Credentials.OTPSecret, time.Now()) + code, err = totp.GenerateCode(cfg.Exchanges[x].API.Credentials.OTPSecret, time.Now()) if err != nil { - log.Printf("Exchange %s: Failed to generate OTP code. Err: %s", cfg.Exchanges[x].Name, err) + log.Printf("Exchange %s: Failed to generate OTP code. Err: %s\n", cfg.Exchanges[x].Name, err) continue } - log.Printf("%s: %s", cfg.Exchanges[x].Name, code) + log.Printf("%s: %s\n", cfg.Exchanges[x].Name, code) } - time.Sleep(time.Second) } + time.Sleep(defaultSleepTime) } } diff --git a/config/config.go b/config/config.go index 343ec58b..30db3fe7 100644 --- a/config/config.go +++ b/config/config.go @@ -1303,9 +1303,13 @@ func (c *Config) checkDatabaseConfig() error { m.Lock() defer m.Unlock() + if !c.Database.Enabled { + return nil + } + if !common.StringDataCompare(database.SupportedDrivers, c.Database.Driver) { c.Database.Enabled = false - return fmt.Errorf("unsupported database driver %v database disabled", c.Database.Driver) + return fmt.Errorf("unsupported database driver %v, database disabled", c.Database.Driver) } if c.Database.Driver == "sqlite" { diff --git a/engine/database.go b/engine/database.go index 696ef965..76644977 100644 --- a/engine/database.go +++ b/engine/database.go @@ -34,7 +34,7 @@ func (a *databaseManager) Start() (err error) { return errors.New("database manager already started") } - log.Debugln(log.DatabaseMgr, "database manager starting...") + log.Debugln(log.DatabaseMgr, "Database manager starting...") a.shutdown = make(chan struct{}) @@ -60,7 +60,7 @@ func (a *databaseManager) Start() (err error) { audit.Audit = auditSQLite.Audit() } dbConn.Connected = true - log.Debugf(log.DatabaseMgr, "connection established to %v using %v", dbConn.Config.Host, dbConn.Config.Driver) + log.Debugf(log.DatabaseMgr, "Database connection established to host: %v using %v driver\n", dbConn.Config.Host, dbConn.Config.Driver) mLogger := mg.MLogger{} migrations := mg.Migrator{ @@ -91,7 +91,7 @@ func (a *databaseManager) Stop() error { return errors.New("database manager already stopped") } - log.Debugln(log.DatabaseMgr, "database manager shutting down...") + log.Debugln(log.DatabaseMgr, "Database manager shutting down...") err := dbConn.SQL.Close() if err != nil { log.Errorf(log.DatabaseMgr, "Failed to close database: %v", err) @@ -101,7 +101,7 @@ func (a *databaseManager) Stop() error { } func (a *databaseManager) run() { - log.Debugln(log.DatabaseMgr, "database manager started.") + log.Debugln(log.DatabaseMgr, "Database manager started.") Bot.ServicesWG.Add(1) t := time.NewTicker(time.Second * 2) @@ -113,7 +113,7 @@ func (a *databaseManager) run() { Bot.ServicesWG.Done() - log.Debugln(log.DatabaseMgr, "database manager shutdown.") + log.Debugln(log.DatabaseMgr, "Database manager shutdown.") }() for { @@ -132,13 +132,13 @@ func (a *databaseManager) checkConnection() { err := dbConn.SQL.Ping() if err != nil { - log.Errorf(log.DatabaseMgr, "database connection error: %v", err) + log.Errorf(log.DatabaseMgr, "Database connection error: %v\n", err) dbConn.Connected = false return } if !dbConn.Connected { - log.Info(log.DatabaseMgr, "database connection reestablished") + log.Info(log.DatabaseMgr, "Database connection reestablished") dbConn.Connected = true } } diff --git a/engine/engine.go b/engine/engine.go index 33be5800..675a33fd 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -164,6 +164,7 @@ func ValidateSettings(b *Engine, s *Settings) { b.Settings.EnableExchangeHTTPDebugging = s.EnableExchangeHTTPDebugging b.Settings.DisableExchangeAutoPairUpdates = s.DisableExchangeAutoPairUpdates b.Settings.ExchangePurgeCredentials = s.ExchangePurgeCredentials + b.Settings.EnableWebsocketRoutine = s.EnableWebsocketRoutine if !b.Settings.EnableExchangeHTTPRateLimiter { request.DisableRateLimiter = true @@ -383,6 +384,10 @@ func (e *Engine) Start() { go EventManger() } + if e.Settings.EnableWebsocketRoutine { + go WebsocketRoutine() + } + <-e.Shutdown e.Stop() } diff --git a/engine/routines.go b/engine/routines.go index 8a82ad52..1c553f39 100644 --- a/engine/routines.go +++ b/engine/routines.go @@ -295,11 +295,21 @@ func WebsocketRoutine() { common.IsEnabled(Bot.Exchanges[i].IsWebsocketEnabled())) } + // TO-DO: expose IsConnected() and IsConnecting so this can be simplified if Bot.Exchanges[i].IsWebsocketEnabled() { ws, err := Bot.Exchanges[i].GetWebsocket() if err != nil { + log.Errorf(log.WebsocketMgr, "Exchange %s GetWebsocket error: %s\n", + Bot.Exchanges[i].GetName(), err) return } + + // Exchange sync manager might have already started ws + // service or is in the process of connecting, so check + if ws.IsConnected() || ws.IsConnecting() { + return + } + // Data handler routine go WebsocketDataHandler(ws)