Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize message parsing #79

Merged
merged 2 commits into from
Jun 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 37 additions & 38 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,73 +108,72 @@ func (c *Codec) RegisterEvent(event string, ctor func() Message) error {
// command, etc cannot be cast, returns DecodeProtocolMessageFieldError.
// See also godoc for json.Unmarshal, which is used for underlying decoding.
func (c *Codec) DecodeMessage(data []byte) (Message, error) {
var protomsg ProtocolMessage
if err := json.Unmarshal(data, &protomsg); err != nil {
// This struct is the union of the ResponseMessage, RequestMessage, and
// EventMessage types. It is an optimization that saves an additional
// json.Unmarshal call.
var m struct {
suzmue marked this conversation as resolved.
Show resolved Hide resolved
ProtocolMessage
Command string `json:"command"`
Event string `json:"event"`
Success bool `json:"success"`
}
if err := json.Unmarshal(data, &m); err != nil {
return nil, err
}
switch protomsg.Type {
switch m.Type {
case "request":
return c.decodeRequest(data)
return c.decodeRequest(m.Command, m.Seq, data)
case "response":
return c.decodeResponse(data)
return c.decodeResponse(m.Command, m.Seq, m.Success, data)
case "event":
return c.decodeEvent(data)
return c.decodeEvent(m.Event, m.Seq, data)
default:
return nil, &DecodeProtocolMessageFieldError{protomsg.GetSeq(), "ProtocolMessage", "type", protomsg.Type}
return nil, &DecodeProtocolMessageFieldError{m.Seq, "ProtocolMessage", "type", m.Type}
}
}

// decodeRequest determines what request type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeRequest(data []byte) (Message, error) {
var r Request
if err := json.Unmarshal(data, &r); err != nil {
return nil, err
func (c *Codec) decodeRequest(command string, seq int, data []byte) (Message, error) {
ctor, ok := c.requestCtor[command]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Request", "command", command}
}
if ctor, ok := c.requestCtor[r.Command]; ok {
requestPtr := ctor()
err := json.Unmarshal(data, requestPtr)
return requestPtr, err
}
return nil, &DecodeProtocolMessageFieldError{r.GetSeq(), "Request", "command", r.Command}
requestPtr := ctor()
err := json.Unmarshal(data, requestPtr)
return requestPtr, err
}

// decodeResponse determines what response type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeResponse(data []byte) (Message, error) {
var r Response
if err := json.Unmarshal(data, &r); err != nil {
return nil, err
}
if !r.Success {
func (c *Codec) decodeResponse(command string, seq int, success bool, data []byte) (Message, error) {
if !success {
var er ErrorResponse
err := json.Unmarshal(data, &er)
return &er, err
}
if ctor, ok := c.responseCtor[r.Command]; ok {
responsePtr := ctor()
err := json.Unmarshal(data, responsePtr)
return responsePtr, err
ctor, ok := c.responseCtor[command]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Response", "command", command}
}
return nil, &DecodeProtocolMessageFieldError{r.GetSeq(), "Response", "command", r.Command}
responsePtr := ctor()
err := json.Unmarshal(data, responsePtr)
return responsePtr, err
}

// decodeEvent determines what event type in the ProtocolMessage hierarchy
// data corresponds to and uses json.Unmarshal to populate the corresponding
// struct to be returned.
func (c *Codec) decodeEvent(data []byte) (Message, error) {
var e Event
if err := json.Unmarshal(data, &e); err != nil {
return nil, err
}
if ctor, ok := c.eventCtor[e.Event]; ok {
eventPtr := ctor()
err := json.Unmarshal(data, eventPtr)
return eventPtr, err
func (c *Codec) decodeEvent(event string, seq int, data []byte) (Message, error) {
ctor, ok := c.eventCtor[event]
if !ok {
return nil, &DecodeProtocolMessageFieldError{seq, "Event", "event", event}
}
return nil, &DecodeProtocolMessageFieldError{e.GetSeq(), "Event", "event", e.Event}
eventPtr := ctor()
err := json.Unmarshal(data, eventPtr)
return eventPtr, err
}

// DecodeProtocolMessage parses the JSON-encoded ProtocolMessage and returns
Expand Down