mirror of
https://github.com/golang/go
synced 2024-11-18 11:24:41 -07:00
internal/jsonrpc2: replace NewErrorf with fmt.Errorf
We utilize error wrapping to recover the error codes when needed. The code constants are also replaced by fully declared errors with human readable messages. Change-Id: I8edeb05f5028e99966e4ca28151f644f008d4e7d Reviewed-on: https://go-review.googlesource.com/c/tools/+/227837 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
79a7a3126e
commit
2595e72532
@ -22,7 +22,7 @@ type Handler func(context.Context, *Request) error
|
||||
// standard method not found response.
|
||||
// This should normally be the final handler in a chain.
|
||||
func MethodNotFound(ctx context.Context, r *Request) error {
|
||||
return r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: %q", ErrMethodNotFound, r.Method))
|
||||
}
|
||||
|
||||
// MustReply creates a Handler that panics if the wrapped handler does
|
||||
|
@ -10,6 +10,7 @@ package jsonrpc2
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@ -50,15 +51,6 @@ type constError string
|
||||
|
||||
func (e constError) Error() string { return string(e) }
|
||||
|
||||
// NewErrorf builds a Error struct for the supplied message and code.
|
||||
// If args is not empty, message and args will be passed to Sprintf.
|
||||
func NewErrorf(code int64, format string, args ...interface{}) *Error {
|
||||
return &Error{
|
||||
Code: code,
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewConn creates a new connection object around the supplied stream.
|
||||
// You must call Run for the connection to be active.
|
||||
func NewConn(s Stream) *Conn {
|
||||
@ -212,7 +204,13 @@ func (r *Request) Reply(ctx context.Context, result interface{}, err error) erro
|
||||
if callErr, ok := err.(*Error); ok {
|
||||
response.Error = callErr
|
||||
} else {
|
||||
response.Error = NewErrorf(0, "%s", err)
|
||||
response.Error = &Error{Message: err.Error()}
|
||||
var wrapped *Error
|
||||
if errors.As(err, &wrapped) {
|
||||
// if we wrapped a wire error, keep the code from the wrapped error
|
||||
// but the message from the outer error
|
||||
response.Error.Code = wrapped.Code
|
||||
}
|
||||
}
|
||||
}
|
||||
data, err := json.Marshal(response)
|
||||
|
@ -123,25 +123,25 @@ func testHandler(log bool) jsonrpc2.Handler {
|
||||
switch r.Method {
|
||||
case "no_args":
|
||||
if r.Params != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
|
||||
}
|
||||
return r.Reply(ctx, true, nil)
|
||||
case "one_string":
|
||||
var v string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
|
||||
}
|
||||
return r.Reply(ctx, "got:"+v, nil)
|
||||
case "one_number":
|
||||
var v int
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
|
||||
}
|
||||
return r.Reply(ctx, fmt.Sprintf("got:%d", v), nil)
|
||||
case "join":
|
||||
var v []string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
|
||||
}
|
||||
return r.Reply(ctx, path.Join(v...), nil)
|
||||
default:
|
||||
|
@ -13,25 +13,25 @@ import (
|
||||
// this file contains the go forms of the wire specification
|
||||
// see http://www.jsonrpc.org/specification for details
|
||||
|
||||
const (
|
||||
// CodeUnknownError should be used for all non coded errors.
|
||||
CodeUnknownError = -32001
|
||||
// CodeParseError is used when invalid JSON was received by the server.
|
||||
CodeParseError = -32700
|
||||
//CodeInvalidRequest is used when the JSON sent is not a valid Request object.
|
||||
CodeInvalidRequest = -32600
|
||||
// CodeMethodNotFound should be returned by the handler when the method does
|
||||
var (
|
||||
// ErrUnknown should be used for all non coded errors.
|
||||
ErrUnknown = NewError(-32001, "JSON RPC unknown error")
|
||||
// ErrParse is used when invalid JSON was received by the server.
|
||||
ErrParse = NewError(-32700, "JSON RPC parse error")
|
||||
//ErrInvalidRequest is used when the JSON sent is not a valid Request object.
|
||||
ErrInvalidRequest = NewError(-32600, "JSON RPC invalid request")
|
||||
// ErrMethodNotFound should be returned by the handler when the method does
|
||||
// not exist / is not available.
|
||||
CodeMethodNotFound = -32601
|
||||
// CodeInvalidParams should be returned by the handler when method
|
||||
ErrMethodNotFound = NewError(-32601, "JSON RPC method not found")
|
||||
// ErrInvalidParams should be returned by the handler when method
|
||||
// parameter(s) were invalid.
|
||||
CodeInvalidParams = -32602
|
||||
// CodeInternalError is not currently returned but defined for completeness.
|
||||
CodeInternalError = -32603
|
||||
ErrInvalidParams = NewError(-32602, "JSON RPC invalid params")
|
||||
// ErrInternal is not currently returned but defined for completeness.
|
||||
ErrInternal = NewError(-32603, "JSON RPC internal error")
|
||||
|
||||
//CodeServerOverloaded is returned when a message was refused due to a
|
||||
//ErrServerOverloaded is returned when a message was refused due to a
|
||||
//server being temporarily unable to accept any new messages.
|
||||
CodeServerOverloaded = -32000
|
||||
ErrServerOverloaded = NewError(-32000, "JSON RPC overloaded")
|
||||
)
|
||||
|
||||
// WireRequest is sent to a server to represent a Call or Notify operaton.
|
||||
@ -87,10 +87,14 @@ type ID struct {
|
||||
Number int64
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
if err == nil {
|
||||
return ""
|
||||
func NewError(code int64, message string) error {
|
||||
return &Error{
|
||||
Code: code,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func (err *Error) Error() string {
|
||||
return err.Message
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
|
||||
s.stateMu.Lock()
|
||||
if s.state >= serverInitializing {
|
||||
defer s.stateMu.Unlock()
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidRequest, "initialize called while server in %v state", s.state)
|
||||
return nil, fmt.Errorf("%w: initialize called while server in %v state", jsonrpc2.ErrInvalidRequest, s.state)
|
||||
}
|
||||
s.state = serverInitializing
|
||||
s.stateMu.Unlock()
|
||||
@ -118,7 +118,7 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
|
||||
s.stateMu.Lock()
|
||||
if s.state >= serverInitialized {
|
||||
defer s.stateMu.Unlock()
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidRequest, "initalized called while server in %v state", s.state)
|
||||
return fmt.Errorf("%w: initalized called while server in %v state", jsonrpc2.ErrInvalidRequest, s.state)
|
||||
}
|
||||
s.state = serverInitialized
|
||||
s.stateMu.Unlock()
|
||||
|
@ -534,7 +534,7 @@ func handshaker(client *debugClient, goplsPath string, handler jsonrpc2.Handler)
|
||||
|
||||
func sendError(ctx context.Context, req *jsonrpc2.Request, err error) {
|
||||
if _, ok := err.(*jsonrpc2.Error); !ok {
|
||||
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
err = fmt.Errorf("%w: %v", jsonrpc2.ErrParse, err)
|
||||
}
|
||||
if err := req.Reply(ctx, nil, err); err != nil {
|
||||
event.Error(ctx, "", err)
|
||||
|
@ -14,9 +14,9 @@ import (
|
||||
"golang.org/x/tools/internal/xcontext"
|
||||
)
|
||||
|
||||
const (
|
||||
var (
|
||||
// RequestCancelledError should be used when a request is cancelled early.
|
||||
RequestCancelledError = -32800
|
||||
RequestCancelledError = jsonrpc2.NewError(-32800, "JSON RPC cancelled")
|
||||
)
|
||||
|
||||
// ClientDispatcher returns a Client that dispatches LSP requests across the
|
||||
@ -79,7 +79,7 @@ func cancelCall(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
|
||||
|
||||
func sendParseError(ctx context.Context, req *jsonrpc2.Request, err error) error {
|
||||
if _, ok := err.(*jsonrpc2.Error); !ok {
|
||||
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
err = fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err)
|
||||
}
|
||||
return req.Reply(ctx, nil, err)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ package protocol
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/xcontext"
|
||||
@ -34,7 +35,7 @@ func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) error {
|
||||
if ctx.Err() != nil {
|
||||
ctx := xcontext.Detach(ctx)
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
|
||||
return r.Reply(ctx, nil, RequestCancelledError)
|
||||
}
|
||||
switch r.Method {
|
||||
case "window/showMessage": // notif
|
||||
@ -74,7 +75,7 @@ func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler {
|
||||
return r.Reply(ctx, nil, err)
|
||||
case "workspace/workspaceFolders": // req
|
||||
if r.Params != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
|
||||
}
|
||||
resp, err := client.WorkspaceFolders(ctx)
|
||||
return r.Reply(ctx, resp, err)
|
||||
|
@ -10,6 +10,7 @@ package protocol
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/xcontext"
|
||||
@ -72,7 +73,7 @@ func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) error {
|
||||
if ctx.Err() != nil {
|
||||
ctx := xcontext.Detach(ctx)
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
|
||||
return r.Reply(ctx, nil, RequestCancelledError)
|
||||
}
|
||||
switch r.Method {
|
||||
case "workspace/didChangeWorkspaceFolders": // notif
|
||||
@ -219,7 +220,7 @@ func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler {
|
||||
return r.Reply(ctx, resp, err)
|
||||
case "shutdown": // req
|
||||
if r.Params != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
|
||||
}
|
||||
err := server.Shutdown(ctx)
|
||||
return r.Reply(ctx, nil, err)
|
||||
|
@ -908,7 +908,7 @@ let server: side = {
|
||||
|
||||
// commonly used output
|
||||
const notNil = `if r.Params != nil {
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return r.Reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.CodeInvalidParams))
|
||||
}`;
|
||||
|
||||
// Go code for notifications. Side is client or server, m is the request
|
||||
@ -1071,6 +1071,7 @@ function output(side: side) {
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/xcontext"
|
||||
@ -1084,7 +1085,7 @@ function output(side: side) {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) error {
|
||||
if ctx.Err() != nil {
|
||||
ctx := xcontext.Detach(ctx)
|
||||
return r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, ""))
|
||||
return r.Reply(ctx, nil, RequestCancelledError)
|
||||
}
|
||||
switch r.Method {`);
|
||||
side.cases.forEach((v) => {f(v)});
|
||||
|
@ -160,8 +160,8 @@ func (s *Server) clearInProgress(token string) {
|
||||
s.inProgressMu.Unlock()
|
||||
}
|
||||
|
||||
func notImplemented(method string) *jsonrpc2.Error {
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not yet implemented", method)
|
||||
func notImplemented(method string) error {
|
||||
return fmt.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method)
|
||||
}
|
||||
|
||||
//go:generate helper/helper -d protocol/tsserver.go -o server_gen.go -u .
|
||||
|
@ -243,7 +243,7 @@ func (s *Server) wasFirstChange(uri span.URI) bool {
|
||||
|
||||
func (s *Server) changedText(ctx context.Context, uri span.URI, changes []protocol.TextDocumentContentChangeEvent) ([]byte, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "no content changes provided")
|
||||
return nil, fmt.Errorf("%w: no content changes provided", jsonrpc2.ErrInternal)
|
||||
}
|
||||
|
||||
// Check if the client sent the full content of the file.
|
||||
@ -257,7 +257,7 @@ func (s *Server) changedText(ctx context.Context, uri span.URI, changes []protoc
|
||||
func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, changes []protocol.TextDocumentContentChangeEvent) ([]byte, error) {
|
||||
content, _, err := s.session.GetFile(uri).Read(ctx)
|
||||
if err != nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "file not found (%v)", err)
|
||||
return nil, fmt.Errorf("%w: file not found (%v)", jsonrpc2.ErrInternal, err)
|
||||
}
|
||||
for _, change := range changes {
|
||||
// Make sure to update column mapper along with the content.
|
||||
@ -268,18 +268,18 @@ func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, chan
|
||||
Content: content,
|
||||
}
|
||||
if change.Range == nil {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "unexpected nil range for change")
|
||||
return nil, fmt.Errorf("%w: unexpected nil range for change", jsonrpc2.ErrInternal)
|
||||
}
|
||||
spn, err := m.RangeSpan(*change.Range)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !spn.HasOffset() {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "invalid range for content change")
|
||||
return nil, fmt.Errorf("%w: invalid range for content change", jsonrpc2.ErrInternal)
|
||||
}
|
||||
start, end := spn.Start().Offset(), spn.End().Offset()
|
||||
if end < start {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "invalid range for content change")
|
||||
return nil, fmt.Errorf("%w: invalid range for content change", jsonrpc2.ErrInternal)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.Write(content[:start])
|
||||
|
Loading…
Reference in New Issue
Block a user