diff --git a/endpoints.go b/endpoints.go index e1dee40dcb7b15e17aba3613666d01734399a073..b743884646a0d944682b82a62852ede08068ff85 100644 --- a/endpoints.go +++ b/endpoints.go @@ -1,17 +1 @@ -// Copyright 2018 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - package jrpc diff --git a/json.go b/json.go index d1a34e501749209c98b485b60bc87c551945c9c0..66b4587b14c792c37305abe6b27724ef23a302ca 100644 --- a/json.go +++ b/json.go @@ -64,15 +64,15 @@ func MakeCall(id int, method string, params []any) *JsonRpcMessage { type JsonRpcMessage = jsonrpcMessage func (msg *jsonrpcMessage) isNotification() bool { - return msg.ID == nil && msg.Method != "" + return msg.ID == nil && len(msg.Method) > 0 } func (msg *jsonrpcMessage) isCall() bool { - return msg.hasValidID() && msg.Method != "" + return msg.hasValidID() && len(msg.Method) > 0 } func (msg *jsonrpcMessage) isResponse() bool { - return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) + return msg.hasValidID() && len(msg.Method) == 0 && msg.Params == nil && (msg.Result != nil || msg.Error != nil) } func (msg *jsonrpcMessage) hasValidID() bool { @@ -182,24 +182,30 @@ type ConnRemoteAddr interface { // jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has // support for parsing arguments and serializing (result) objects. type jsonCodec struct { - remote string - closer sync.Once // close closed channel once - closeCh chan any // closed on Close - decode func(v any) error // decoder to allow multiple transports - encMu sync.Mutex // guards the encoder - encode func(v any) error // encoder to allow multiple transports - conn deadlineCloser + remote string + closer sync.Once // close closed channel once + closeFunc func() error + closeCh chan any // closed on Close + decode func(v any) error // decoder to allow multiple transports + encMu sync.Mutex // guards the encoder + encode func(v any) error // encoder to allow multiple transports + conn deadlineCloser } // NewFuncCodec creates a codec which uses the given functions to read and write. If conn // implements ConnRemoteAddr, log messages will use it to include the remote address of // the connection. -func NewFuncCodec(conn deadlineCloser, encode, decode func(v any) error) ServerCodec { +func NewFuncCodec( + conn deadlineCloser, + encode, decode func(v any) error, + closeFunc func() error, +) ServerCodec { codec := &jsonCodec{ - closeCh: make(chan any), - encode: encode, - decode: decode, - conn: conn, + closeFunc: closeFunc, + closeCh: make(chan any), + encode: encode, + decode: decode, + conn: conn, } if ra, ok := conn.(ConnRemoteAddr); ok { codec.remote = ra.RemoteAddr() @@ -210,10 +216,24 @@ func NewFuncCodec(conn deadlineCloser, encode, decode func(v any) error) ServerC // NewCodec creates a codec on the given connection. If conn implements ConnRemoteAddr, log // messages will use it to include the remote address of the connection. func NewCodec(conn Conn) ServerCodec { - enc := jzon.NewEncoder(conn) + // for some reason other json decoders are incompatible with our test suite + // pretty sure its how we handle EOFs and stuff dec := json.NewDecoder(conn) dec.UseNumber() - return NewFuncCodec(conn, enc.Encode, dec.Decode) + return NewFuncCodec(conn, func(v any) error { + enc := jzon.BorrowStream(conn) + defer jzon.ReturnStream(enc) + enc.WriteVal(v) + enc.WriteRaw("\n") + enc.Flush() + if enc.Error != nil { + return enc.Error + } + return nil + // return jzon.NewEncoder(conn).Encode(v) + }, dec.Decode, func() error { + return nil + }) } func (c *jsonCodec) PeerInfo() PeerInfo { @@ -258,6 +278,9 @@ func (c *jsonCodec) WriteJSON(ctx context.Context, v any) error { func (c *jsonCodec) Close() error { c.closer.Do(func() { close(c.closeCh) + if c.closeFunc != nil { + c.closeFunc() + } c.conn.Close() }) return nil @@ -292,7 +315,8 @@ func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) { func isBatch(raw json.RawMessage) bool { for _, c := range raw { // skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt) - if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d { + switch c { + case 0x20, 0x09, 0x0a, 0x0d: continue } return c == '[' diff --git a/websocket.go b/websocket.go index 7c9b049c0754e286c1cde6d600f71dc3d816b492..1ffe457d4a068eedeb54cbc2be23ca2ca68b6552 100644 --- a/websocket.go +++ b/websocket.go @@ -163,7 +163,7 @@ func newWebsocketCodec(ctx context.Context, c *websocket.Conn, host string, req } conn := websocket.NetConn(ctx, c, websocket.MessageText) wc := &websocketCodec{ - jsonCodec: NewFuncCodec(conn, jsonWriter, jsonReader).(*jsonCodec), + jsonCodec: NewFuncCodec(conn, jsonWriter, jsonReader, func() error { return nil }).(*jsonCodec), conn: c, pingReset: make(chan struct{}, 1), info: PeerInfo{ diff --git a/wsjson/wsjson.go b/wsjson/wsjson.go index b58a220ee3af4002952c7072d9c77cd77d05bb87..01f607e8fa8bb7a78053e76f8161b98e501e7e65 100644 --- a/wsjson/wsjson.go +++ b/wsjson/wsjson.go @@ -69,15 +69,13 @@ func Write(ctx context.Context, c *websocket.Conn, v interface{}) error { return write(ctx, c, v) } -var jpool = jsoniter.NewStream(jzon, nil, 0).Pool() - func write(ctx context.Context, c *websocket.Conn, v interface{}) (err error) { w, err := c.Writer(ctx, websocket.MessageText) if err != nil { return err } - st := jpool.BorrowStream(w) - defer jpool.ReturnStream(st) + st := jzon.BorrowStream(w) + defer jzon.ReturnStream(st) st.WriteVal(v) err = st.Flush() if err != nil {