90 lines
2.9 KiB
Go
Raw Normal View History

package jrpc2
import (
"encoding/json"
"errors"
"fmt"
"github.com/creachadair/jrpc2/code"
)
// Error is the concrete type of errors returned from RPC calls.
type Error struct {
message string
code code.Code
data json.RawMessage
}
// Error renders e to a human-readable string for the error interface.
func (e Error) Error() string { return fmt.Sprintf("[%d] %s", e.code, e.message) }
// Code returns the error code value associated with e.
func (e Error) Code() code.Code { return e.code }
// Message returns the message string associated with e.
func (e Error) Message() string { return e.message }
// HasData reports whether e has error data to unmarshal.
func (e Error) HasData() bool { return len(e.data) != 0 }
// UnmarshalData decodes the error data associated with e into v. It returns
// ErrNoData without modifying v if there was no data message attached to e.
func (e Error) UnmarshalData(v interface{}) error {
if !e.HasData() {
return ErrNoData
}
return json.Unmarshal([]byte(e.data), v)
}
// MarshalJSON implements the json.Marshaler interface for Error values.
func (e Error) MarshalJSON() ([]byte, error) {
return json.Marshal(jerror{C: int32(e.code), M: e.message, D: e.data})
}
// UnmarshalJSON implements the json.Unmarshaler interface for Error values.
func (e *Error) UnmarshalJSON(data []byte) error {
var v jerror
if err := json.Unmarshal(data, &v); err != nil {
return err
}
e.code = code.Code(v.C)
e.message = v.M
e.data = v.D
return nil
}
// ErrNoData indicates that there are no data to unmarshal.
var ErrNoData = errors.New("no data to unmarshal")
// errServerStopped is returned by Server.Wait when the server was shut down by
// an explicit call to its Stop method or orderly termination of its channel.
var errServerStopped = errors.New("the server has been stopped")
// errClientStopped is the error reported when a client is shut down by an
// explicit call to its Close method.
var errClientStopped = errors.New("the client has been stopped")
// ErrConnClosed is returned by a server's push-to-client methods if they are
// called after the client connection is closed.
var ErrConnClosed = errors.New("client connection is closed")
// Errorf returns an error value of concrete type *Error having the specified
// code and formatted message string.
// It is shorthand for DataErrorf(code, nil, msg, args...)
func Errorf(code code.Code, msg string, args ...interface{}) error {
return DataErrorf(code, nil, msg, args...)
}
// DataErrorf returns an error value of concrete type *Error having the
// specified code, error data, and formatted message string.
// If v == nil this behaves identically to Errorf(code, msg, args...).
func DataErrorf(code code.Code, v interface{}, msg string, args ...interface{}) error {
e := &Error{code: code, message: fmt.Sprintf(msg, args...)}
if v != nil {
if data, err := json.Marshal(v); err == nil {
e.data = data
}
}
return e
}