mirror of
https://github.com/sourcegraph/jsonrpc2.git
synced 2026-06-16 04:04:56 +02:00
Break the Call method into a dispatcher and waiter
Before, the Call method dispatched the JSON-RPC request and waited until completion of the request before returning. This made it difficult to release any locks that need to be released upon dispatch. Now, the Call method is broken into a DispatchCall and Wait pair. DispatchCall returns a proxy to the internal call object as soon as the request is dispatched. When appropriate, the caller can invoke the Wait method on this proxy to block until the result is ready. The original Call method is not changed, but now implemented by these primitives.
This commit is contained in:
parent
15c2290dcb
commit
682876aa75
1 changed files with 33 additions and 7 deletions
40
jsonrpc2.go
40
jsonrpc2.go
|
|
@ -416,24 +416,50 @@ func (c *Conn) send(_ context.Context, m *anyMessage, wait bool) (cc *call, err
|
|||
// its result is stored in result (a pointer to a value that can be
|
||||
// JSON-unmarshaled into); otherwise, a non-nil error is returned.
|
||||
func (c *Conn) Call(ctx context.Context, method string, params, result interface{}, opts ...CallOption) error {
|
||||
call, err := c.DispatchCall(ctx, method, params, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return call.Wait(ctx, result)
|
||||
}
|
||||
|
||||
// DispatchCall dispatches a JSON-RPC call using the specified method
|
||||
// and params, and returns a call proxy or an error. Call Wait()
|
||||
// on the returned proxy to receive the response. Only use this
|
||||
// function if you need to do work after dispatching the request,
|
||||
// otherwise use Call.
|
||||
func (c *Conn) DispatchCall(ctx context.Context, method string, params interface{}, opts ...CallOption) (Waiter, error) {
|
||||
req := &Request{Method: method}
|
||||
if err := req.SetParams(params); err != nil {
|
||||
return err
|
||||
return Waiter{}, err
|
||||
}
|
||||
for _, opt := range opts {
|
||||
if opt == nil {
|
||||
continue
|
||||
}
|
||||
if err := opt.apply(req); err != nil {
|
||||
return err
|
||||
return Waiter{}, err
|
||||
}
|
||||
}
|
||||
call, err := c.send(ctx, &anyMessage{request: req}, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return Waiter{}, err
|
||||
}
|
||||
return Waiter{call: call}, nil
|
||||
}
|
||||
|
||||
// Waiter proxies an ongoing JSON-RPC call.
|
||||
type Waiter struct {
|
||||
*call
|
||||
}
|
||||
|
||||
// Wait for the result of an ongoing JSON-RPC call. If the response
|
||||
// is successful, its result is stored in result (a pointer to a
|
||||
// value that can be JSON-unmarshaled into); otherwise, a non-nil
|
||||
// error is returned.
|
||||
func (w Waiter) Wait(ctx context.Context, result interface{}) error {
|
||||
select {
|
||||
case err, ok := <-call.done:
|
||||
case err, ok := <-w.call.done:
|
||||
if !ok {
|
||||
err = ErrClosed
|
||||
}
|
||||
|
|
@ -441,10 +467,10 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
|
|||
return err
|
||||
}
|
||||
if result != nil {
|
||||
if call.response.Result == nil {
|
||||
call.response.Result = &jsonNull
|
||||
if w.call.response.Result == nil {
|
||||
w.call.response.Result = &jsonNull
|
||||
}
|
||||
if err := json.Unmarshal(*call.response.Result, result); err != nil {
|
||||
if err := json.Unmarshal(*w.call.response.Result, result); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue