-
Notifications
You must be signed in to change notification settings - Fork 98
feat: add 'Data' field to 'respError' struct #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
d56a7d5
8493164
dfc83a0
514c1af
a0806e5
53eab64
4358258
4e33c9f
9592989
65441ad
ef506b1
e8dc77a
90c8605
9ef484a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,3 +58,15 @@ type marshalable interface { | |
| json.Marshaler | ||
| json.Unmarshaler | ||
| } | ||
|
|
||
| // Error wraps RPC errors, which contain an error code in addition to the message. | ||
| type Error interface { | ||
| Error() string // returns the message | ||
| ErrorCode() int // returns the code | ||
| } | ||
|
|
||
| // DataError contains extra data to explain the error | ||
| type DataError interface { | ||
|
||
| Error() string // returns the message | ||
| ErrorData() interface{} // returns the error data | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ import ( | |||
| "context" | ||||
| "encoding/base64" | ||||
| "encoding/json" | ||||
| "errors" | ||||
| "fmt" | ||||
| "io" | ||||
| "reflect" | ||||
|
|
@@ -69,6 +70,7 @@ type respError struct { | |||
| Code ErrorCode `json:"code"` | ||||
| Message string `json:"message"` | ||||
| Meta json.RawMessage `json:"meta,omitempty"` | ||||
| Data interface{} `json:"data,omitempty"` | ||||
|
||||
| } | ||||
|
|
||||
| func (e *respError) Error() string { | ||||
|
|
@@ -78,6 +80,10 @@ func (e *respError) Error() string { | |||
| return e.Message | ||||
| } | ||||
|
|
||||
| func (e *respError) ErrorData() interface{} { | ||||
| return e.Data | ||||
| } | ||||
|
|
||||
| var marshalableRT = reflect.TypeOf(new(marshalable)).Elem() | ||||
|
|
||||
| func (e *respError) val(errors *Errors) reflect.Value { | ||||
|
|
@@ -104,10 +110,10 @@ func (e *respError) val(errors *Errors) reflect.Value { | |||
| } | ||||
|
|
||||
| type response struct { | ||||
| Jsonrpc string | ||||
| Result interface{} | ||||
| ID interface{} | ||||
| Error *respError | ||||
| Jsonrpc string `json:"jsonrpc"` | ||||
| Result interface{} `json:"result,omitempty"` | ||||
| ID interface{} `json:"id"` | ||||
| Error *respError `json:"error,omitempty"` | ||||
| } | ||||
|
|
||||
| func (r response) MarshalJSON() ([]byte, error) { | ||||
|
|
@@ -119,9 +125,11 @@ func (r response) MarshalJSON() ([]byte, error) { | |||
| // > `error`: | ||||
| // > This member is REQUIRED on error. | ||||
| // > This member MUST NOT exist if there was no error triggered during invocation. | ||||
| data := make(map[string]interface{}) | ||||
| data["jsonrpc"] = r.Jsonrpc | ||||
| data["id"] = r.ID | ||||
| data := map[string]interface{}{ | ||||
| "jsonrpc": r.Jsonrpc, | ||||
| "id": r.ID, | ||||
| } | ||||
|
|
||||
| if r.Error != nil { | ||||
| data["error"] = r.Error | ||||
| } else { | ||||
|
|
@@ -349,12 +357,24 @@ func (s *handler) createError(err error) *respError { | |||
| } | ||||
|
|
||||
| if m, ok := err.(marshalable); ok { | ||||
| meta, err := m.MarshalJSON() | ||||
| if err == nil { | ||||
| meta, marshalErr := m.MarshalJSON() | ||||
| if marshalErr == nil { | ||||
| out.Meta = meta | ||||
| } else { | ||||
| log.Warnf("Failed to marshal error metadata: %v", marshalErr) | ||||
| } | ||||
| } | ||||
|
|
||||
| var err2 Error | ||||
| if errors.As(err, &err2) { | ||||
| out.Code = ErrorCode(err2.ErrorCode()) | ||||
|
||||
| } | ||||
|
|
||||
| var de DataError | ||||
| if errors.As(err, &de) { | ||||
| out.Data = de.ErrorData() | ||||
| } | ||||
|
|
||||
| return out | ||||
| } | ||||
|
|
||||
|
|
@@ -504,10 +524,17 @@ func (s *handler) handle(ctx context.Context, req request, w func(func(io.Writer | |||
|
|
||||
| log.Warnf("failed to setup channel in RPC call to '%s': %+v", req.Method, err) | ||||
| stats.Record(ctx, metrics.RPCResponseError.M(1)) | ||||
| resp.Error = &respError{ | ||||
| respErr := &respError{ | ||||
|
||||
| callResult, err := doCall(req.Method, handler.handlerFunc, callParams) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this interface ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added so we can have custom error codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need custom error codes ? Can you write a bit explaining what made you add this ? Was it something you saw during your testing ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this needs a better name. This can be
ErrorWithCodeand the below can beErrorWithDataThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aarshkshah1992 I think this will give more idea towards the error codes: filecoin-project/lotus#12553