diff --git a/jsonrpc/codec.go b/jsonrpc/codec.go index 7cbe7c1f5f..f8f5191f9a 100644 --- a/jsonrpc/codec.go +++ b/jsonrpc/codec.go @@ -15,6 +15,8 @@ type Request struct { Params json.RawMessage `json:"params,omitempty"` } +type BatchRequest []Request + // Response is a jsonrpc response interface type Response interface { GetID() interface{} diff --git a/jsonrpc/dispatcher.go b/jsonrpc/dispatcher.go index ae7ef31668..179e0cea60 100644 --- a/jsonrpc/dispatcher.go +++ b/jsonrpc/dispatcher.go @@ -231,11 +231,45 @@ func (d *Dispatcher) RemoveFilterByWs(conn wsConn) { } func (d *Dispatcher) HandleWs(reqBody []byte, conn wsConn) ([]byte, error) { + // first try to unmarshal to batch request + // if there is an error try to unmarshal to single request + var batchReq BatchRequest + if err := json.Unmarshal(reqBody, &batchReq); err == nil { + const ( + openSquareBracket = 91 // [ + closeSquareBracket = 93 // ] + comma = 44 // , + ) + + responses := make([][]byte, len(batchReq)) + + for i, req := range batchReq { + responses[i], err = d.handleWs(req, conn) + if err != nil { + return nil, err + } + } + + var buf bytes.Buffer + + buf.WriteByte(openSquareBracket) // Write the start byte + buf.Write(bytes.Join(responses, []byte{comma})) // Write the original byte slice + buf.WriteByte(closeSquareBracket) // Write the end byte + + // batch output should look like + // [ { "requestId": "1", "status": 200 }, { "requestId": "2", "status": 200 } ] + return buf.Bytes(), nil + } + var req Request if err := json.Unmarshal(reqBody, &req); err != nil { return NewRPCResponse(req.ID, "2.0", nil, NewInvalidRequestError("Invalid json request")).Bytes() } + return d.handleWs(req, conn) +} + +func (d *Dispatcher) handleWs(req Request, conn wsConn) ([]byte, error) { // if the request method is eth_subscribe we need to create a // new filter with ws connection if req.Method == "eth_subscribe" {