1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 "golang.org/x/tools/internal/event"
15 // Handler is invoked to handle incoming requests.
16 // The Replier sends a reply to the request and must be called exactly once.
17 type Handler func(ctx context.Context, reply Replier, req Request) error
19 // Replier is passed to handlers to allow them to reply to the request.
20 // If err is set then result will be ignored.
21 type Replier func(ctx context.Context, result interface{}, err error) error
23 // MethodNotFound is a Handler that replies to all call requests with the
24 // standard method not found response.
25 // This should normally be the final handler in a chain.
26 func MethodNotFound(ctx context.Context, reply Replier, req Request) error {
27 return reply(ctx, nil, fmt.Errorf("%w: %q", ErrMethodNotFound, req.Method()))
30 // MustReplyHandler creates a Handler that panics if the wrapped handler does
31 // not call Reply for every request that it is passed.
32 func MustReplyHandler(handler Handler) Handler {
33 return func(ctx context.Context, reply Replier, req Request) error {
35 err := handler(ctx, func(ctx context.Context, result interface{}, err error) error {
37 panic(fmt.Errorf("request %q replied to more than once", req.Method()))
40 return reply(ctx, result, err)
43 panic(fmt.Errorf("request %q was never replied to", req.Method()))
49 // CancelHandler returns a handler that supports cancellation, and a function
50 // that can be used to trigger canceling in progress requests.
51 func CancelHandler(handler Handler) (Handler, func(id ID)) {
53 handling := make(map[ID]context.CancelFunc)
54 wrapped := func(ctx context.Context, reply Replier, req Request) error {
55 if call, ok := req.(*Call); ok {
56 cancelCtx, cancel := context.WithCancel(ctx)
59 handling[call.ID()] = cancel
62 reply = func(ctx context.Context, result interface{}, err error) error {
64 delete(handling, call.ID())
66 return innerReply(ctx, result, err)
69 return handler(ctx, reply, req)
71 return wrapped, func(id ID) {
73 cancel, found := handling[id]
81 // AsyncHandler returns a handler that processes each request goes in its own
83 // The handler returns immediately, without the request being processed.
84 // Each request then waits for the previous request to finish before it starts.
85 // This allows the stream to unblock at the cost of unbounded goroutines
86 // all stalled on the previous one.
87 func AsyncHandler(handler Handler) Handler {
88 nextRequest := make(chan struct{})
90 return func(ctx context.Context, reply Replier, req Request) error {
91 waitForPrevious := nextRequest
92 nextRequest = make(chan struct{})
93 unlockNext := nextRequest
95 reply = func(ctx context.Context, result interface{}, err error) error {
97 return innerReply(ctx, result, err)
99 _, queueDone := event.Start(ctx, "queued")
103 if err := handler(ctx, reply, req); err != nil {
104 event.Error(ctx, "jsonrpc2 async message delivery failed", err)