1
0
Fork 0
mirror of https://github.com/sourcegraph/jsonrpc2.git synced 2026-06-16 20:20:03 +02:00

Compare commits

..

No commits in common. "master" and "v0.2.1" have entirely different histories.

5 changed files with 27 additions and 86 deletions

View file

@ -18,9 +18,9 @@ jobs:
name: Go ${{ matrix.go }} name: Go ${{ matrix.go }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v5
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
id: go id: go

View file

@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: sourcegraph/scip-go container: sourcegraph/scip-go
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Get src-cli - name: Get src-cli
run: curl -L https://sourcegraph.com/.api/src-cli/src_linux_amd64 -o /usr/local/bin/src; run: curl -L https://sourcegraph.com/.api/src-cli/src_linux_amd64 -o /usr/local/bin/src;
chmod +x /usr/local/bin/src chmod +x /usr/local/bin/src

18
conn.go
View file

@ -27,7 +27,6 @@ type Conn struct {
sending sync.Mutex sending sync.Mutex
cancelCtx context.CancelFunc
disconnect chan struct{} disconnect chan struct{}
logger Logger logger Logger
@ -44,19 +43,13 @@ var _ JSONRPC2 = (*Conn)(nil)
// JSON-RPC protocol is symmetric, so a Conn runs on both ends of a // JSON-RPC protocol is symmetric, so a Conn runs on both ends of a
// client-server connection. // client-server connection.
// //
// NewConn consumes stream, so you should call Close on the returned // NewClient consumes conn, so you should call Close on the returned
// Conn not on the given stream or its underlying connection. // client not on the given conn.
//
// Conn is closed when the given context's Done channel is closed.
func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOpt) *Conn { func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOpt) *Conn {
ctx, cancel := context.WithCancel(ctx)
c := &Conn{ c := &Conn{
stream: stream, stream: stream,
h: h, h: h,
pending: map[ID]*call{}, pending: map[ID]*call{},
cancelCtx: cancel,
disconnect: make(chan struct{}), disconnect: make(chan struct{}),
logger: log.New(os.Stderr, "", log.LstdFlags), logger: log.New(os.Stderr, "", log.LstdFlags),
} }
@ -67,12 +60,6 @@ func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOp
opt(c) opt(c)
} }
go c.readMessages(ctx) go c.readMessages(ctx)
go func() {
<-ctx.Done()
c.close(nil)
}()
return c return c
} }
@ -195,7 +182,6 @@ func (c *Conn) close(cause error) error {
} }
close(c.disconnect) close(c.disconnect)
c.cancelCtx()
c.closed = true c.closed = true
return c.stream.Close() return c.stream.Close()
} }

View file

@ -14,58 +14,6 @@ import (
"github.com/sourcegraph/jsonrpc2" "github.com/sourcegraph/jsonrpc2"
) )
func TestConn(t *testing.T) {
t.Run("closes when context is done", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
connA, connB := Pipe(ctx, noopHandler{}, noopHandler{})
defer connA.Close()
defer connB.Close()
cancel()
<-connA.DisconnectNotify()
got := connA.Close()
want := jsonrpc2.ErrClosed
if got != want {
t.Fatalf("got %v, want %v", got, want)
}
})
t.Run("cancels context when closed", func(t *testing.T) {
ctxCanceled := make(chan struct{})
handler := handlerFunc(func(ctx context.Context, c *jsonrpc2.Conn, r *jsonrpc2.Request) {
// Block until the context is canceled.
<-ctx.Done()
close(ctxCanceled)
})
connA, connB := Pipe(context.Background(), noopHandler{}, jsonrpc2.AsyncHandler(handler))
defer connA.Close()
defer connB.Close()
// Send a notification from connA to connB to trigger connB's handler
// function.
if err := connA.Notify(context.Background(), "foo", nil, nil); err != nil {
t.Fatal(err)
}
// Disconnect connA from connB.
if err := connA.Close(); err != nil {
t.Fatal(err)
}
select {
case <-ctxCanceled:
// Test passed, the handler's context was canceled.
case <-time.After(time.Second):
t.Fatal("context not canceled")
}
})
}
var paramsTests = []struct { var paramsTests = []struct {
sendParams interface{} sendParams interface{}
wantParams *json.RawMessage wantParams *json.RawMessage
@ -250,12 +198,12 @@ func testParams(t *testing.T, want *json.RawMessage, fn func(c *jsonrpc2.Conn) e
wg.Done() wg.Done()
}) })
connA, connB := Pipe(context.Background(), noopHandler{}, handler) client, server := newClientServer(handler)
defer connA.Close() defer client.Close()
defer connB.Close() defer server.Close()
wg.Add(1) wg.Add(1)
if err := fn(connA); err != nil { if err := fn(client); err != nil {
t.Error(err) t.Error(err)
} }
wg.Wait() wg.Wait()
@ -294,11 +242,18 @@ func assertRawJSONMessage(t *testing.T, got *json.RawMessage, want *json.RawMess
} }
} }
// Pipe returns two jsonrpc2.Conn, connected via a synchronous, in-memory, full func newClientServer(handler jsonrpc2.Handler) (client *jsonrpc2.Conn, server *jsonrpc2.Conn) {
// duplex network connection. ctx := context.Background()
func Pipe(ctx context.Context, handlerA, handlerB jsonrpc2.Handler) (connA *jsonrpc2.Conn, connB *jsonrpc2.Conn) { connA, connB := net.Pipe()
a, b := net.Pipe() client = jsonrpc2.NewConn(
connA = jsonrpc2.NewConn(ctx, jsonrpc2.NewPlainObjectStream(a), handlerA) ctx,
connB = jsonrpc2.NewConn(ctx, jsonrpc2.NewPlainObjectStream(b), handlerB) jsonrpc2.NewPlainObjectStream(connA),
return connA, connB noopHandler{},
)
server = jsonrpc2.NewConn(
ctx,
jsonrpc2.NewPlainObjectStream(connB),
handler,
)
return client, server
} }

View file

@ -59,10 +59,10 @@ const (
// Handler handles JSON-RPC requests and notifications. // Handler handles JSON-RPC requests and notifications.
type Handler interface { type Handler interface {
// Handle is called to handle a request. No other requests are handled until // Handle is called to handle a request. No other requests are handled
// it returns. If you do not require strict ordering behavior of received // until it returns. If you do not require strict ordering behavior
// RPCs, it is suggested to wrap your handler in AsyncHandler. The context // of received RPCs, it is suggested to wrap your handler in
// is automatically canceled when the connection closes. // AsyncHandler.
Handle(context.Context, *Conn, *Request) Handle(context.Context, *Conn, *Request)
} }