127 lines
4.3 KiB
Go
127 lines
4.3 KiB
Go
// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.
|
|
|
|
// Package code defines error code values used by the jrpc2 package.
|
|
package code
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// A Code is an error response code.
|
|
//
|
|
// Code values from and including -32768 to -32000 are reserved for pre-defined
|
|
// JSON-RPC errors. Any code within this range, but not defined explicitly
|
|
// below is reserved for future use. The remainder of the space is available
|
|
// for application defined errors.
|
|
//
|
|
// See also: https://www.jsonrpc.org/specification#error_object
|
|
type Code int32
|
|
|
|
func (c Code) String() string {
|
|
if s, ok := stdError[c]; ok {
|
|
return s
|
|
}
|
|
return fmt.Sprintf("error code %d", c)
|
|
}
|
|
|
|
// An ErrCoder is a value that can report an error code value.
|
|
type ErrCoder interface {
|
|
ErrCode() Code
|
|
}
|
|
|
|
// A codeError wraps a Code to satisfy the standard error interface. This
|
|
// indirection prevents a Code from accidentally being used as an error value.
|
|
// It also satisfies the ErrCoder interface, allowing the code to be recovered.
|
|
type codeError Code
|
|
|
|
// Error satisfies the error interface using the registered string for the
|
|
// code, if one is defined, or else a placeholder that describes the value.
|
|
func (c codeError) Error() string { return Code(c).String() }
|
|
|
|
// ErrCode trivially satisfies the ErrCoder interface.
|
|
func (c codeError) ErrCode() Code { return Code(c) }
|
|
|
|
// Is reports whether err is c or has a code equal to c.
|
|
func (c codeError) Is(err error) bool {
|
|
v, ok := err.(ErrCoder) // including codeError
|
|
return ok && v.ErrCode() == Code(c)
|
|
}
|
|
|
|
// Err converts c to an error value, which is nil for code.NoError and
|
|
// otherwise an error value whose code is c and whose text is based on the
|
|
// registered string for c if one exists.
|
|
func (c Code) Err() error {
|
|
if c == NoError {
|
|
return nil
|
|
}
|
|
return codeError(c)
|
|
}
|
|
|
|
// Error codes from and including -32768 to -32000 are reserved for pre-defined
|
|
// errors by the JSON-RPC specification. These constants cover the standard
|
|
// codes and implementation-specific codes used by the jrpc2 module.
|
|
const (
|
|
ParseError Code = -32700 // [std] Invalid JSON received by the server
|
|
InvalidRequest Code = -32600 // [std] The JSON sent is not a valid request object
|
|
MethodNotFound Code = -32601 // [std] The method does not exist or is unavailable
|
|
InvalidParams Code = -32602 // [std] Invalid method parameters
|
|
InternalError Code = -32603 // [std] Internal JSON-RPC error
|
|
|
|
NoError Code = -32099 // Denotes a nil error (used by FromError)
|
|
SystemError Code = -32098 // Errors from the operating environment
|
|
Cancelled Code = -32097 // Request cancelled (context.Canceled)
|
|
DeadlineExceeded Code = -32096 // Request deadline exceeded (context.DeadlineExceeded)
|
|
)
|
|
|
|
var stdError = map[Code]string{
|
|
ParseError: "parse error",
|
|
InvalidRequest: "invalid request",
|
|
MethodNotFound: "method not found",
|
|
InvalidParams: "invalid parameters",
|
|
InternalError: "internal error",
|
|
|
|
NoError: "no error (success)",
|
|
SystemError: "system error",
|
|
Cancelled: "request cancelled",
|
|
DeadlineExceeded: "deadline exceeded",
|
|
}
|
|
|
|
// Register adds a new Code value with the specified message string. This
|
|
// function will panic if the proposed value is already registered with a
|
|
// different string.
|
|
//
|
|
// Registering a code allows you to control the string returned by the String
|
|
// method for the code value you specify. It is not necessary to register a
|
|
// code before using it. An unregistered code renders a generic string.
|
|
func Register(value int32, message string) Code {
|
|
code := Code(value)
|
|
if s, ok := stdError[code]; ok && s != message {
|
|
panic(fmt.Sprintf("code %d is already registered for %q", code, s))
|
|
}
|
|
stdError[code] = message
|
|
return code
|
|
}
|
|
|
|
// FromError returns a Code to categorize the specified error.
|
|
// If err == nil, it returns code.NoError.
|
|
// If err is (or wraps) an ErrCoder, it returns the reported code value.
|
|
// If err is context.Canceled, it returns code.Cancelled.
|
|
// If err is context.DeadlineExceeded, it returns code.DeadlineExceeded.
|
|
// Otherwise it returns code.SystemError.
|
|
func FromError(err error) Code {
|
|
if err == nil {
|
|
return NoError
|
|
}
|
|
var c ErrCoder
|
|
if errors.As(err, &c) {
|
|
return c.ErrCode()
|
|
} else if errors.Is(err, context.Canceled) {
|
|
return Cancelled
|
|
} else if errors.Is(err, context.DeadlineExceeded) {
|
|
return DeadlineExceeded
|
|
}
|
|
return SystemError
|
|
}
|