From 274bd84d12e1cea16f358bf906d0da9ec2da4204 Mon Sep 17 00:00:00 2001 From: a <a@tuxpa.in> Date: Mon, 4 Dec 2023 11:48:42 -0600 Subject: [PATCH] tests passed --- pkg/jsonrpc/message.go | 59 ++++++++++++++++++++++++++++ pkg/server/server.go | 87 ++++++++++++++++++------------------------ 2 files changed, 96 insertions(+), 50 deletions(-) create mode 100644 pkg/jsonrpc/message.go diff --git a/pkg/jsonrpc/message.go b/pkg/jsonrpc/message.go new file mode 100644 index 0000000..dfaeacb --- /dev/null +++ b/pkg/jsonrpc/message.go @@ -0,0 +1,59 @@ +package jsonrpc + +import ( + "encoding/json" + "io" + + "github.com/go-faster/jx" +) + +// MessageStream is a writer used to write jsonrpc message to a stream +type MessageStream struct { + w io.Writer + jx *jx.Writer +} + +func NewStream(w io.Writer) (*MessageStream, error) { + enc := jx.GetWriter() + defer jx.PutWriter(enc) + enc.Grow(4096) + enc.ResetWriter(w) + enc.ObjStart() + enc.FieldStart("jsonrpc") + enc.Str("2.0") + enc.Close() + return &MessageStream{ + w: w, + jx: enc, + }, nil +} + +func (m *MessageStream) Field(name string, value json.RawMessage) error { + m.jx.ResetWriter(m.w) + m.jx.Comma() + m.jx.FieldStart(name) + m.jx.Raw(value) + return m.jx.Close() +} + +// Result returns a writecloser that writes to a result field +func (m *MessageStream) Result() (io.Writer, error) { + m.jx.ResetWriter(m.w) + m.jx.Comma() + m.jx.FieldStart("result") + m.jx.Close() + return &MessageWriter{w: m.w}, nil +} + +func (m *MessageStream) Close() error { + _, err := m.w.Write([]byte("}")) + return err +} + +type MessageWriter struct { + w io.Writer +} + +func (m *MessageWriter) Write(p []byte) (n int, err error) { + return m.w.Write(p) +} diff --git a/pkg/server/server.go b/pkg/server/server.go index ac33a89..67ea3ed 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -294,63 +294,50 @@ type callEnv struct { func (c *callResponder) send(ctx context.Context, env *callEnv) (err error) { w := c.remote - enc := jx.GetWriter() - defer jx.PutWriter(enc) - enc.Grow(4096) - enc.ResetWriter(w) - enc.ObjStart() - enc.FieldStart("jsonrpc") - enc.Str("2.0") + s, err := jsonrpc.NewStream(w) + if err != nil { + return err + } + defer s.Close() if env.id != nil { - enc.Comma() - enc.FieldStart("id") - enc.Raw(env.id.RawMessage()) + s.Field("id", env.id.RawMessage()) } if env.err != nil { - enc.Comma() - enc.FieldStart("error") - enc.Raw(jsonrpc.MarshalError(env.err)) - } else { - // if there is no error, we try to marshal the result - enc.Comma() - enc.FieldStart("result") - enc.Close() - enc.ResetWriter(w) - if env.v != nil { - switch cast := (env.v).(type) { - case json.RawMessage: - if len(cast) == 0 { - enc.Null() - } else { - enc.Raw(cast) - } - case *io.PipeReader: - _, err := io.Copy(w, cast) - if err != nil { - return err - } - cast.Close() - case func(e io.Writer) error: - err = cast(w) - case func(e *jx.Writer) error: - err = cast(enc) - default: - err = jjson.Encode(w, cast) - } - } else { - enc.Null() - } - } - if env.err == nil && err != nil { - enc.Comma() - enc.FieldStart("error") - enc.Raw(jsonrpc.MarshalError(err)) + s.Field("error", jsonrpc.MarshalError(env.err)) + return nil } - enc.ObjEnd() - err = enc.Close() + // if there is no error, we try to marshal the result + wr, err := s.Result() if err != nil { return err } + if env.v == nil { + _, err := wr.Write(jsonrpc.Null) + if err != nil { + return err + } + return nil + } + switch cast := (env.v).(type) { + case json.RawMessage: + if len(cast) == 0 { + } else { + _, err := wr.Write(cast) + if err != nil { + return err + } + } + case *io.PipeReader: + _, err := io.Copy(wr, cast) + if err != nil { + return err + } + cast.Close() + case func(e io.Writer) error: + err = cast(wr) + default: + err = jjson.Encode(w, cast) + } return nil } -- GitLab