github.com/mavryk-network/mvgo@v1.19.9/rpc/errors.go (about)

     1  // Copyright (c) 2020-2022 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  package rpc
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/mavryk-network/mvgo/micheline"
    11  )
    12  
    13  const (
    14  	// ErrorKindPermanent Tezos RPC error kind.
    15  	ErrorKindPermanent = "permanent"
    16  	// ErrorKindTemporary Tezos RPC error kind.
    17  	ErrorKindTemporary = "temporary"
    18  	// ErrorKindBranch Tezos RPC error kind.
    19  	ErrorKindBranch = "branch"
    20  )
    21  
    22  func ErrorStatus(err error) int {
    23  	switch e := err.(type) {
    24  	case *httpError:
    25  		return e.statusCode
    26  	default:
    27  		return 0
    28  	}
    29  }
    30  
    31  // Error is a Tezos error as documented on http://protocol.mavryk.org/mainnet/api/errors.html.
    32  type Error interface {
    33  	error
    34  	ErrorID() string
    35  	ErrorKind() string
    36  }
    37  
    38  // GenericError is a basic error type
    39  type GenericError struct {
    40  	ID   string         `json:"id"`
    41  	Kind string         `json:"kind"`
    42  	With micheline.Prim `json:"with"`
    43  }
    44  
    45  func (e GenericError) Error() string {
    46  	var reason string
    47  	if e.With.IsValid() {
    48  		reason = e.With.Dump()
    49  	}
    50  	return fmt.Sprintf("tezos: kind=%s, id=%s, reason=%s", e.Kind, e.ID, reason)
    51  }
    52  
    53  // ErrorID returns Tezos error id
    54  func (e GenericError) ErrorID() string {
    55  	return e.ID
    56  }
    57  
    58  // ErrorKind returns Tezos error kind
    59  func (e GenericError) ErrorKind() string {
    60  	return e.Kind
    61  }
    62  
    63  // HTTPStatus interface represents an unprocessed HTTP reply
    64  type HTTPStatus interface {
    65  	Request() string // e.g. GET /...
    66  	Status() string  // e.g. "200 OK"
    67  	StatusCode() int // e.g. 200
    68  	Body() []byte
    69  }
    70  
    71  // HTTPError retains HTTP status
    72  type HTTPError interface {
    73  	error
    74  	HTTPStatus
    75  }
    76  
    77  // RPCError is a Tezos RPC error as documented on http://protocol.mavryk.org/mainnet/api/errors.html.
    78  type RPCError interface {
    79  	Error
    80  	HTTPStatus
    81  	Errors() []Error // returns all errors as a slice
    82  }
    83  
    84  // Errors is a slice of Error with custom JSON unmarshaller
    85  type Errors []Error
    86  
    87  // UnmarshalJSON implements json.Unmarshaler
    88  func (e *Errors) UnmarshalJSON(data []byte) error {
    89  	var errs []*GenericError
    90  
    91  	if err := json.Unmarshal(data, &errs); err != nil {
    92  		return err
    93  	}
    94  
    95  	*e = make(Errors, len(errs))
    96  	for i, g := range errs {
    97  		// TODO: handle different kinds
    98  		(*e)[i] = g
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  func (e Errors) Error() string {
   105  	if len(e) == 0 {
   106  		return ""
   107  	}
   108  	return e[0].Error()
   109  }
   110  
   111  // ErrorID returns Tezos error id
   112  func (e Errors) ErrorID() string {
   113  	if len(e) == 0 {
   114  		return ""
   115  	}
   116  	return e[0].ErrorID()
   117  }
   118  
   119  // ErrorKind returns Tezos error kind
   120  func (e Errors) ErrorKind() string {
   121  	if len(e) == 0 {
   122  		return ""
   123  	}
   124  	return e[0].ErrorKind()
   125  }
   126  
   127  type httpError struct {
   128  	request    string
   129  	status     string
   130  	statusCode int
   131  	body       []byte
   132  }
   133  
   134  func (e *httpError) Error() string {
   135  	return fmt.Sprintf("rpc: %s status %d (%v)", e.request, e.statusCode, string(e.body))
   136  }
   137  
   138  func (e *httpError) Request() string {
   139  	return e.request
   140  }
   141  
   142  func (e *httpError) Status() string {
   143  	return e.status
   144  }
   145  
   146  func (e *httpError) StatusCode() int {
   147  	return e.statusCode
   148  }
   149  
   150  func (e *httpError) Body() []byte {
   151  	return e.body
   152  }
   153  
   154  type rpcError struct {
   155  	*httpError
   156  	errors Errors
   157  }
   158  
   159  func (e *rpcError) Error() string {
   160  	return e.errors.Error()
   161  }
   162  
   163  func (e *rpcError) ErrorID() string {
   164  	return e.errors.ErrorID()
   165  }
   166  
   167  func (e *rpcError) ErrorKind() string {
   168  	return e.errors.ErrorKind()
   169  }
   170  
   171  func (e *rpcError) Errors() []Error {
   172  	return e.errors
   173  }
   174  
   175  type plainError struct {
   176  	*httpError
   177  	msg string
   178  }
   179  
   180  func (e *plainError) Error() string {
   181  	return e.msg
   182  }
   183  
   184  var (
   185  	_ Error    = &GenericError{}
   186  	_ Error    = Errors{}
   187  	_ RPCError = &rpcError{}
   188  )