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 )