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
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
2
.github/workflows/scip.yml
vendored
2
.github/workflows/scip.yml
vendored
|
|
@ -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
18
conn.go
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
81
conn_test.go
81
conn_test.go
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue