OSDN Git Service

5c412f867fa80d660bfa2324547811227bfe1c44
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / cmd / btcctl / btcctl.go
1 package main
2
3 import (
4         "bufio"
5         "bytes"
6         "encoding/json"
7         "fmt"
8         "io"
9         "os"
10         "path/filepath"
11         "strings"
12
13         "github.com/btcsuite/btcd/btcjson"
14 )
15
16 const (
17         showHelpMessage = "Specify -h to show available options"
18         listCmdMessage  = "Specify -l to list available commands"
19 )
20
21 // commandUsage display the usage for a specific command.
22 func commandUsage(method string) {
23         usage, err := btcjson.MethodUsageText(method)
24         if err != nil {
25                 // This should never happen since the method was already checked
26                 // before calling this function, but be safe.
27                 fmt.Fprintln(os.Stderr, "Failed to obtain command usage:", err)
28                 return
29         }
30
31         fmt.Fprintln(os.Stderr, "Usage:")
32         fmt.Fprintf(os.Stderr, "  %s\n", usage)
33 }
34
35 // usage displays the general usage when the help flag is not displayed and
36 // and an invalid command was specified.  The commandUsage function is used
37 // instead when a valid command was specified.
38 func usage(errorMessage string) {
39         appName := filepath.Base(os.Args[0])
40         appName = strings.TrimSuffix(appName, filepath.Ext(appName))
41         fmt.Fprintln(os.Stderr, errorMessage)
42         fmt.Fprintln(os.Stderr, "Usage:")
43         fmt.Fprintf(os.Stderr, "  %s [OPTIONS] <command> <args...>\n\n",
44                 appName)
45         fmt.Fprintln(os.Stderr, showHelpMessage)
46         fmt.Fprintln(os.Stderr, listCmdMessage)
47 }
48
49 func main() {
50         cfg, args, err := loadConfig()
51         if err != nil {
52                 os.Exit(1)
53         }
54         if len(args) < 1 {
55                 usage("No command specified")
56                 os.Exit(1)
57         }
58
59         // Ensure the specified method identifies a valid registered command and
60         // is one of the usable types.
61         method := args[0]
62         usageFlags, err := btcjson.MethodUsageFlags(method)
63         if err != nil {
64                 fmt.Fprintf(os.Stderr, "Unrecognized command '%s'\n", method)
65                 fmt.Fprintln(os.Stderr, listCmdMessage)
66                 os.Exit(1)
67         }
68         if usageFlags&unusableFlags != 0 {
69                 fmt.Fprintf(os.Stderr, "The '%s' command can only be used via "+
70                         "websockets\n", method)
71                 fmt.Fprintln(os.Stderr, listCmdMessage)
72                 os.Exit(1)
73         }
74
75         // Convert remaining command line args to a slice of interface values
76         // to be passed along as parameters to new command creation function.
77         //
78         // Since some commands, such as submitblock, can involve data which is
79         // too large for the Operating System to allow as a normal command line
80         // parameter, support using '-' as an argument to allow the argument
81         // to be read from a stdin pipe.
82         bio := bufio.NewReader(os.Stdin)
83         params := make([]interface{}, 0, len(args[1:]))
84         for _, arg := range args[1:] {
85                 if arg == "-" {
86                         param, err := bio.ReadString('\n')
87                         if err != nil && err != io.EOF {
88                                 fmt.Fprintf(os.Stderr, "Failed to read data "+
89                                         "from stdin: %v\n", err)
90                                 os.Exit(1)
91                         }
92                         if err == io.EOF && len(param) == 0 {
93                                 fmt.Fprintln(os.Stderr, "Not enough lines "+
94                                         "provided on stdin")
95                                 os.Exit(1)
96                         }
97                         param = strings.TrimRight(param, "\r\n")
98                         params = append(params, param)
99                         continue
100                 }
101
102                 params = append(params, arg)
103         }
104
105         // Attempt to create the appropriate command using the arguments
106         // provided by the user.
107         cmd, err := btcjson.NewCmd(method, params...)
108         if err != nil {
109                 // Show the error along with its error code when it's a
110                 // btcjson.Error as it reallistcally will always be since the
111                 // NewCmd function is only supposed to return errors of that
112                 // type.
113                 if jerr, ok := err.(btcjson.Error); ok {
114                         fmt.Fprintf(os.Stderr, "%s command: %v (code: %s)\n",
115                                 method, err, jerr.ErrorCode)
116                         commandUsage(method)
117                         os.Exit(1)
118                 }
119
120                 // The error is not a btcjson.Error and this really should not
121                 // happen.  Nevertheless, fallback to just showing the error
122                 // if it should happen due to a bug in the package.
123                 fmt.Fprintf(os.Stderr, "%s command: %v\n", method, err)
124                 commandUsage(method)
125                 os.Exit(1)
126         }
127
128         // Marshal the command into a JSON-RPC byte slice in preparation for
129         // sending it to the RPC server.
130         marshalledJSON, err := btcjson.MarshalCmd(1, cmd)
131         if err != nil {
132                 fmt.Fprintln(os.Stderr, err)
133                 os.Exit(1)
134         }
135
136         // Send the JSON-RPC request to the server using the user-specified
137         // connection configuration.
138         result, err := sendPostRequest(marshalledJSON, cfg)
139         if err != nil {
140                 fmt.Fprintln(os.Stderr, err)
141                 os.Exit(1)
142         }
143
144         // Choose how to display the result based on its type.
145         strResult := string(result)
146         if strings.HasPrefix(strResult, "{") || strings.HasPrefix(strResult, "[") {
147                 var dst bytes.Buffer
148                 if err := json.Indent(&dst, result, "", "  "); err != nil {
149                         fmt.Fprintf(os.Stderr, "Failed to format result: %v",
150                                 err)
151                         os.Exit(1)
152                 }
153                 fmt.Println(dst.String())
154
155         } else if strings.HasPrefix(strResult, `"`) {
156                 var str string
157                 if err := json.Unmarshal(result, &str); err != nil {
158                         fmt.Fprintf(os.Stderr, "Failed to unmarshal result: %v",
159                                 err)
160                         os.Exit(1)
161                 }
162                 fmt.Println(str)
163
164         } else if strResult != "null" {
165                 fmt.Println(strResult)
166         }
167 }