
在internal/lsprpc/lsprpc.go中有Forwarder的实现
func NewForwarder(rawAddr string, argFunc func(network, address string) []string) (jsonrpc2.StreamServer, error) {
dialer, err := newAutoDialer(rawAddr, argFunc)
if err != nil {
return nil, err
}
fwd := &forwarder{
dialer: dialer,
}
return fwd, nil
}它返回一个实现了ServeStream方法的接口
type StreamServer interface {
ServeStream(context.Context, Conn) error
}具体实现如下,先建立client连接用于转发请求,然后,启动server来提供服务,最后启动一个协程,用于请求的转发工作,转发工作有两个协程,分别用于客户端侧转发和服务端侧转发
type forwarder struct {
dialer *autoDialer
mu sync.Mutex
// Hold on to the server connection so that we can redo the handshake if any
// information changes.
serverConn jsonrpc2.Conn
serverID string
}func (f *forwarder) ServeStream(ctx context.Context, clientConn jsonrpc2.Conn) error {
client := protocol.ClientDispatcher(clientConn)
netConn, err := f.dialer.dialNet(ctx)
serverConn := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn))
server := protocol.ServerDispatcher(serverConn)
serverConn.Go(ctx,
protocol.Handlers(
protocol.ClientHandler(client,
jsonrpc2.MethodNotFound)))
f.handshake(ctx)
clientConn.Go(ctx,
protocol.Handlers(
f.handler(
protocol.ServerHandler(server,
jsonrpc2.MethodNotFound))))在进行转发之前还初始化了一个autoDialer,实现位于internal/lsprpc/dialer.go
func newAutoDialer(rawAddr string, argFunc func(network, addr string) []string) (*autoDialer, error) {
d := autoDialer{
argFunc: argFunc,
}
bin, err := os.Executable()
d.network, d.addr = autoNetworkAddress(bin, d.addr)其中
autoNetworkAddress = autoNetworkAddressDefaultfunc autoNetworkAddressDefault(goplsPath, id string) (network string, address string) {
if id != "" {
panic("identified remotes are not supported on windows")
}
return "tcp", "localhost:37374"
}这里可以看下gopls默认服务端口是37374
在internal/jsonrpc2/conn.go中定义了Conn接口,转发的时候用到了其中的Go方法。
type Conn interface {
// Call invokes the target method and waits for a response.
// The params will be marshaled to JSON before sending over the wire, and will
// be handed to the method invoked.
// The response will be unmarshaled from JSON into the result.
// The id returned will be unique from this connection, and can be used for
// logging or tracking.
Call(ctx context.Context, method string, params, result interface{}) (ID, error)
// Notify invokes the target method but does not wait for a response.
// The params will be marshaled to JSON before sending over the wire, and will
// be handed to the method invoked.
Notify(ctx context.Context, method string, params interface{}) error
// Go starts a goroutine to handle the connection.
// It must be called exactly once for each Conn.
// It returns immediately.
// You must block on Done() to wait for the connection to shut down.
// This is a temporary measure, this should be started automatically in the
// future.
Go(ctx context.Context, handler Handler)
// Close closes the connection and it's underlying stream.
// It does not wait for the close to complete, use the Done() channel for
// that.
Close() error
// Done returns a channel that will be closed when the processing goroutine
// has terminated, which will happen if Close() is called or an underlying
// stream is closed.
Done() <-chan struct{}
// Err returns an error if there was one from within the processing goroutine.
// If err returns non nil, the connection will be already closed or closing.
Err() error
}protocol.Handlers为转发过程增加了一系列middleware,同样作用的还有f.handler,它在middleware中实现了初始化和工作区间执行命令的功能。
func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler {
return CancelHandler(
jsonrpc2.AsyncHandler(
jsonrpc2.MustReplyHandler(handler)))
}func (f *forwarder) handler(handler jsonrpc2.Handler) jsonrpc2.Handler {
return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
// Intercept certain messages to add special handling.
switch r.Method() {
case "initialize":
if newr, err := addGoEnvToInitializeRequest(ctx, r); err == nil {
r = newr
} else {
log.Printf("unable to add local env to initialize request: %v", err)
}
case "workspace/executeCommand":ServerHandler和 ClientHandler分别提供了服务端和客户端的middleware
func ServerHandler(server Server, handler jsonrpc2.Handler) jsonrpc2.Handler {func ClientHandler(client Client, handler jsonrpc2.Handler) jsonrpc2.Handler {至此转发代理模式的server初始化完毕。
本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!