internal/jsonrpc2_v2: an updated jsonrpc2 library
Change-Id: I609173baa6842d33068a7e9596d54f03d89c5401 Reviewed-on: https://go-review.googlesource.com/c/tools/+/292169 Run-TryBot: Ian Cottrell <iancottrell@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Ian Cottrell <iancottrell@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
8d98c809a2
commit
cf8963447b
1 changed files with 1992 additions and 0 deletions
129
internal/jsonrpc2/net.go
Normal file
129
internal/jsonrpc2/net.go
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2018 The Go MCP SDK Authors. All rights reserved.
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package jsonrpc2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This file contains implementations of the transport primitives that use the standard network
|
||||
// package.
|
||||
|
||||
// NetListenOptions is the optional arguments to the NetListen function.
|
||||
type NetListenOptions struct {
|
||||
NetListenConfig net.ListenConfig
|
||||
NetDialer net.Dialer
|
||||
}
|
||||
|
||||
// NetListener returns a new Listener that listents on a socket using the net package.
|
||||
func NetListener(ctx context.Context, network, address string, options NetListenOptions) (Listener, error) {
|
||||
ln, err := options.NetListenConfig.Listen(ctx, network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &netListener{net: ln}, nil
|
||||
}
|
||||
|
||||
// netListener is the implementation of Listener for connections made using the net package.
|
||||
type netListener struct {
|
||||
net net.Listener
|
||||
}
|
||||
|
||||
// Accept blocks waiting for an incoming connection to the listener.
|
||||
func (l *netListener) Accept(ctx context.Context) (io.ReadWriteCloser, error) {
|
||||
return l.net.Accept()
|
||||
}
|
||||
|
||||
// Close will cause the listener to stop listening. It will not close any connections that have
|
||||
// already been accepted.
|
||||
func (l *netListener) Close() error {
|
||||
addr := l.net.Addr()
|
||||
err := l.net.Close()
|
||||
if addr.Network() == "unix" {
|
||||
rerr := os.Remove(addr.String())
|
||||
if rerr != nil && err == nil {
|
||||
err = rerr
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Dialer returns a dialer that can be used to connect to the listener.
|
||||
func (l *netListener) Dialer() Dialer {
|
||||
return NetDialer(l.net.Addr().Network(), l.net.Addr().String(), net.Dialer{
|
||||
Timeout: 5 * time.Second,
|
||||
})
|
||||
}
|
||||
|
||||
// NetDialer returns a Dialer using the supplied standard network dialer.
|
||||
func NetDialer(network, address string, nd net.Dialer) Dialer {
|
||||
return &netDialer{
|
||||
network: network,
|
||||
address: address,
|
||||
dialer: nd,
|
||||
}
|
||||
}
|
||||
|
||||
type netDialer struct {
|
||||
network string
|
||||
address string
|
||||
dialer net.Dialer
|
||||
}
|
||||
|
||||
func (n *netDialer) Dial(ctx context.Context) (io.ReadWriteCloser, error) {
|
||||
return n.dialer.DialContext(ctx, n.network, n.address)
|
||||
}
|
||||
|
||||
// NetPipe returns a new Listener that listens using net.Pipe.
|
||||
// It is only possibly to connect to it using the Dialier returned by the
|
||||
// Dialer method, each call to that method will generate a new pipe the other
|
||||
// side of which will be returnd from the Accept call.
|
||||
func NetPipe(ctx context.Context) (Listener, error) {
|
||||
return &netPiper{
|
||||
done: make(chan struct{}),
|
||||
dialed: make(chan io.ReadWriteCloser),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// netPiper is the implementation of Listener build on top of net.Pipes.
|
||||
type netPiper struct {
|
||||
done chan struct{}
|
||||
dialed chan io.ReadWriteCloser
|
||||
}
|
||||
|
||||
// Accept blocks waiting for an incoming connection to the listener.
|
||||
func (l *netPiper) Accept(ctx context.Context) (io.ReadWriteCloser, error) {
|
||||
// block until we have a listener, or are closed or cancelled
|
||||
select {
|
||||
case rwc := <-l.dialed:
|
||||
return rwc, nil
|
||||
case <-l.done:
|
||||
return nil, io.EOF
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// Close will cause the listener to stop listening. It will not close any connections that have
|
||||
// already been accepted.
|
||||
func (l *netPiper) Close() error {
|
||||
// unblock any accept calls that are pending
|
||||
close(l.done)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *netPiper) Dialer() Dialer {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *netPiper) Dial(ctx context.Context) (io.ReadWriteCloser, error) {
|
||||
client, server := net.Pipe()
|
||||
l.dialed <- server
|
||||
return client, nil
|
||||
}
|
||||
Loading…
Reference in a new issue