decred.org/dcrdex@v1.0.5/client/cmd/bwctl/config.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package main 5 6 import ( 7 "errors" 8 "fmt" 9 "path/filepath" 10 "runtime" 11 12 flags "github.com/jessevdk/go-flags" 13 14 "decred.org/dcrdex/client/rpcserver" 15 "decred.org/dcrdex/dex" 16 "github.com/decred/dcrd/dcrutil/v4" 17 ) 18 19 const ( 20 defaultRPCPort = "5757" 21 defaultMainnetHost = "127.0.0.1" 22 defaultTestnetHost = "127.0.0.2" 23 defaultSimnetHost = "127.0.0.3" 24 defaultConfigFilename = "dexcctl.conf" 25 defaultRPCCertFile = "rpc.cert" 26 ) 27 28 var ( 29 appDir = dcrutil.AppDataDir("dexcctl", false) 30 bisonwAppDir = dcrutil.AppDataDir("dexc", false) 31 defaultConfigPath = filepath.Join(appDir, defaultConfigFilename) 32 ) 33 34 // config defines the configuration options for bwctl. 35 type config struct { 36 ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` 37 ListCommands bool `short:"l" long:"listcommands" description:"List all of the supported commands and exit"` 38 Config string `short:"C" long:"config" description:"Path to configuration file"` 39 RPCUser string `short:"u" long:"rpcuser" description:"RPC username"` 40 RPCPass string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password"` 41 RPCAddr string `short:"a" long:"rpcaddr" description:"RPC server to connect to"` 42 RPCCert string `short:"c" long:"rpccert" description:"RPC server certificate chain for validation"` 43 PrintJSON bool `short:"j" long:"json" description:"Print json messages sent and received"` 44 Proxy string `long:"proxy" description:"Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)"` 45 ProxyUser string `long:"proxyuser" description:"Username for proxy server"` 46 ProxyPass string `long:"proxypass" default-mask:"-" description:"Password for proxy server"` 47 PasswordArgs []string `short:"p" long:"passarg" description:"Password arguments to bypass stdin prompts."` 48 Testnet bool `long:"testnet" description:"use testnet"` 49 Simnet bool `long:"simnet" description:"use simnet"` 50 } 51 52 // configure parses command line options and a config file if present. Returns 53 // an instantiated *config, leftover command line arguments, and a bool that 54 // is true if there is nothing further to do (i.e. version was printed and we 55 // can exit), or a parsing error, in that order. 56 func configure() (*config, []string, bool, error) { 57 stop := true 58 cfg := &config{ 59 Config: defaultConfigPath, 60 } 61 preParser := flags.NewParser(cfg, flags.HelpFlag|flags.PassDoubleDash|flags.PassAfterNonOption) 62 _, err := preParser.Parse() 63 if err != nil { 64 var flagErr *flags.Error 65 if errors.As(err, &flagErr) && flagErr.Type == flags.ErrHelp { 66 // This line is printed below the help message. 67 fmt.Printf("%v\nThe special parameter `-` indicates that a parameter should be read from the\nnext unread line from standard input.\n", err) 68 return nil, nil, stop, nil 69 } 70 return nil, nil, false, err 71 } 72 73 // Show the version and exit if the version flag was specified. 74 if cfg.ShowVersion { 75 fmt.Printf("%s version %s (Go version %s %s/%s)\n", appName, 76 Version, runtime.Version(), runtime.GOOS, runtime.GOARCH) 77 fmt.Printf("%s required RPC server version: %s\n", appName, requiredRPCServerVersion.String()) 78 return nil, nil, stop, nil 79 } 80 81 // Show the available commands and exit if the associated flag was 82 // specified. 83 if cfg.ListCommands { 84 fmt.Println(rpcserver.ListCommands(false)) 85 return nil, nil, stop, nil 86 } 87 88 parser := flags.NewParser(cfg, flags.Default|flags.PassAfterNonOption) 89 90 if dex.FileExists(cfg.Config) { 91 // Load additional config from file. 92 err = flags.NewIniParser(parser).ParseFile(cfg.Config) 93 if err != nil { 94 return nil, nil, false, err 95 } 96 } 97 98 // Parse command line options again to ensure they take precedence. 99 remainingArgs, err := parser.Parse() 100 if err != nil { 101 return nil, nil, false, err 102 } 103 104 if cfg.RPCCert == "" { 105 // Check in ~/.dexcctl first. 106 cfg.RPCCert = dex.CleanAndExpandPath(filepath.Join(appDir, defaultRPCCertFile)) 107 if !dex.FileExists(cfg.RPCCert) { // Then in ~/.dexc 108 cfg.RPCCert = dex.CleanAndExpandPath(filepath.Join(bisonwAppDir, defaultRPCCertFile)) 109 } 110 } else { 111 // Handle environment variable and tilde expansion in the given path. 112 cfg.RPCCert = dex.CleanAndExpandPath(cfg.RPCCert) 113 } 114 115 if cfg.Simnet && cfg.Testnet { 116 return nil, nil, false, fmt.Errorf("simnet and testnet cannot both be specified") 117 } 118 119 if cfg.RPCAddr == "" { 120 var rpcHost string 121 switch { 122 case cfg.Testnet: 123 rpcHost = defaultTestnetHost 124 case cfg.Simnet: 125 rpcHost = defaultSimnetHost 126 default: 127 rpcHost = defaultMainnetHost 128 } 129 cfg.RPCAddr = rpcHost + ":" + defaultRPCPort 130 } 131 132 return cfg, remainingArgs, false, nil 133 }