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  }