jsonrpc2: Add batch and notify support - #49
Conversation
Fix pool metadata bugs
Needs more tests
Mildly breaks the public API (probably unused)
| }, | ||
| ID: req.ID, | ||
| Version: Version, | ||
| func (s *Server) Handle(ctx context.Context, req *Request) *Response { |
There was a problem hiding this comment.
This is breaking the public API, but nobody is using it yet and it's moderately internal, sooo seems safe? 🤷♂️
ryanschneider
left a comment
There was a problem hiding this comment.
Overall lgtm, minor questions/comments below.
Overall, I agree w/ breaking it out into it's own 0.x-versioned repo.
| } | ||
|
|
||
| // newNotification is a helper for creating encoded Request Messages without IDs. | ||
| func newNotification(method string, params ...interface{}) (*Message, error) { |
There was a problem hiding this comment.
Why not add Notification as a public method and to the Requester interface? Or perhaps a new Notifier interface?
There was a problem hiding this comment.
Mostly trying to reduce the public API surface. I imagine there are two use flows for this kind of library: Either you're using it at the highest level (Call(...)) and never have to think about the message types, or you're using it at the lowest level and passing around message instances through codecs.
These newNotification/newRequest helpers are kind-of in-between (really they're helpers for going from low-level to high-level). If you're constructing your own message types, you probably have enough custom stuff that you're not going to use this. If you're using the high-level interface, you're not going to use this either.
Also they're just the byproduct of an internal refactor, so it's not something that was exposed before.
| @@ -26,31 +52,121 @@ var _ Codec = &jsonCodec{} | |||
| // IOCodec returns a Codec that wraps JSON encoding and decoding over IO. | |||
| func IOCodec(rwc io.ReadWriteCloser) *jsonCodec { | |||
There was a problem hiding this comment.
Intentional discrepancy? Public function is IOCodec but it returns a jsonCodec?
There was a problem hiding this comment.
All the *Codec helpers return a Codec interface implementation. In this case, it takes an IO (rwc) and returns a Codec (implemented by jsonCodec), so it's an IOCodec.
I don't return the Codec interface explicitly to comply with the "accept interfaces, return structs" mantra.
The fact that it's a jsonCodec is because it is json RPC after all. :)
I should probably:
- Pull all these codecs into a codec sub-package, then could have
jsonrpc2.codec.New(rwc) - Maybe make the jsonCodec struct a public JSONCodec so people can directly provide their own encoders/decoders.
I've been going back and forth on how I wanted the jsonCodec internals to be used, but it might be stable enough now.
| if len(batch) == 0 { | ||
| // FIXME: Should we be forgiving of this? Just return an empty message, | ||
| // or keep blocking until we get one? | ||
| return nil, errors.New("empty message batch") |
There was a problem hiding this comment.
According to the spec:
If the batch rpc call itself fails to be recognized as an valid JSON or as an Array with at least one value, the response from the Server MUST be a single Response object
There was a problem hiding this comment.
Also from the examples:
--> []
<-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
There was a problem hiding this comment.
Good catch on that in the specs, I missed it!
I'm preeeetty sure the outcome will be correct, because the error at the codec level will get converted into a JSONRPC error message at the transport level.
I should totally add a test for this.
Interestingly, it seems geth's jsonrpc implementation ignores empty batches.
There was a problem hiding this comment.
In fact, I should add all the examples as tests.
There was a problem hiding this comment.
You were right, needed to wire up the actual response error. (Edit: Got a few more changes coming up, hang tight)
| }, | ||
| { | ||
| In: ` | ||
| [ |
There was a problem hiding this comment.
Is this actually desired behavior?
There was a problem hiding this comment.
@ryanschneider How do you mean?
I'm probably missing something, but looks sensible to me. Note that the input is a JSON stream, so multiple messages are supported.
|
Leaning towards pulling this out into a standalone lib now, instead of even merging changes here. |
|
Maybe take the opportunity to reduce the public API surface, too. |
|
Going to move around where the batch errors are generated, and add a bunch more tests. Will ping again when it's ready for another look. :) |
This should get us very close to #43. The goal is to have a complete JSONRPC2 implementation with a permissive license that can be usable for all functions of Ethereum nodes. (Aside: Might even be worth pulling it out into a standalone library at that point, to allow for separate versioning?)