Skip to content

Commit 2d2670a

Browse files
authored
Merge pull request ethereum#192 from OffchainLabs/rpc-client-hooks
Add request and response hooks to rpc.Client
2 parents 55ba905 + c90128a commit 2d2670a

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

rpc/client.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ type BatchElem struct {
7474

7575
// Client represents a connection to an RPC server.
7676
type Client struct {
77+
requestHook RequestHook
78+
7779
idgen func() ID // for subscriptions
7880
isHTTP bool // connection type: http, ws or ipc
7981
services *serviceRegistry
@@ -300,25 +302,32 @@ func (c *Client) CallContext(ctx context.Context, result interface{}, method str
300302
}
301303
op := &requestOp{ids: []json.RawMessage{msg.ID}, resp: make(chan *jsonrpcMessage, 1)}
302304

305+
resultHook := c.onRequest(msg)
303306
if c.isHTTP {
304307
err = c.sendHTTP(ctx, op, msg)
305308
} else {
306309
err = c.send(ctx, op, msg)
307310
}
308311
if err != nil {
312+
resultHook.OnResult(nil, err)
309313
return err
310314
}
311315

312316
// dispatch has accepted the request and will close the channel when it quits.
313317
switch resp, err := op.wait(ctx, c); {
314318
case err != nil:
319+
resultHook.OnResult(resp, err)
315320
return err
316321
case resp.Error != nil:
322+
resultHook.OnResult(resp, resp.Error)
317323
return resp.Error
318324
case len(resp.Result) == 0:
325+
resultHook.OnResult(resp, ErrNoResult)
319326
return ErrNoResult
320327
default:
321-
return json.Unmarshal(resp.Result, &result)
328+
err := json.Unmarshal(resp.Result, &result)
329+
resultHook.OnResult(resp, err)
330+
return err
322331
}
323332
}
324333

@@ -362,6 +371,12 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
362371
byID[string(msg.ID)] = i
363372
}
364373

374+
resultHooks := make([]ResultHook, len(msgs))
375+
responsesForHooks := make([]interface{}, len(msgs))
376+
for i, msg := range msgs {
377+
resultHooks[i] = c.onRequest(msg)
378+
}
379+
365380
var err error
366381
if c.isHTTP {
367382
err = c.sendBatchHTTP(ctx, op, msgs)
@@ -379,7 +394,9 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
379394
// Find the element corresponding to this response.
380395
// The element is guaranteed to be present because dispatch
381396
// only sends valid IDs to our channel.
382-
elem := &b[byID[string(resp.ID)]]
397+
idx := byID[string(resp.ID)]
398+
responsesForHooks[idx] = resp
399+
elem := &b[idx]
383400
if resp.Error != nil {
384401
elem.Error = resp.Error
385402
continue
@@ -390,6 +407,9 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
390407
}
391408
elem.Error = json.Unmarshal(resp.Result, elem.Result)
392409
}
410+
for i, hook := range resultHooks {
411+
hook.OnResult(responsesForHooks[i], err)
412+
}
393413
return err
394414
}
395415

rpc/client_arbitrum.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// Copyright 2022 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
117
package rpc
218

319
import (
@@ -34,3 +50,37 @@ func DialTransport(ctx context.Context, rawUrl string, transport *http.Transport
3450
}
3551
return rpcClient, nil
3652
}
53+
54+
func DialContextWithRequestHook(ctx context.Context, url string, hook RequestHook) (*Client, error) {
55+
client, err := DialContext(ctx, url)
56+
if err != nil {
57+
return nil, err
58+
}
59+
client.requestHook = hook
60+
return client, nil
61+
}
62+
63+
type RequestHook interface {
64+
OnRequest(request interface{}) ResultHook
65+
}
66+
67+
type ResultHook interface {
68+
OnResult(response interface{}, err error)
69+
}
70+
71+
type noopResultHook struct{}
72+
73+
func (h noopResultHook) OnResult(interface{}, error) {
74+
}
75+
76+
func (c *Client) onRequest(request interface{}) ResultHook {
77+
hooks := c.requestHook
78+
var respHooks ResultHook
79+
if hooks != nil {
80+
respHooks = hooks.OnRequest(request)
81+
}
82+
if respHooks == nil {
83+
respHooks = noopResultHook{}
84+
}
85+
return respHooks
86+
}

0 commit comments

Comments
 (0)