github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/cmd/spc/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  
    10  	"github.com/spf13/cobra"
    11  
    12  	"SiaPrime/build"
    13  	"SiaPrime/node/api/client"
    14  )
    15  
    16  var (
    17  	// Flags.
    18  	hostContractOutputType string // output type for host contracts
    19  	hostVerbose            bool   // display additional host info
    20  	initForce              bool   // destroy and re-encrypt the wallet on init if it already exists
    21  	initPassword           bool   // supply a custom password when creating a wallet
    22  	renterAllContracts     bool   // Show all active and expired contracts
    23  	renterDownloadAsync    bool   // Downloads files asynchronously
    24  	renterListVerbose      bool   // Show additional info about uploaded files.
    25  	renterShowHistory      bool   // Show download history in addition to download queue.
    26  	siaDir                 string // Path to sia data dir
    27  	walletRawTxn           bool   // Encode/decode transactions in base64-encoded binary.
    28  )
    29  
    30  var (
    31  	// Globals.
    32  	rootCmd    *cobra.Command // Root command cobra object, used by bash completion cmd.
    33  	httpClient client.Client
    34  )
    35  
    36  // Exit codes.
    37  // inspired by sysexits.h
    38  const (
    39  	exitCodeGeneral = 1  // Not in sysexits.h, but is standard practice.
    40  	exitCodeUsage   = 64 // EX_USAGE in sysexits.h
    41  )
    42  
    43  // post makes an API call and discards the response. An error is returned if
    44  // the response status is not 2xx.
    45  // wrap wraps a generic command with a check that the command has been
    46  // passed the correct number of arguments. The command must take only strings
    47  // as arguments.
    48  func wrap(fn interface{}) func(*cobra.Command, []string) {
    49  	fnVal, fnType := reflect.ValueOf(fn), reflect.TypeOf(fn)
    50  	if fnType.Kind() != reflect.Func {
    51  		panic("wrapped function has wrong type signature")
    52  	}
    53  	for i := 0; i < fnType.NumIn(); i++ {
    54  		if fnType.In(i).Kind() != reflect.String {
    55  			panic("wrapped function has wrong type signature")
    56  		}
    57  	}
    58  
    59  	return func(cmd *cobra.Command, args []string) {
    60  		if len(args) != fnType.NumIn() {
    61  			cmd.UsageFunc()(cmd)
    62  			os.Exit(exitCodeUsage)
    63  		}
    64  		argVals := make([]reflect.Value, fnType.NumIn())
    65  		for i := range args {
    66  			argVals[i] = reflect.ValueOf(args[i])
    67  		}
    68  		fnVal.Call(argVals)
    69  	}
    70  }
    71  
    72  // die prints its arguments to stderr, then exits the program with the default
    73  // error code.
    74  func die(args ...interface{}) {
    75  	fmt.Fprintln(os.Stderr, args...)
    76  	os.Exit(exitCodeGeneral)
    77  }
    78  
    79  func main() {
    80  	root := &cobra.Command{
    81  		Use:   os.Args[0],
    82  		Short: "Sia Client v" + build.Version,
    83  		Long:  "Sia Client v" + build.Version,
    84  		Run:   wrap(consensuscmd),
    85  	}
    86  
    87  	rootCmd = root
    88  
    89  	// create command tree
    90  	root.AddCommand(versionCmd)
    91  	root.AddCommand(stopCmd)
    92  
    93  	root.AddCommand(updateCmd)
    94  	updateCmd.AddCommand(updateCheckCmd)
    95  
    96  	root.AddCommand(hostCmd)
    97  	hostCmd.AddCommand(hostConfigCmd, hostAnnounceCmd, hostFolderCmd, hostContractCmd, hostSectorCmd)
    98  	hostFolderCmd.AddCommand(hostFolderAddCmd, hostFolderRemoveCmd, hostFolderResizeCmd)
    99  	hostSectorCmd.AddCommand(hostSectorDeleteCmd)
   100  	hostCmd.Flags().BoolVarP(&hostVerbose, "verbose", "v", false, "Display detailed host info")
   101  	hostContractCmd.Flags().StringVarP(&hostContractOutputType, "type", "t", "value", "Select output type")
   102  
   103  	root.AddCommand(hostdbCmd)
   104  	hostdbCmd.AddCommand(hostdbViewCmd)
   105  	hostdbCmd.Flags().IntVarP(&hostdbNumHosts, "numhosts", "n", 0, "Number of hosts to display from the hostdb")
   106  	hostdbCmd.Flags().BoolVarP(&hostdbVerbose, "verbose", "v", false, "Display full hostdb information")
   107  
   108  	root.AddCommand(minerCmd)
   109  	minerCmd.AddCommand(minerStartCmd, minerStopCmd)
   110  
   111  	root.AddCommand(poolCmd)
   112  	poolCmd.AddCommand(poolConfigCmd, poolClientsCmd)
   113  
   114  	root.AddCommand(stratumminerCmd)
   115  	stratumminerCmd.AddCommand(stratumminerStartCmd, stratumminerStopCmd)
   116  
   117  	root.AddCommand(walletCmd)
   118  	walletCmd.AddCommand(walletAddressCmd, walletAddressesCmd, walletChangepasswordCmd, walletInitCmd, walletInitSeedCmd,
   119  		walletLoadCmd, walletLockCmd, walletSeedsCmd, walletSendCmd, walletSweepCmd, walletSignCmd,
   120  		walletBalanceCmd, walletBroadcastCmd, walletTransactionsCmd, walletUnlockCmd)
   121  	walletInitCmd.Flags().BoolVarP(&initPassword, "password", "p", false, "Prompt for a custom password")
   122  	walletInitCmd.Flags().BoolVarP(&initForce, "force", "", false, "destroy the existing wallet and re-encrypt")
   123  	walletInitSeedCmd.Flags().BoolVarP(&initForce, "force", "", false, "destroy the existing wallet")
   124  	walletSendCmd.AddCommand(walletSendSiacoinsCmd, walletSendSiafundsCmd)
   125  	walletUnlockCmd.Flags().BoolVarP(&initPassword, "password", "p", false, "Display interactive password prompt even if SIAPRIME_WALLET_PASSWORD is set")
   126  	walletBroadcastCmd.Flags().BoolVarP(&walletRawTxn, "raw", "", false, "Decode transaction as base64 instead of JSON")
   127  	walletSignCmd.Flags().BoolVarP(&walletRawTxn, "raw", "", false, "Encode signed transaction as base64 instead of JSON")
   128  
   129  	root.AddCommand(renterCmd)
   130  	renterCmd.AddCommand(renterFilesDeleteCmd, renterFilesDownloadCmd,
   131  		renterDownloadsCmd, renterAllowanceCmd, renterSetAllowanceCmd,
   132  		renterContractsCmd, renterFilesListCmd, renterFilesRenameCmd,
   133  		renterFilesUploadCmd, renterUploadsCmd, renterExportCmd,
   134  		renterPricesCmd)
   135  
   136  	renterContractsCmd.AddCommand(renterContractsViewCmd)
   137  	renterAllowanceCmd.AddCommand(renterAllowanceCancelCmd)
   138  
   139  	renterCmd.Flags().BoolVarP(&renterListVerbose, "verbose", "v", false, "Show additional file info such as redundancy")
   140  	renterContractsCmd.Flags().BoolVarP(&renterAllContracts, "all", "A", false, "Show all expired contracts in addition to active contracts")
   141  	renterDownloadsCmd.Flags().BoolVarP(&renterShowHistory, "history", "H", false, "Show download history in addition to the download queue")
   142  	renterFilesDownloadCmd.Flags().BoolVarP(&renterDownloadAsync, "async", "A", false, "Download file asynchronously")
   143  	renterFilesListCmd.Flags().BoolVarP(&renterListVerbose, "verbose", "v", false, "Show additional file info such as redundancy")
   144  	renterExportCmd.AddCommand(renterExportContractTxnsCmd)
   145  
   146  	root.AddCommand(gatewayCmd)
   147  	gatewayCmd.AddCommand(gatewayConnectCmd, gatewayDisconnectCmd, gatewayAddressCmd, gatewayListCmd)
   148  
   149  	root.AddCommand(consensusCmd)
   150  
   151  	utilsCmd.AddCommand(bashcomplCmd, mangenCmd, utilsHastingsCmd, utilsEncodeRawTxnCmd, utilsDecodeRawTxnCmd,
   152  		utilsSigHashCmd, utilsCheckSigCmd)
   153  	root.AddCommand(utilsCmd)
   154  
   155  	// initialize client
   156  	root.PersistentFlags().StringVarP(&httpClient.Address, "addr", "a", "localhost:4280", "which host/port to communicate with (i.e. the host/port spd is listening on)")
   157  	root.PersistentFlags().StringVarP(&httpClient.Password, "apipassword", "", "", "the password for the API's http authentication")
   158  	root.PersistentFlags().StringVarP(&siaDir, "siaprime-directory", "d", build.DefaultSiaDir(), "location of the sia directory")
   159  	root.PersistentFlags().StringVarP(&httpClient.UserAgent, "useragent", "", "SiaPrime-Agent", "the useragent used by spc to connect to the daemon's API")
   160  
   161  	// Check if the api password environment variable is set.
   162  	apiPassword := os.Getenv("SIAPRIME_API_PASSWORD")
   163  	if apiPassword != "" {
   164  		httpClient.Password = apiPassword
   165  		fmt.Println("Using SIAPRIME_API_PASSWORD environment variable")
   166  	}
   167  
   168  	// If the API password wasn't set we try to read it from the file. If
   169  	// reading fails, continue silently; but in the next release, this will
   170  	// be an error.
   171  	if httpClient.Password == "" {
   172  		pw, err := ioutil.ReadFile(build.APIPasswordFile(siaDir))
   173  		if err == nil {
   174  			httpClient.Password = strings.TrimSpace(string(pw))
   175  		}
   176  	}
   177  
   178  	// run
   179  	if err := root.Execute(); err != nil {
   180  		// Since no commands return errors (all commands set Command.Run instead of
   181  		// Command.RunE), Command.Execute() should only return an error on an
   182  		// invalid command or flag. Therefore Command.Usage() was called (assuming
   183  		// Command.SilenceUsage is false) and we should exit with exitCodeUsage.
   184  		os.Exit(exitCodeUsage)
   185  	}
   186  }