internal/jsonrpc2: add concrete types for Call, Notify and Response

The previous implementation was exposing the details of the wire format
and resulted in non idomatic go, detecting the presence of absence of
values in fields to deterimine the message type.
Now the messages are distinct types and we use type switches instead.
Request still exists as an interface to expose the shared behaviour of
Call and Notification, as this is the type accepted by handlers.
The set of messages is deliberately closed by using a private methods on the
interfaces.

Change-Id: I2cf15ee3923ef4688670c62896f81f760c77fe04
Reviewed-on: https://go-review.googlesource.com/c/tools/+/228719
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:
Ian Cottrell 2020-04-12 22:47:10 -04:00
Родитель 98173f2f69
Коммит 434f7a8fef
10 изменённых файлов: 435 добавлений и 263 удалений

Просмотреть файл

@ -14,7 +14,7 @@ import (
// Handler is invoked to handle incoming requests.
// The Replier sends a reply to the request and must be called exactly once.
type Handler func(ctx context.Context, reply Replier, req *Request) error
type Handler func(ctx context.Context, reply Replier, req Request) error
// Replier is passed to handlers to allow them to reply to the request.
// If err is set then result will be ignored.
@ -23,24 +23,24 @@ type Replier func(ctx context.Context, result interface{}, err error) error
// MethodNotFound is a Handler that replies to all call requests with the
// standard method not found response.
// This should normally be the final handler in a chain.
func MethodNotFound(ctx context.Context, reply Replier, r *Request) error {
return reply(ctx, nil, fmt.Errorf("%w: %q", ErrMethodNotFound, r.Method))
func MethodNotFound(ctx context.Context, reply Replier, req Request) error {
return reply(ctx, nil, fmt.Errorf("%w: %q", ErrMethodNotFound, req.Method()))
}
// MustReplyHandler creates a Handler that panics if the wrapped handler does
// not call Reply for every request that it is passed.
func MustReplyHandler(handler Handler) Handler {
return func(ctx context.Context, reply Replier, req *Request) error {
return func(ctx context.Context, reply Replier, req Request) error {
called := false
err := handler(ctx, func(ctx context.Context, result interface{}, err error) error {
if called {
panic(fmt.Errorf("request %q replied to more than once", req.Method))
panic(fmt.Errorf("request %q replied to more than once", req.Method()))
}
called = true
return reply(ctx, result, err)
}, req)
if !called {
panic(fmt.Errorf("request %q was never replied to", req.Method))
panic(fmt.Errorf("request %q was never replied to", req.Method()))
}
return err
}
@ -51,17 +51,17 @@ func MustReplyHandler(handler Handler) Handler {
func CancelHandler(handler Handler) (Handler, func(id ID)) {
var mu sync.Mutex
handling := make(map[ID]context.CancelFunc)
wrapped := func(ctx context.Context, reply Replier, req *Request) error {
if req.ID != nil {
wrapped := func(ctx context.Context, reply Replier, req Request) error {
if call, ok := req.(*Call); ok {
cancelCtx, cancel := context.WithCancel(ctx)
ctx = cancelCtx
mu.Lock()
handling[*req.ID] = cancel
handling[call.ID()] = cancel
mu.Unlock()
innerReply := reply
reply = func(ctx context.Context, result interface{}, err error) error {
mu.Lock()
delete(handling, *req.ID)
delete(handling, call.ID())
mu.Unlock()
return innerReply(ctx, result, err)
}
@ -87,7 +87,7 @@ func CancelHandler(handler Handler) (Handler, func(id ID)) {
func AsyncHandler(handler Handler) Handler {
nextRequest := make(chan struct{})
close(nextRequest)
return func(ctx context.Context, reply Replier, req *Request) error {
return func(ctx context.Context, reply Replier, req Request) error {
waitForPrevious := nextRequest
nextRequest = make(chan struct{})
unlockNext := nextRequest

Просмотреть файл

@ -10,7 +10,6 @@ package jsonrpc2
import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"sync/atomic"
@ -33,20 +32,7 @@ type Conn struct {
seq int64 // must only be accessed using atomic operations
stream Stream
pendingMu sync.Mutex // protects the pending map
pending map[ID]chan *wireResponse
}
// Request is sent to a server to represent a Call or Notify operaton.
type Request struct {
// The Wire values of the request.
// Method is a string containing the method name to invoke.
Method string
// Params is either a struct or an array with the parameters of the method.
Params *json.RawMessage
// The id of this request, used to tie the Response back to the request.
// Will be either a string or a number. If not set, the Request is a notify,
// and no response is possible.
ID *ID
pending map[ID]chan *Response
}
type constError string
@ -58,7 +44,7 @@ func (e constError) Error() string { return string(e) }
func NewConn(s Stream) *Conn {
conn := &Conn{
stream: s,
pending: make(map[ID]chan *wireResponse),
pending: make(map[ID]chan *Response),
}
return conn
}
@ -67,22 +53,17 @@ func NewConn(s Stream) *Conn {
// It will return as soon as the notification has been sent, as no response is
// possible.
func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (err error) {
jsonParams, err := marshalToRaw(params)
notify, err := NewNotification(method, params)
if err != nil {
return fmt.Errorf("marshaling notify parameters: %v", err)
}
request := &wireRequest{
Method: method,
Params: jsonParams,
}
data, err := json.Marshal(request)
data, err := json.Marshal(notify)
if err != nil {
return fmt.Errorf("marshaling notify request: %v", err)
}
ctx, done := event.StartSpan(ctx, request.Method,
tag.Method.Of(request.Method),
ctx, done := event.StartSpan(ctx, method,
tag.Method.Of(method),
tag.RPCDirection.Of(tag.Outbound),
tag.RPCID.Of(fmt.Sprintf("%q", request.ID)),
)
defer func() {
recordStatus(ctx, err)
@ -101,24 +82,19 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (e
func (c *Conn) Call(ctx context.Context, method string, params, result interface{}) (_ ID, err error) {
// generate a new request identifier
id := ID{number: atomic.AddInt64(&c.seq, 1)}
jsonParams, err := marshalToRaw(params)
call, err := NewCall(id, method, params)
if err != nil {
return id, fmt.Errorf("marshaling call parameters: %v", err)
}
request := &wireRequest{
ID: &id,
Method: method,
Params: jsonParams,
}
// marshal the request now it is complete
data, err := json.Marshal(request)
data, err := json.Marshal(call)
if err != nil {
return id, fmt.Errorf("marshaling call request: %v", err)
}
ctx, done := event.StartSpan(ctx, request.Method,
tag.Method.Of(request.Method),
ctx, done := event.StartSpan(ctx, method,
tag.Method.Of(method),
tag.RPCDirection.Of(tag.Outbound),
tag.RPCID.Of(fmt.Sprintf("%q", request.ID)),
tag.RPCID.Of(fmt.Sprintf("%q", id)),
)
defer func() {
recordStatus(ctx, err)
@ -129,7 +105,7 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
// are racing the response. Also add a buffer to rchan, so that if we get a
// wire response between the time this call is cancelled and id is deleted
// from c.pending, the send to rchan will not block.
rchan := make(chan *wireResponse, 1)
rchan := make(chan *Response, 1)
c.pendingMu.Lock()
c.pending[id] = rchan
c.pendingMu.Unlock()
@ -149,13 +125,13 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
select {
case response := <-rchan:
// is it an error response?
if response.Error != nil {
return id, response.Error
if response.err != nil {
return id, response.err
}
if result == nil || response.Result == nil {
if result == nil || len(response.result) == 0 {
return id, nil
}
if err := json.Unmarshal(*response.Result, result); err != nil {
if err := json.Unmarshal(response.result, result); err != nil {
return id, fmt.Errorf("unmarshaling result: %v", err)
}
return id, nil
@ -164,43 +140,22 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
}
}
func replier(conn *Conn, r *Request, spanDone func()) Replier {
func replier(conn *Conn, req Request, spanDone func()) Replier {
return func(ctx context.Context, result interface{}, err error) error {
defer func() {
recordStatus(ctx, err)
spanDone()
}()
if r.ID == nil {
call, ok := req.(*Call)
if !ok {
// request was a notify, no need to respond
return nil
}
var raw *json.RawMessage
if err == nil {
raw, err = marshalToRaw(result)
}
response := &wireResponse{
Result: raw,
ID: r.ID,
}
if err != nil {
if callErr, ok := err.(*wireError); ok {
response.Error = callErr
} else {
response.Error = &wireError{Message: err.Error()}
var wrapped *wireError
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)
response, err := NewResponse(call.id, result, err)
if err != nil {
return err
}
data, err := json.Marshal(response)
n, err := conn.stream.Write(ctx, data)
event.Record(ctx, tag.SentBytes.Of(n))
@ -227,61 +182,51 @@ func (c *Conn) Run(runCtx context.Context, handler Handler) error {
return err
}
// read a combined message
msg := &wireCombined{}
if err := json.Unmarshal(data, msg); err != nil {
msg, err := DecodeMessage(data)
if err != nil {
// a badly formed message arrived, log it and continue
// we trust the stream to have isolated the error to just this message
continue
}
// Work out whether this is a request or response.
switch {
case msg.Method != "":
// If method is set it must be a request.
reqCtx, spanDone := event.StartSpan(runCtx, msg.Method,
tag.Method.Of(msg.Method),
switch msg := msg.(type) {
case Request:
tags := []event.Tag{
tag.Method.Of(msg.Method()),
tag.RPCDirection.Of(tag.Inbound),
tag.RPCID.Of(fmt.Sprintf("%q", msg.ID)),
)
{}, // reserved for ID if present
}
if call, ok := msg.(*Call); ok {
tags[len(tags)-1] = tag.RPCID.Of(fmt.Sprintf("%q", call.ID()))
} else {
tags = tags[:len(tags)-1]
}
reqCtx, spanDone := event.StartSpan(runCtx, msg.Method(), tags...)
event.Record(reqCtx,
tag.Started.Of(1),
tag.ReceivedBytes.Of(n))
req := &Request{
Method: msg.Method,
Params: msg.Params,
ID: msg.ID,
}
if err := handler(reqCtx, replier(c, req, spanDone), req); err != nil {
if err := handler(reqCtx, replier(c, msg, spanDone), msg); err != nil {
// delivery failed, not much we can do
event.Error(reqCtx, "jsonrpc2 message delivery failed", err)
}
case msg.ID != nil:
case *Response:
// If method is not set, this should be a response, in which case we must
// have an id to send the response back to the caller.
c.pendingMu.Lock()
rchan, ok := c.pending[*msg.ID]
rchan, ok := c.pending[msg.id]
c.pendingMu.Unlock()
if ok {
response := &wireResponse{
Result: msg.Result,
Error: msg.Error,
ID: msg.ID,
}
rchan <- response
rchan <- msg
}
default:
}
}
}
func marshalToRaw(obj interface{}) (*json.RawMessage, error) {
func marshalToRaw(obj interface{}) (json.RawMessage, error) {
data, err := json.Marshal(obj)
if err != nil {
return nil, err
return json.RawMessage{}, err
}
raw := json.RawMessage(data)
return &raw, nil
return json.RawMessage(data), nil
}
func recordStatus(ctx context.Context, err error) {

Просмотреть файл

@ -134,28 +134,28 @@ func run(ctx context.Context, t *testing.T, withHeaders bool, r io.ReadCloser, w
}
func testHandler(log bool) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, req *jsonrpc2.Request) error {
switch req.Method {
return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
switch req.Method() {
case "no_args":
if req.Params != nil {
if len(req.Params()) > 0 {
return reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
}
return reply(ctx, true, nil)
case "one_string":
var v string
if err := json.Unmarshal(*req.Params, &v); err != nil {
if err := json.Unmarshal(req.Params(), &v); err != nil {
return reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
}
return reply(ctx, "got:"+v, nil)
case "one_number":
var v int
if err := json.Unmarshal(*req.Params, &v); err != nil {
if err := json.Unmarshal(req.Params(), &v); err != nil {
return reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
}
return reply(ctx, fmt.Sprintf("got:%d", v), nil)
case "join":
var v []string
if err := json.Unmarshal(*req.Params, &v); err != nil {
if err := json.Unmarshal(req.Params(), &v); err != nil {
return reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
}
return reply(ctx, path.Join(v...), nil)

Просмотреть файл

@ -0,0 +1,227 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package jsonrpc2
import (
"encoding/json"
"errors"
"fmt"
)
// Message is the interface to all jsonrpc2 message types.
// They share no common functionality, but are a closed set of concrete types
// that are allowed to implement this interface. The message types are *Call,
// *Notification and *Response.
type Message interface {
// isJSONRPC2Message is used to make the set of message implementations a
// closed set.
isJSONRPC2Message()
}
// Request is the shared interface to jsonrpc2 messages that request
// a method be invoked.
// The request types are a closed set of *Call and *Notification.
type Request interface {
Message
// Method is a string containing the method name to invoke.
Method() string
// Params is either a struct or an array with the parameters of the method.
Params() json.RawMessage
// isJSONRPC2Request is used to make the set of request implementations closed.
isJSONRPC2Request()
}
// Notification is a request for which a response cannot occur, and as such
// it has not ID.
type Notification struct {
// Method is a string containing the method name to invoke.
method string
params json.RawMessage
}
// Call is a request that expects a response.
// The response will have a matching ID.
type Call struct {
// Method is a string containing the method name to invoke.
method string
// Params is either a struct or an array with the parameters of the method.
params json.RawMessage
// id of this request, used to tie the Response back to the request.
id ID
}
// Response is a reply to a Call.
// It will have the same ID as the call it is a response to.
type Response struct {
// result is the content of the response.
result json.RawMessage
// err is set only if the call failed.
err error
// ID of the request this is a response to.
id ID
}
// NewNotification constructs a new Notification message for the supplied
// method and parameters.
func NewNotification(method string, params interface{}) (*Notification, error) {
p, merr := marshalToRaw(params)
return &Notification{method: method, params: p}, merr
}
func (msg *Notification) Method() string { return msg.method }
func (msg *Notification) Params() json.RawMessage { return msg.params }
func (msg *Notification) isJSONRPC2Message() {}
func (msg *Notification) isJSONRPC2Request() {}
func (n *Notification) MarshalJSON() ([]byte, error) {
msg := wireRequest{Method: n.method, Params: &n.params}
data, err := json.Marshal(msg)
if err != nil {
return data, fmt.Errorf("marshaling notification: %w", err)
}
return data, nil
}
func (n *Notification) UnmarshalJSON(data []byte) error {
msg := wireRequest{}
if err := json.Unmarshal(data, &msg); err != nil {
return fmt.Errorf("unmarshaling notification: %w", err)
}
n.method = msg.Method
if msg.Params != nil {
n.params = *msg.Params
}
return nil
}
// NewCall constructs a new Call message for the supplied ID, method and
// parameters.
func NewCall(id ID, method string, params interface{}) (*Call, error) {
p, merr := marshalToRaw(params)
return &Call{id: id, method: method, params: p}, merr
}
func (msg *Call) Method() string { return msg.method }
func (msg *Call) Params() json.RawMessage { return msg.params }
func (msg *Call) ID() ID { return msg.id }
func (msg *Call) isJSONRPC2Message() {}
func (msg *Call) isJSONRPC2Request() {}
func (c *Call) MarshalJSON() ([]byte, error) {
msg := wireRequest{Method: c.method, Params: &c.params, ID: &c.id}
data, err := json.Marshal(msg)
if err != nil {
return data, fmt.Errorf("marshaling call: %w", err)
}
return data, nil
}
func (c *Call) UnmarshalJSON(data []byte) error {
msg := wireRequest{}
if err := json.Unmarshal(data, &msg); err != nil {
return fmt.Errorf("unmarshaling call: %w", err)
}
c.method = msg.Method
if msg.Params != nil {
c.params = *msg.Params
}
if msg.ID != nil {
c.id = *msg.ID
}
return nil
}
// NewResponse constructs a new Response message that is a reply to the
// supplied. If err is set result may be ignored.
func NewResponse(id ID, result interface{}, err error) (*Response, error) {
r, merr := marshalToRaw(result)
return &Response{id: id, result: r, err: err}, merr
}
func (msg *Response) ID() ID { return msg.id }
func (msg *Response) Result() json.RawMessage { return msg.result }
func (msg *Response) Err() error { return msg.err }
func (msg *Response) isJSONRPC2Message() {}
func (r *Response) MarshalJSON() ([]byte, error) {
msg := &wireResponse{Result: &r.result, Error: toWireError(r.err), ID: &r.id}
data, err := json.Marshal(msg)
if err != nil {
return data, fmt.Errorf("marshaling notification: %w", err)
}
return data, nil
}
func toWireError(err error) *wireError {
if err == nil {
// no error, the response is complete
return nil
}
if err, ok := err.(*wireError); ok {
// already a wire error, just use it
return err
}
result := &wireError{Message: err.Error()}
var wrapped *wireError
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
result.Code = wrapped.Code
}
return result
}
func (r *Response) UnmarshalJSON(data []byte) error {
msg := wireResponse{}
if err := json.Unmarshal(data, &msg); err != nil {
return fmt.Errorf("unmarshaling jsonrpc response: %w", err)
}
if msg.Result != nil {
r.result = *msg.Result
}
if msg.Error != nil {
r.err = msg.Error
}
if msg.ID != nil {
r.id = *msg.ID
}
return nil
}
func DecodeMessage(data []byte) (Message, error) {
msg := wireCombined{}
if err := json.Unmarshal(data, &msg); err != nil {
return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
}
if msg.Method == "" {
// no method, should be a response
if msg.ID == nil {
return nil, ErrInvalidRequest
}
response := &Response{id: *msg.ID}
if msg.Error != nil {
response.err = msg.Error
}
if msg.Result != nil {
response.result = *msg.Result
}
return response, nil
}
// has a method, must be a request
if msg.ID == nil {
// request with no ID is a notify
notify := &Notification{method: msg.Method}
if msg.Params != nil {
notify.params = *msg.Params
}
return notify, nil
}
// request with an ID, must be a call
call := &Call{method: msg.Method, id: *msg.ID}
if msg.Params != nil {
call.params = *msg.Params
}
return call, nil
}

Просмотреть файл

@ -16,7 +16,7 @@ type msg struct {
Msg string
}
func fakeHandler(ctx context.Context, reply jsonrpc2.Replier, req *jsonrpc2.Request) error {
func fakeHandler(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
return reply(ctx, &msg{"pong"}, nil)
}

Просмотреть файл

@ -416,10 +416,10 @@ func OverrideExitFuncsForTest() func() {
// instance from exiting. In the future it may also intercept 'shutdown' to
// provide more graceful shutdown of the client connection.
func forwarderHandler(handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r *jsonrpc2.Request) error {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
// TODO(golang.org/issues/34111): we should more gracefully disconnect here,
// once that process exists.
if r.Method == "exit" {
if r.Method() == "exit" {
ForwarderExitFunc(0)
// reply nil here to consume the message: in
// tests, ForwarderExitFunc may be overridden to something that doesn't
@ -486,12 +486,12 @@ const (
)
func handshaker(client *debugClient, goplsPath string, handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r *jsonrpc2.Request) error {
switch r.Method {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
switch r.Method() {
case handshakeMethod:
var req handshakeRequest
if err := json.Unmarshal(*r.Params, &req); err != nil {
sendError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &req); err != nil {
sendError(ctx, reply, err)
return nil
}
client.debugAddress = req.DebugAddr
@ -532,7 +532,7 @@ func handshaker(client *debugClient, goplsPath string, handler jsonrpc2.Handler)
}
}
func sendError(ctx context.Context, reply jsonrpc2.Replier, req *jsonrpc2.Request, err error) {
func sendError(ctx context.Context, reply jsonrpc2.Replier, err error) {
err = fmt.Errorf("%w: %v", jsonrpc2.ErrParse, err)
if err := reply(ctx, nil, err); err != nil {
event.Error(ctx, "", err)

Просмотреть файл

@ -40,20 +40,20 @@ func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler {
func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler {
handler, canceller := jsonrpc2.CancelHandler(handler)
return func(ctx context.Context, reply jsonrpc2.Replier, req *jsonrpc2.Request) error {
if req.Method != "$/cancelRequest" {
return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
if req.Method() != "$/cancelRequest" {
return handler(ctx, reply, req)
}
var params CancelParams
if err := json.Unmarshal(*req.Params, &params); err != nil {
return sendParseError(ctx, reply, req, err)
if err := json.Unmarshal(req.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
if n, ok := params.ID.(float64); ok {
canceller(*jsonrpc2.NewIntID(int64(n)))
} else if s, ok := params.ID.(string); ok {
canceller(*jsonrpc2.NewStringID(s))
} else {
return sendParseError(ctx, reply, req, fmt.Errorf("request ID %v malformed", params.ID))
return sendParseError(ctx, reply, fmt.Errorf("request ID %v malformed", params.ID))
}
return reply(ctx, nil, nil)
}
@ -75,6 +75,6 @@ func cancelCall(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: &id})
}
func sendParseError(ctx context.Context, reply jsonrpc2.Replier, req *jsonrpc2.Request, err error) error {
func sendParseError(ctx context.Context, reply jsonrpc2.Replier, err error) error {
return reply(ctx, nil, fmt.Errorf("%w: %s", jsonrpc2.ErrParse, err))
}

Просмотреть файл

@ -32,92 +32,92 @@ type Client interface {
}
func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r *jsonrpc2.Request) error {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
if ctx.Err() != nil {
ctx := xcontext.Detach(ctx)
return reply(ctx, nil, RequestCancelledError)
}
switch r.Method {
switch r.Method() {
case "window/showMessage": // notif
var params ShowMessageParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.ShowMessage(ctx, &params)
return reply(ctx, nil, err)
case "window/logMessage": // notif
var params LogMessageParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.LogMessage(ctx, &params)
return reply(ctx, nil, err)
case "telemetry/event": // notif
var params interface{}
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.Event(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/publishDiagnostics": // notif
var params PublishDiagnosticsParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.PublishDiagnostics(ctx, &params)
return reply(ctx, nil, err)
case "$/progress": // notif
var params ProgressParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.Progress(ctx, &params)
return reply(ctx, nil, err)
case "workspace/workspaceFolders": // req
if r.Params != nil {
if len(r.Params()) > 0 {
return reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
}
resp, err := client.WorkspaceFolders(ctx)
return reply(ctx, resp, err)
case "workspace/configuration": // req
var params ParamConfiguration
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := client.Configuration(ctx, &params)
return reply(ctx, resp, err)
case "window/workDoneProgress/create": // req
var params WorkDoneProgressCreateParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.WorkDoneProgressCreate(ctx, &params)
return reply(ctx, nil, err)
case "client/registerCapability": // req
var params RegistrationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.RegisterCapability(ctx, &params)
return reply(ctx, nil, err)
case "client/unregisterCapability": // req
var params UnregistrationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := client.UnregisterCapability(ctx, &params)
return reply(ctx, nil, err)
case "window/showMessageRequest": // req
var params ShowMessageRequestParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := client.ShowMessageRequest(ctx, &params)
return reply(ctx, resp, err)
case "workspace/applyEdit": // req
var params ApplyWorkspaceEditParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := client.ApplyEdit(ctx, &params)
return reply(ctx, resp, err)

Просмотреть файл

@ -70,30 +70,30 @@ type Server interface {
}
func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r *jsonrpc2.Request) error {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
if ctx.Err() != nil {
ctx := xcontext.Detach(ctx)
return reply(ctx, nil, RequestCancelledError)
}
switch r.Method {
switch r.Method() {
case "workspace/didChangeWorkspaceFolders": // notif
var params DidChangeWorkspaceFoldersParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidChangeWorkspaceFolders(ctx, &params)
return reply(ctx, nil, err)
case "window/workDoneProgress/cancel": // notif
var params WorkDoneProgressCancelParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.WorkDoneProgressCancel(ctx, &params)
return reply(ctx, nil, err)
case "initialized": // notif
var params InitializedParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.Initialized(ctx, &params)
return reply(ctx, nil, err)
@ -101,324 +101,324 @@ func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler {
return server.Exit(ctx)
case "workspace/didChangeConfiguration": // notif
var params DidChangeConfigurationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidChangeConfiguration(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/didOpen": // notif
var params DidOpenTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidOpen(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/didChange": // notif
var params DidChangeTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidChange(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/didClose": // notif
var params DidCloseTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidClose(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/didSave": // notif
var params DidSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidSave(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/willSave": // notif
var params WillSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.WillSave(ctx, &params)
return reply(ctx, nil, err)
case "workspace/didChangeWatchedFiles": // notif
var params DidChangeWatchedFilesParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.DidChangeWatchedFiles(ctx, &params)
return reply(ctx, nil, err)
case "$/setTraceNotification": // notif
var params SetTraceParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.SetTraceNotification(ctx, &params)
return reply(ctx, nil, err)
case "$/logTraceNotification": // notif
var params LogTraceParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err := server.LogTraceNotification(ctx, &params)
return reply(ctx, nil, err)
case "textDocument/implementation": // req
var params ImplementationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Implementation(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/typeDefinition": // req
var params TypeDefinitionParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.TypeDefinition(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/documentColor": // req
var params DocumentColorParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.DocumentColor(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/colorPresentation": // req
var params ColorPresentationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.ColorPresentation(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/foldingRange": // req
var params FoldingRangeParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.FoldingRange(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/declaration": // req
var params DeclarationParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Declaration(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/selectionRange": // req
var params SelectionRangeParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.SelectionRange(ctx, &params)
return reply(ctx, resp, err)
case "initialize": // req
var params ParamInitialize
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Initialize(ctx, &params)
return reply(ctx, resp, err)
case "shutdown": // req
if r.Params != nil {
if len(r.Params()) > 0 {
return reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
}
err := server.Shutdown(ctx)
return reply(ctx, nil, err)
case "textDocument/willSaveWaitUntil": // req
var params WillSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.WillSaveWaitUntil(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/completion": // req
var params CompletionParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Completion(ctx, &params)
return reply(ctx, resp, err)
case "completionItem/resolve": // req
var params CompletionItem
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Resolve(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/hover": // req
var params HoverParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Hover(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/signatureHelp": // req
var params SignatureHelpParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.SignatureHelp(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/definition": // req
var params DefinitionParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Definition(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/references": // req
var params ReferenceParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.References(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/documentHighlight": // req
var params DocumentHighlightParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.DocumentHighlight(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/documentSymbol": // req
var params DocumentSymbolParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.DocumentSymbol(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/codeAction": // req
var params CodeActionParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.CodeAction(ctx, &params)
return reply(ctx, resp, err)
case "workspace/symbol": // req
var params WorkspaceSymbolParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Symbol(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/codeLens": // req
var params CodeLensParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.CodeLens(ctx, &params)
return reply(ctx, resp, err)
case "codeLens/resolve": // req
var params CodeLens
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.ResolveCodeLens(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/documentLink": // req
var params DocumentLinkParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.DocumentLink(ctx, &params)
return reply(ctx, resp, err)
case "documentLink/resolve": // req
var params DocumentLink
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.ResolveDocumentLink(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/formatting": // req
var params DocumentFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Formatting(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/rangeFormatting": // req
var params DocumentRangeFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.RangeFormatting(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/onTypeFormatting": // req
var params DocumentOnTypeFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.OnTypeFormatting(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/rename": // req
var params RenameParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.Rename(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/prepareRename": // req
var params PrepareRenameParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.PrepareRename(ctx, &params)
return reply(ctx, resp, err)
case "workspace/executeCommand": // req
var params ExecuteCommandParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.ExecuteCommand(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/prepareCallHierarchy": // req
var params CallHierarchyPrepareParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.PrepareCallHierarchy(ctx, &params)
return reply(ctx, resp, err)
case "callHierarchy/incomingCalls": // req
var params CallHierarchyIncomingCallsParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.IncomingCalls(ctx, &params)
return reply(ctx, resp, err)
case "callHierarchy/outgoingCalls": // req
var params CallHierarchyOutgoingCallsParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.OutgoingCalls(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/semanticTokens": // req
var params SemanticTokensParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.SemanticTokens(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/semanticTokens/edits": // req
var params SemanticTokensEditsParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.SemanticTokensEdits(ctx, &params)
return reply(ctx, resp, err)
case "textDocument/semanticTokens/range": // req
var params SemanticTokensRangeParams
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.SemanticTokensRange(ctx, &params)
return reply(ctx, resp, err)
default:
var params interface{}
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.NonstandardRequest(ctx, r.Method, params)
resp, err := server.NonstandardRequest(ctx, r.Method(), params)
return reply(ctx, resp, err)
}

Просмотреть файл

@ -907,7 +907,7 @@ let server: side = {
};
// commonly used output
const notNil = `if r.Params != nil {
const notNil = `if len(r.Params()) > 0 {
return reply(ctx, nil, fmt.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
}`;
@ -923,8 +923,8 @@ function goNot(side: side, m: string) {
let case1 = notNil;
if (a != '' && a != 'void') {
case1 = `var params ${a}
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
err:= ${side.name}.${nm}(ctx, &params)
return reply(ctx, nil, err)`
@ -958,8 +958,8 @@ function goReq(side: side, m: string) {
if (a != '') {
if (extraTypes.has('Param' + nm)) a = 'Param' + nm
case1 = `var params ${a}
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}`;
}
const arg2 = a == '' ? '' : ', &params';
@ -1082,12 +1082,12 @@ function output(side: side) {
side.methods.forEach((v) => {f(v)});
f('}\n');
f(`func ${a}Handler(${side.name} ${a}, handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r *jsonrpc2.Request) error {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
if ctx.Err() != nil {
ctx := xcontext.Detach(ctx)
return reply(ctx, nil, RequestCancelledError)
}
switch r.Method {`);
switch r.Method() {`);
side.cases.forEach((v) => {f(v)});
f(`
}
@ -1118,10 +1118,10 @@ function nonstandardRequests() {
return handler(ctx, reply, r)`)
server.cases.push(`default:
var params interface{}
if err := json.Unmarshal(*r.Params, &params); err != nil {
return sendParseError(ctx, reply, r, err)
if err := json.Unmarshal(r.Params(), &params); err != nil {
return sendParseError(ctx, reply, err)
}
resp, err := server.NonstandardRequest(ctx, r.Method, params)
resp, err := server.NonstandardRequest(ctx, r.Method(), params)
return reply(ctx, resp, err)
`)
}