golang.org/x/tools/gopls@v0.15.3/internal/lsprpc/export_test.go (about)

     1  // Copyright 2024 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.
     4  
     5  package lsprpc
     6  
     7  // This file defines things (and opens backdoors) needed only by tests.
     8  
     9  import (
    10  	"context"
    11  	"encoding/json"
    12  	"fmt"
    13  
    14  	"golang.org/x/tools/gopls/internal/protocol"
    15  	"golang.org/x/tools/internal/event"
    16  	jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2"
    17  	"golang.org/x/tools/internal/xcontext"
    18  )
    19  
    20  const HandshakeMethod = handshakeMethod
    21  
    22  // A ServerFunc is used to construct an LSP server for a given client.
    23  type ServerFunc func(context.Context, protocol.ClientCloser) protocol.Server
    24  
    25  type Canceler struct {
    26  	Conn *jsonrpc2_v2.Connection
    27  }
    28  
    29  func (c *Canceler) Preempt(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) {
    30  	if req.Method != "$/cancelRequest" {
    31  		return nil, jsonrpc2_v2.ErrNotHandled
    32  	}
    33  	var params protocol.CancelParams
    34  	if err := json.Unmarshal(req.Params, &params); err != nil {
    35  		return nil, fmt.Errorf("%w: %v", jsonrpc2_v2.ErrParse, err)
    36  	}
    37  	var id jsonrpc2_v2.ID
    38  	switch raw := params.ID.(type) {
    39  	case float64:
    40  		id = jsonrpc2_v2.Int64ID(int64(raw))
    41  	case string:
    42  		id = jsonrpc2_v2.StringID(raw)
    43  	default:
    44  		return nil, fmt.Errorf("%w: invalid ID type %T", jsonrpc2_v2.ErrParse, params.ID)
    45  	}
    46  	c.Conn.Cancel(id)
    47  	return nil, nil
    48  }
    49  
    50  type ForwardBinder struct {
    51  	dialer jsonrpc2_v2.Dialer
    52  	onBind func(*jsonrpc2_v2.Connection)
    53  }
    54  
    55  func NewForwardBinder(dialer jsonrpc2_v2.Dialer) *ForwardBinder {
    56  	return &ForwardBinder{
    57  		dialer: dialer,
    58  	}
    59  }
    60  
    61  func (b *ForwardBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) (opts jsonrpc2_v2.ConnectionOptions) {
    62  	client := protocol.ClientDispatcherV2(conn)
    63  	clientBinder := NewClientBinder(func(context.Context, protocol.Server) protocol.Client { return client })
    64  
    65  	serverConn, err := jsonrpc2_v2.Dial(context.Background(), b.dialer, clientBinder)
    66  	if err != nil {
    67  		return jsonrpc2_v2.ConnectionOptions{
    68  			Handler: jsonrpc2_v2.HandlerFunc(func(context.Context, *jsonrpc2_v2.Request) (interface{}, error) {
    69  				return nil, fmt.Errorf("%w: %v", jsonrpc2_v2.ErrInternal, err)
    70  			}),
    71  		}
    72  	}
    73  
    74  	if b.onBind != nil {
    75  		b.onBind(serverConn)
    76  	}
    77  	server := protocol.ServerDispatcherV2(serverConn)
    78  	preempter := &Canceler{
    79  		Conn: conn,
    80  	}
    81  	detached := xcontext.Detach(ctx)
    82  	go func() {
    83  		conn.Wait()
    84  		if err := serverConn.Close(); err != nil {
    85  			event.Log(detached, fmt.Sprintf("closing remote connection: %v", err))
    86  		}
    87  	}()
    88  	return jsonrpc2_v2.ConnectionOptions{
    89  		Handler:   protocol.ServerHandlerV2(server),
    90  		Preempter: preempter,
    91  	}
    92  }
    93  
    94  func NewClientBinder(newClient ClientFunc) *clientBinder {
    95  	return &clientBinder{newClient}
    96  }
    97  
    98  // A ClientFunc is used to construct an LSP client for a given server.
    99  type ClientFunc func(context.Context, protocol.Server) protocol.Client
   100  
   101  // clientBinder binds an LSP client to an incoming connection.
   102  type clientBinder struct {
   103  	newClient ClientFunc
   104  }
   105  
   106  func (b *clientBinder) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions {
   107  	server := protocol.ServerDispatcherV2(conn)
   108  	client := b.newClient(ctx, server)
   109  	return jsonrpc2_v2.ConnectionOptions{
   110  		Handler: protocol.ClientHandlerV2(client),
   111  	}
   112  }
   113  
   114  // HandlerMiddleware is a middleware that only modifies the jsonrpc2 handler.
   115  type HandlerMiddleware func(jsonrpc2_v2.Handler) jsonrpc2_v2.Handler
   116  
   117  // BindHandler transforms a HandlerMiddleware into a Middleware.
   118  func BindHandler(hmw HandlerMiddleware) Middleware {
   119  	return Middleware(func(binder jsonrpc2_v2.Binder) jsonrpc2_v2.Binder {
   120  		return BinderFunc(func(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions {
   121  			opts := binder.Bind(ctx, conn)
   122  			opts.Handler = hmw(opts.Handler)
   123  			return opts
   124  		})
   125  	})
   126  }
   127  
   128  // The BinderFunc type adapts a bind function to implement the jsonrpc2.Binder
   129  // interface.
   130  type BinderFunc func(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions
   131  
   132  func (f BinderFunc) Bind(ctx context.Context, conn *jsonrpc2_v2.Connection) jsonrpc2_v2.ConnectionOptions {
   133  	return f(ctx, conn)
   134  }
   135  
   136  // Middleware defines a transformation of jsonrpc2 Binders, that may be
   137  // composed to build jsonrpc2 servers.
   138  type Middleware func(jsonrpc2_v2.Binder) jsonrpc2_v2.Binder
   139  
   140  var GetGoEnv = getGoEnv
   141  
   142  type StreamServer = streamServer