rpc: implement full bi-directional communication (#18471)
New APIs added: client.RegisterName(namespace, service) // makes service available to server client.Notify(ctx, method, args...) // sends a notification ClientFromContext(ctx) // to get a client in handler method This is essentially a rewrite of the server-side code. JSON-RPC processing code is now the same on both server and client side. Many minor issues were fixed in the process and there is a new test suite for JSON-RPC spec compliance (and non-compliance in some cases). List of behavior changes: - Method handlers are now called with a per-request context instead of a per-connection context. The context is canceled right after the method returns. - Subscription error channels are always closed when the connection ends. There is no need to also wait on the Notifier's Closed channel to detect whether the subscription has ended. - Client now omits "params" instead of sending "params": null when there are no arguments to a call. The previous behavior was not compliant with the spec. The server still accepts "params": null. - Floating point numbers are allowed as "id". The spec doesn't allow them, but we handle request "id" as json.RawMessage and guarantee that the same number will be sent back. - Logging is improved significantly. There is now a message at DEBUG level for each RPC call served.
This commit is contained in:
82
rpc/doc.go
82
rpc/doc.go
@ -15,43 +15,49 @@
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
Package rpc provides access to the exported methods of an object across a network
|
||||
or other I/O connection. After creating a server instance objects can be registered,
|
||||
making it visible from the outside. Exported methods that follow specific
|
||||
conventions can be called remotely. It also has support for the publish/subscribe
|
||||
pattern.
|
||||
|
||||
Package rpc implements bi-directional JSON-RPC 2.0 on multiple transports.
|
||||
|
||||
It provides access to the exported methods of an object across a network or other I/O
|
||||
connection. After creating a server or client instance, objects can be registered to make
|
||||
them visible as 'services'. Exported methods that follow specific conventions can be
|
||||
called remotely. It also has support for the publish/subscribe pattern.
|
||||
|
||||
RPC Methods
|
||||
|
||||
Methods that satisfy the following criteria are made available for remote access:
|
||||
- object must be exported
|
||||
|
||||
- method must be exported
|
||||
- method returns 0, 1 (response or error) or 2 (response and error) values
|
||||
- method argument(s) must be exported or builtin types
|
||||
- method returned value(s) must be exported or builtin types
|
||||
|
||||
An example method:
|
||||
|
||||
func (s *CalcService) Add(a, b int) (int, error)
|
||||
|
||||
When the returned error isn't nil the returned integer is ignored and the error is
|
||||
sent back to the client. Otherwise the returned integer is sent back to the client.
|
||||
When the returned error isn't nil the returned integer is ignored and the error is sent
|
||||
back to the client. Otherwise the returned integer is sent back to the client.
|
||||
|
||||
Optional arguments are supported by accepting pointer values as arguments. E.g.
|
||||
if we want to do the addition in an optional finite field we can accept a mod
|
||||
argument as pointer value.
|
||||
Optional arguments are supported by accepting pointer values as arguments. E.g. if we want
|
||||
to do the addition in an optional finite field we can accept a mod argument as pointer
|
||||
value.
|
||||
|
||||
func (s *CalService) Add(a, b int, mod *int) (int, error)
|
||||
func (s *CalcService) Add(a, b int, mod *int) (int, error)
|
||||
|
||||
This RPC method can be called with 2 integers and a null value as third argument.
|
||||
In that case the mod argument will be nil. Or it can be called with 3 integers,
|
||||
in that case mod will be pointing to the given third argument. Since the optional
|
||||
argument is the last argument the RPC package will also accept 2 integers as
|
||||
arguments. It will pass the mod argument as nil to the RPC method.
|
||||
This RPC method can be called with 2 integers and a null value as third argument. In that
|
||||
case the mod argument will be nil. Or it can be called with 3 integers, in that case mod
|
||||
will be pointing to the given third argument. Since the optional argument is the last
|
||||
argument the RPC package will also accept 2 integers as arguments. It will pass the mod
|
||||
argument as nil to the RPC method.
|
||||
|
||||
The server offers the ServeCodec method which accepts a ServerCodec instance. It will
|
||||
read requests from the codec, process the request and sends the response back to the
|
||||
client using the codec. The server can execute requests concurrently. Responses
|
||||
can be sent back to the client out of order.
|
||||
The server offers the ServeCodec method which accepts a ServerCodec instance. It will read
|
||||
requests from the codec, process the request and sends the response back to the client
|
||||
using the codec. The server can execute requests concurrently. Responses can be sent back
|
||||
to the client out of order.
|
||||
|
||||
An example server which uses the JSON codec:
|
||||
|
||||
type CalculatorService struct {}
|
||||
|
||||
func (s *CalculatorService) Add(a, b int) int {
|
||||
@ -73,26 +79,40 @@ An example server which uses the JSON codec:
|
||||
for {
|
||||
c, _ := l.AcceptUnix()
|
||||
codec := v2.NewJSONCodec(c)
|
||||
go server.ServeCodec(codec)
|
||||
go server.ServeCodec(codec, 0)
|
||||
}
|
||||
|
||||
Subscriptions
|
||||
|
||||
The package also supports the publish subscribe pattern through the use of subscriptions.
|
||||
A method that is considered eligible for notifications must satisfy the following criteria:
|
||||
- object must be exported
|
||||
A method that is considered eligible for notifications must satisfy the following
|
||||
criteria:
|
||||
|
||||
- method must be exported
|
||||
- first method argument type must be context.Context
|
||||
- method argument(s) must be exported or builtin types
|
||||
- method must return the tuple Subscription, error
|
||||
- method must have return types (rpc.Subscription, error)
|
||||
|
||||
An example method:
|
||||
func (s *BlockChainService) NewBlocks(ctx context.Context) (Subscription, error) {
|
||||
|
||||
func (s *BlockChainService) NewBlocks(ctx context.Context) (rpc.Subscription, error) {
|
||||
...
|
||||
}
|
||||
|
||||
Subscriptions are deleted when:
|
||||
- the user sends an unsubscribe request
|
||||
- the connection which was used to create the subscription is closed. This can be initiated
|
||||
by the client and server. The server will close the connection on a write error or when
|
||||
the queue of buffered notifications gets too big.
|
||||
When the service containing the subscription method is registered to the server, for
|
||||
example under the "blockchain" namespace, a subscription is created by calling the
|
||||
"blockchain_subscribe" method.
|
||||
|
||||
Subscriptions are deleted when the user sends an unsubscribe request or when the
|
||||
connection which was used to create the subscription is closed. This can be initiated by
|
||||
the client and server. The server will close the connection for any write error.
|
||||
|
||||
For more information about subscriptions, see https://github.com/ethereum/go-ethereum/wiki/RPC-PUB-SUB.
|
||||
|
||||
Reverse Calls
|
||||
|
||||
In any method handler, an instance of rpc.Client can be accessed through the
|
||||
ClientFromContext method. Using this client instance, server-to-client method calls can be
|
||||
performed on the RPC connection.
|
||||
*/
|
||||
package rpc
|
||||
|
Reference in New Issue
Block a user