From c2c70328585490917ec45d318ea25448bee394e8 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Fri, 19 Oct 2018 17:26:00 +1100 Subject: [PATCH] Add debug logger and default data directory support --- common/common.go | 31 ++++++++++++++++++ config/config.go | 82 ++++++++++++++++++++++++++++++++++-------------- helpers.go | 33 +++++++++++++++++++ main.go | 25 +++++++++++++-- 4 files changed, 145 insertions(+), 26 deletions(-) diff --git a/common/common.go b/common/common.go index 44a1c7c3..7b96d7f3 100644 --- a/common/common.go +++ b/common/common.go @@ -21,6 +21,7 @@ import ( "net/http" "net/url" "os" + "path" "path/filepath" "reflect" "regexp" @@ -607,3 +608,33 @@ func TimeFromUnixTimestampFloat(raw interface{}) (time.Time, error) { } return time.Unix(0, int64(ts)*int64(time.Millisecond)), nil } + +// GetDefaultDataDir returns the default data directory +// Windows - C:\Users\%USER%\AppData\Roaming\GoCryptoTrader +// Linux/Unix or OSX - $HOME/.gocryptotrader +func GetDefaultDataDir(env string) string { + if env == "windows" { + return os.Getenv("APPDATA") + GetOSPathSlash() + "GoCryptoTrader" + } + return path.Join(os.ExpandEnv("$HOME"), ".gocryptotrader") +} + +// CheckDir checks to see if a particular directory exists +// and attempts to create it if desired, if it doesn't exist +func CheckDir(dir string, create bool) error { + _, err := os.Stat(dir) + if !os.IsNotExist(err) { + return nil + } + + if !create { + return fmt.Errorf("directory %s does not exist. Err: %s", dir, err) + } + + log.Printf("Directory %s does not exist.. creating.", dir) + err = os.Mkdir(dir, 0777) + if err != nil { + return fmt.Errorf("failed to create dir. Err: %s", err) + } + return nil +} diff --git a/config/config.go b/config/config.go index 6ec4a155..4827b73f 100644 --- a/config/config.go +++ b/config/config.go @@ -7,6 +7,8 @@ import ( "fmt" "log" "os" + "path" + "runtime" "strconv" "sync" "time" @@ -942,39 +944,71 @@ func GetFilePath(file string) (string, error) { exePath, err := common.GetExecutablePath() if err != nil { - log.Fatalf("Unable to get executable path: %s", err) return "", err } - tempPath := exePath + common.GetOSPathSlash() - encPath := tempPath + EncryptedConfigFile - cfgPath := tempPath + ConfigFile + oldDir := exePath + common.GetOSPathSlash() + oldDirs := []string{oldDir + ConfigFile, oldDir + EncryptedConfigFile} - data, err := common.ReadFile(encPath) - if err == nil { - if ConfirmECS(data) { - return encPath, nil + newDir := common.GetDefaultDataDir(runtime.GOOS) + common.GetOSPathSlash() + err = common.CheckDir(newDir, true) + if err != nil { + return "", err + } + newDirs := []string{newDir + ConfigFile, newDir + EncryptedConfigFile} + + // First upgrade the old dir config file if it exists to the corresponding new one + for x := range oldDirs { + _, err := os.Stat(oldDirs[x]) + if os.IsNotExist(err) { + continue + } else { + if path.Ext(oldDirs[x]) == ".json" { + err = os.Rename(oldDirs[x], newDirs[0]) + if err != nil { + return "", err + } + log.Printf("Renamed old config file %s to %s", oldDirs[x], newDirs[0]) + } else { + err = os.Rename(oldDirs[x], newDirs[1]) + if err != nil { + return "", err + } + log.Printf("Renamed old config file %s to %s", oldDirs[x], newDirs[1]) + } } - err = os.Rename(encPath, cfgPath) + } + + // Secondly check to see if the new config file extension is correct or not + for x := range newDirs { + _, err := os.Stat(newDirs[x]) + if os.IsNotExist(err) { + continue + } + + data, err := common.ReadFile(newDirs[x]) + if ConfirmECS(data) { + if path.Ext(newDirs[x]) == ".dat" { + return newDirs[x], nil + } + err = os.Rename(newDirs[x], newDirs[1]) + if err != nil { + return "", err + } + return newDirs[1], nil + } + + if path.Ext(newDirs[x]) == ".json" { + return newDirs[x], nil + } + err = os.Rename(newDirs[x], newDirs[0]) if err != nil { - log.Fatalf("Unable to rename config file: %s", err) return "", err } - log.Printf("Renaming non-encrypted config file from %s to %s", - encPath, cfgPath) - return cfgPath, nil + return newDirs[0], nil } - if !ConfirmECS(data) { - return cfgPath, nil - } - err = os.Rename(cfgPath, encPath) - if err != nil { - log.Fatalf("Unable to rename config file: %s", err) - return "", err - } - log.Printf("Renamed encrypted config file from %s to %s", cfgPath, - encPath) - return encPath, nil + + return "", errors.New("config default file path error") } // ReadConfig verifies and checks for encryption and verifies the unencrypted diff --git a/helpers.go b/helpers.go index a35f3b5e..d577396d 100644 --- a/helpers.go +++ b/helpers.go @@ -3,8 +3,11 @@ package main import ( "errors" "fmt" + "io" "log" + "os" + "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/currency/pair" "github.com/thrasher-/gocryptotrader/currency/translation" @@ -15,6 +18,36 @@ import ( "github.com/thrasher-/gocryptotrader/portfolio" ) +const ( + logFile = "debug.log" +) + +var ( + logFileHandle *os.File +) + +// InitLogFile initialises the log file +func InitLogFile(lFile string) error { + if logFileHandle != nil { + return nil + } + + var err error + logFileHandle, err = os.OpenFile(lFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return err + } + + wrt := io.MultiWriter(os.Stdout, logFileHandle) + log.SetOutput(wrt) + return nil +} + +// GetLogFile returns the debug.log file +func GetLogFile(dir string) string { + return dir + common.GetOSPathSlash() + logFile +} + // GetAllAvailablePairs returns a list of all available pairs on either enabled // or disabled exchanges func GetAllAvailablePairs(enabledExchangesOnly bool) []pair.CurrencyPair { diff --git a/main.go b/main.go index 2f394912..545462c3 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,8 @@ type Bot struct { shutdown chan bool dryRun bool configFile string + dataDir string + logFile string } const banner = ` @@ -54,6 +56,7 @@ func main() { //Handle flags flag.StringVar(&bot.configFile, "config", defaultPath, "config file to load") + flag.StringVar(&bot.dataDir, "datadir", common.GetDefaultDataDir(runtime.GOOS), "default data directory for GoCryptoTrader files") dryrun := flag.Bool("dryrun", false, "dry runs bot, doesn't save config file") version := flag.Bool("version", false, "retrieves current GoCryptoTrader version") flag.Parse() @@ -67,16 +70,30 @@ func main() { bot.dryRun = true } - bot.config = &config.Cfg fmt.Println(banner) fmt.Println(BuildVersion(false)) - log.Printf("Loading config file %s..\n", bot.configFile) + bot.config = &config.Cfg + log.Printf("Loading config file %s..\n", bot.configFile) err = bot.config.LoadConfig(bot.configFile) if err != nil { log.Fatalf("Failed to load config. Err: %s", err) } + err = common.CheckDir(bot.dataDir, true) + if err != nil { + log.Fatalf("Failed to open/create data directory: %s. Err: %s", bot.dataDir, err) + } + log.Printf("Using data directory: %s.\n", bot.dataDir) + + bot.logFile = GetLogFile(bot.dataDir) + err = InitLogFile(bot.logFile) + if err != nil { + log.Printf("Failed to create log file writer. Err: %s", err) + } else { + log.Printf("Using log file: %s.\n", bot.logFile) + } + AdjustGoMaxProcs() log.Printf("Bot '%s' started.\n", bot.config.Name) log.Printf("Bot dry run mode: %v.\n", common.IsEnabled(bot.dryRun)) @@ -199,5 +216,9 @@ func Shutdown() { } log.Println("Exiting.") + + if logFileHandle != nil { + logFileHandle.Close() + } os.Exit(0) }