github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/output/format.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package output 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "log" 12 ) 13 14 // Format is the target of output-format flag 15 var Format string 16 17 // ErrorCode is the code of error 18 type ErrorCode int 19 20 const ( 21 // UndefinedError used when an error cat't be classified 22 UndefinedError ErrorCode = iota 23 // UpdateError used when an error occurs when running update command 24 UpdateError 25 // RuntimeError used when an error occurs in runtime 26 RuntimeError 27 // NetworkError used when an network error is happened 28 NetworkError 29 // APIError used when an API error is happened 30 APIError 31 // ValidationError used when validation is not passed 32 ValidationError 33 // SerializationError used when marshal or unmarshal meets error 34 SerializationError 35 // ReadFileError used when error occurs during reading a file 36 ReadFileError 37 // WriteFileError used when error occurs during writing a file 38 WriteFileError 39 // FlagError used when invalid flag is set 40 FlagError 41 // ConvertError used when fail to converting data 42 ConvertError 43 // CryptoError used when crypto error occurs 44 CryptoError 45 // AddressError used if an error is related to address 46 AddressError 47 // InputError used when error about input occurs 48 InputError 49 // KeystoreError used when an error related to keystore 50 KeystoreError 51 // ConfigError used when an error about config occurs 52 ConfigError 53 // InstantiationError used when an error during instantiation 54 InstantiationError 55 // CompilerError used when an error occurs when using the solidity compiler 56 CompilerError 57 ) 58 59 // MessageType marks the type of output message 60 type MessageType int 61 62 const ( 63 // Result represents the result of a command 64 Result MessageType = iota 65 // Confirmation represents request for confirmation 66 Confirmation 67 // Query represents request for answer of certain question 68 Query 69 // Error represents error occurred when running a command 70 Error 71 // Warn represents non-fatal mistake occurred when running a command 72 Warn 73 ) 74 75 // Output is used for format output 76 type Output struct { 77 MessageType MessageType `json:"messageType"` 78 Message Message `json:"message"` 79 MessageWithTranslation MessageWithTranslation `json:"messageWithTranslation"` 80 } 81 82 // Message is the message part of output 83 type Message interface { 84 String() string 85 } 86 87 // MessageWithTranslation is the message part of output supporting multi languages 88 type MessageWithTranslation interface { 89 String(args ...string) string 90 } 91 92 // ConfirmationMessage is the struct of an Confirmation output 93 type ConfirmationMessage struct { 94 Info string `json:"info"` 95 Options []string `json:"options"` 96 } 97 98 func (m *ConfirmationMessage) String() string { 99 if Format == "" { 100 line := fmt.Sprintf("%s\nOptions:", m.Info) 101 for _, option := range m.Options { 102 line += " " + option 103 } 104 line += "\nQuit for anything else." 105 return line 106 } 107 return FormatString(Confirmation, m) 108 } 109 110 // ErrorMessage is the struct of an Error output 111 type ErrorMessage struct { 112 Code ErrorCode `json:"code"` 113 Info string `json:"info"` 114 } 115 116 func (m *ErrorMessage) String() string { 117 if Format == "" { 118 return fmt.Sprintf("%d, %s", m.Code, m.Info) 119 } 120 return FormatString(Error, m) 121 } 122 123 // Error implements error interface 124 func (m ErrorMessage) Error() string { 125 return m.Info 126 } 127 128 // StringMessage is the Message for string 129 type StringMessage string 130 131 func (m StringMessage) String() string { 132 if Format == "" { 133 return string(m) 134 } 135 return FormatString(Result, m) 136 } 137 138 // Query prints query message 139 func (m StringMessage) Query() string { 140 if Format == "" { 141 return string(m) 142 } 143 return FormatString(Query, m) 144 } 145 146 // Warn prints warn message 147 func (m StringMessage) Warn() string { 148 if Format == "" { 149 return fmt.Sprintf("Warn: %s\n", string(m)) 150 } 151 return FormatString(Warn, m) 152 } 153 154 // FormatString returns Output as string in certain format 155 func FormatString(t MessageType, m Message) string { 156 out := Output{ 157 MessageType: t, 158 Message: m, 159 } 160 switch Format { 161 default: // default is json 162 return JSONString(out) 163 } 164 } 165 166 // FormatStringWithTrans returns Output as string in certain format supporting multi languages 167 func FormatStringWithTrans(t MessageType, m MessageWithTranslation) string { 168 out := Output{ 169 MessageType: t, 170 MessageWithTranslation: m, 171 } 172 switch Format { 173 default: // default is json 174 return JSONString(out) 175 } 176 } 177 178 // JSONString returns json string for message 179 func JSONString(out interface{}) string { 180 byteAsJSON, err := json.MarshalIndent(out, "", " ") 181 if err != nil { 182 log.Panic(err) 183 } 184 return fmt.Sprint(string(byteAsJSON)) 185 } 186 187 // NewError and returns golang error that contains Error Message 188 // ErrorCode can pass zero only when previous error is always a format error 189 // that contains non-zero error code. ErrorCode passes 0 means that I want to 190 // use previous error's code rather than override it. 191 // If there is no previous error, newInfo should not be empty. 192 func NewError(code ErrorCode, info string, pre error) error { 193 if pre == nil { 194 return ErrorMessage{Code: code, Info: info} 195 } 196 message, ok := pre.(ErrorMessage) 197 if ok { 198 if code != 0 { 199 // override error code 200 message.Code = code 201 } 202 if len(info) != 0 { 203 message.Info = fmt.Sprintf("%s: %s", info, message.Info) 204 } 205 } else { 206 message = ErrorMessage{Code: code, Info: fmt.Sprintf("%s: %s", info, pre.Error())} 207 } 208 return message 209 } 210 211 // PrintError prints Error Message in format, only used at top layer of a command 212 func PrintError(err error) error { 213 if err == nil || Format == "" { 214 return err 215 } 216 newErr := NewError(0, "", err) 217 message := newErr.(ErrorMessage) 218 fmt.Println(message.String()) 219 return nil 220 } 221 222 // PrintResult prints result message in format 223 func PrintResult(result string) { 224 message := StringMessage(result) 225 fmt.Println(message.String()) 226 } 227 228 // PrintQuery prints query message in format 229 func PrintQuery(query string) { 230 message := StringMessage(query) 231 fmt.Println(message.Query()) 232 }