Skip to content

Commit

Permalink
deps: update x/tools and gopls to 44c82bac18ac (#845)
Browse files Browse the repository at this point in the history
* internal/jsonrpc2: make it an error to fail to call Reply 44c82bac
* internal/jsonrpc2: cleanup reply handling 7e0acf58
* internal/jsonrpc2: change handler to a function type 6dc6d571
* internal/lsp, go/packages: don't log context cancellation errors 44a64ad7
* go/packages: only list current module's directory in determineRootDirs 4480df5f
* internal/lsp: use context with timeout in all RunProcessEnvFuncs bcf69026
* internal/lsp/regtest: clean up module names and include github issues 8cb32c46
* internal/lsp: fix references for transitive dependencies 226fa68e
* internal/lsp: handle non-file:// URIs gracefully 72cf467e
* internal/lsp/regtest: add functions to make diagnostic assertions easier 8f5be0d3
  • Loading branch information
myitcv committed Apr 7, 2020
1 parent 0c3dd98 commit 281246e
Show file tree
Hide file tree
Showing 25 changed files with 765 additions and 1,014 deletions.
53 changes: 25 additions & 28 deletions cmd/govim/internal/golang_org_x_tools/jsonrpc2/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ package jsonrpc2

import (
"context"
"fmt"
)

// Handler is the interface used to hook into the message handling of an rpc
// connection.
type Handler interface {
// Handler is invoked to handle incoming requests.
// If the request returns false from IsNotify then the Handler must eventually
// call Reply on the Conn with the supplied request.
// The handler should return ErrNotHandled if it could not handle the request.
type Handler func(context.Context, *Request) error

// LegacyHooks is a temporary measure during migration from the old Handler
// interface to the new HandleFunc.
// The intent is to delete this interface in a later cl.
type LegacyHooks interface {
// Deliver is invoked to handle incoming requests.
// If the request returns false from IsNotify then the Handler must eventually
// call Reply on the Conn with the supplied request.
Expand Down Expand Up @@ -54,32 +62,21 @@ func (d Direction) String() string {
}
}

type EmptyHandler struct{}

func (EmptyHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
return false
}

func (EmptyHandler) Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool {
return false
}

func (EmptyHandler) Request(ctx context.Context, conn *Conn, direction Direction, r *WireRequest) context.Context {
return ctx
}

func (EmptyHandler) Response(ctx context.Context, conn *Conn, direction Direction, r *WireResponse) context.Context {
return ctx
// 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, r *Request) error {
return r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
}

type defaultHandler struct{ EmptyHandler }

func (defaultHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
if delivered {
return false
}
if !r.IsNotify() {
r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
// MustReply creates a Handler that panics if the wrapped handler does
// not call Reply for every request that it is passed.
func MustReply(handler Handler) Handler {
return func(ctx context.Context, req *Request) error {
err := handler(ctx, req)
if req.state < requestReplied {
panic(fmt.Errorf("request %q was never replied to", req.Method))
}
return err
}
return true
}
116 changes: 51 additions & 65 deletions cmd/govim/internal/golang_org_x_tools/jsonrpc2/jsonrpc2.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,24 @@ import (
"github.com/govim/govim/cmd/govim/internal/golang_org_x_tools/telemetry/event"
)

const (
// ErrIdleTimeout is returned when serving timed out waiting for new connections.
ErrIdleTimeout = constError("timed out waiting for new connections")

// ErrDisconnected signals that the stream or connection exited normally.
ErrDisconnected = constError("disconnected")
)

// Conn is a JSON RPC 2 client server connection.
// Conn is bidirectional; it does not have a designated server or client end.
type Conn struct {
seq int64 // must only be accessed using atomic operations
handlers []Handler
stream Stream
pendingMu sync.Mutex // protects the pending map
pending map[ID]chan *WireResponse
handlingMu sync.Mutex // protects the handling map
handling map[ID]*Request
seq int64 // must only be accessed using atomic operations
LegacyHooks LegacyHooks
stream Stream
pendingMu sync.Mutex // protects the pending map
pending map[ID]chan *WireResponse
handlingMu sync.Mutex // protects the handling map
handling map[ID]*Request
}

type requestState int
Expand All @@ -51,6 +59,10 @@ type Request struct {
WireRequest
}

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 {
Expand All @@ -64,23 +76,13 @@ func NewErrorf(code int64, format string, args ...interface{}) *Error {
// You must call Run for the connection to be active.
func NewConn(s Stream) *Conn {
conn := &Conn{
handlers: []Handler{defaultHandler{}},
stream: s,
pending: make(map[ID]chan *WireResponse),
handling: make(map[ID]*Request),
}
return conn
}

// AddHandler adds a new handler to the set the connection will invoke.
// Handlers are invoked in the reverse order of how they were added, this
// allows the most recent addition to be the first one to attempt to handle a
// message.
func (c *Conn) AddHandler(handler Handler) {
// prepend the new handlers so we use them first
c.handlers = append([]Handler{handler}, c.handlers...)
}

// Cancel cancels a pending Call on the server side.
// The call is identified by its id.
// JSON RPC 2 does not specify a cancel message, so cancellation support is not
Expand Down Expand Up @@ -111,8 +113,8 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (e
if err != nil {
return fmt.Errorf("marshalling notify request: %v", err)
}
for _, h := range c.handlers {
ctx = h.Request(ctx, c, Send, request)
if c.LegacyHooks != nil {
ctx = c.LegacyHooks.Request(ctx, c, Send, request)
}
ctx, done := event.StartSpan(ctx, request.Method,
tag.Method.Of(request.Method),
Expand Down Expand Up @@ -150,8 +152,8 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
if err != nil {
return fmt.Errorf("marshalling call request: %v", err)
}
for _, h := range c.handlers {
ctx = h.Request(ctx, c, Send, request)
if c.LegacyHooks != nil {
ctx = c.LegacyHooks.Request(ctx, c, Send, request)
}
ctx, done := event.StartSpan(ctx, request.Method,
tag.Method.Of(request.Method),
Expand Down Expand Up @@ -199,11 +201,8 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
return nil
case <-ctx.Done():
// Allow the handler to propagate the cancel.
cancelled := false
for _, h := range c.handlers {
if h.Cancel(ctx, c, id, cancelled) {
cancelled = true
}
if c.LegacyHooks != nil {
c.LegacyHooks.Cancel(ctx, c, id, false)
}
return ctx.Err()
}
Expand All @@ -217,39 +216,26 @@ func (r *Request) IsNotify() bool {
return r.ID == nil
}

// Parallel indicates that the system is now allowed to process other requests
// in parallel with this one.
// It is safe to call any number of times, but must only be called from the
// request handling go routine.
// It is implied by both reply and by the handler returning.
func (r *Request) Parallel() {
if r.state >= requestParallel {
return
}
r.state = requestParallel
close(r.nextRequest)
}

// Reply sends a reply to the given request.
// It is an error to call this if request was not a call.
// You must call this exactly once for any given request.
// It should only be called from the handler go routine.
// If err is set then result will be ignored.
// If the request has not yet dropped into parallel mode
// it will be before this function returns.
// This will mark the request as done, triggering any done
// handlers
func (r *Request) Reply(ctx context.Context, result interface{}, err error) error {
if r.state >= requestReplied {
return fmt.Errorf("reply invoked more than once")
}
if r.IsNotify() {
return fmt.Errorf("reply not invoked with a valid call: %v, %v", r.Method, r.Params)

if r.state < requestParallel {
r.state = requestParallel
close(r.nextRequest)
}
// reply ends the handling phase of a call, so if we are not yet
// parallel we should be now. The go routine is allowed to continue
// to do work after replying, which is why it is important to unlock
// the rpc system at this point.
r.Parallel()
r.state = requestReplied
recordStatus(ctx, nil)

if r.IsNotify() {
return nil
}

var raw *json.RawMessage
if err == nil {
Expand Down Expand Up @@ -281,7 +267,7 @@ func (r *Request) Reply(ctx context.Context, result interface{}, err error) erro
return nil
}

func (c *Conn) setHandling(r *Request, active bool) {
func setHandling(r *Request, active bool) {
if r.ID == nil {
return
}
Expand Down Expand Up @@ -309,7 +295,8 @@ type combined struct {
// caused the termination.
// It must be called exactly once for each Conn.
// It returns only when the reader is closed or there is an error in the stream.
func (c *Conn) Run(runCtx context.Context) error {
func (c *Conn) Run(runCtx context.Context, handler Handler) error {
handler = MustReply(handler)
// we need to make the next request "lock" in an unlocked state to allow
// the first incoming request to proceed. All later requests are unlocked
// by the preceding request going to parallel mode.
Expand Down Expand Up @@ -348,8 +335,8 @@ func (c *Conn) Run(runCtx context.Context) error {
ID: msg.ID,
},
}
for _, h := range c.handlers {
reqCtx = h.Request(reqCtx, c, Receive, &req.WireRequest)
if c.LegacyHooks != nil {
reqCtx = c.LegacyHooks.Request(reqCtx, c, Receive, &req.WireRequest)
}
reqCtx, done := event.StartSpan(reqCtx, req.WireRequest.Method,
tag.Method.Of(req.WireRequest.Method),
Expand All @@ -359,28 +346,27 @@ func (c *Conn) Run(runCtx context.Context) error {
event.Record(reqCtx,
tag.Started.Of(1),
tag.SentBytes.Of(n))
c.setHandling(req, true)
setHandling(req, true)
_, queueDone := event.StartSpan(reqCtx, "queued")
go func() {
<-thisRequest
queueDone()
req.state = requestSerial
defer func() {
c.setHandling(req, false)
if !req.IsNotify() && req.state < requestReplied {
req.Reply(reqCtx, nil, NewErrorf(CodeInternalError, "method %q did not reply", req.Method))
}
req.Parallel()
recordStatus(reqCtx, nil)
setHandling(req, false)
done()
cancelReq()
}()
delivered := false
for _, h := range c.handlers {
if h.Deliver(reqCtx, req, delivered) {
delivered = true
if c.LegacyHooks != nil {
if c.LegacyHooks.Deliver(reqCtx, req, false) {
return
}
}
err := handler(reqCtx, req)
if err != nil {
// delivery failed, not much we can do
event.Error(reqCtx, "jsonrpc2 message delivery failed", err)
}
}()
case msg.ID != nil:
// If method is not set, this should be a response, in which case we must
Expand Down
7 changes: 1 addition & 6 deletions cmd/govim/internal/golang_org_x_tools/jsonrpc2/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package jsonrpc2

import (
"context"
"errors"
"fmt"
"log"
"net"
Expand Down Expand Up @@ -39,8 +38,7 @@ func (f ServerFunc) ServeStream(ctx context.Context, s Stream) error {
func HandlerServer(h Handler) StreamServer {
return ServerFunc(func(ctx context.Context, s Stream) error {
conn := NewConn(s)
conn.AddHandler(h)
return conn.Run(ctx)
return conn.Run(ctx, h)
})
}

Expand All @@ -59,9 +57,6 @@ func ListenAndServe(ctx context.Context, network, addr string, server StreamServ
return Serve(ctx, ln, server, idleTimeout)
}

// ErrIdleTimeout is returned when serving timed out waiting for new connections.
var ErrIdleTimeout = errors.New("timed out waiting for new connections")

// Serve accepts incoming connections from the network, and handles them using
// the provided server. If idleTimeout is non-zero, ListenAndServe exits after
// there are no clients for this duration, otherwise it exits only on error.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ func (s *TCPServer) Connect(ctx context.Context) *jsonrpc2.Conn {
s.cls.add(func() {
netConn.Close()
})
conn := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn, netConn))
go conn.Run(ctx)
return conn
return jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn, netConn))
}

// Close closes all connected pipes.
Expand Down Expand Up @@ -92,9 +90,7 @@ func (s *PipeServer) Connect(ctx context.Context) *jsonrpc2.Conn {
go s.server.ServeStream(ctx, serverStream)

clientStream := jsonrpc2.NewStream(cReader, sWriter)
clientConn := jsonrpc2.NewConn(clientStream)
go clientConn.Run(ctx)
return clientConn
return jsonrpc2.NewConn(clientStream)
}

// Close closes all connected pipes.
Expand Down
4 changes: 0 additions & 4 deletions cmd/govim/internal/golang_org_x_tools/jsonrpc2/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
Expand All @@ -29,9 +28,6 @@ type Stream interface {
Write(context.Context, []byte) (int64, error)
}

// ErrDisconnected signals that the stream or connection exited normally.
var ErrDisconnected = errors.New("disconnected")

// NewStream returns a Stream built on top of an io.Reader and io.Writer
// The messages are sent with no wrapping, and rely on json decode consistency
// to determine message boundaries.
Expand Down
5 changes: 2 additions & 3 deletions cmd/govim/internal/golang_org_x_tools/lsp/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,9 @@ func (app *Application) connectRemote(ctx context.Context, remote string) (*conn
stream := jsonrpc2.NewHeaderStream(conn, conn)
cc := jsonrpc2.NewConn(stream)
connection.Server = protocol.ServerDispatcher(cc)
cc.AddHandler(protocol.ClientHandler(connection.Client))
cc.AddHandler(protocol.Canceller{})
cc.LegacyHooks = protocol.Canceller{}
ctx = protocol.WithClient(ctx, connection.Client)
go cc.Run(ctx)
go cc.Run(ctx, protocol.ClientHandler(connection.Client, jsonrpc2.MethodNotFound))
return connection, connection.initialize(ctx, app.options)
}

Expand Down
Loading

0 comments on commit 281246e

Please sign in to comment.