package msgpackrpc import ( "errors" "fmt" "io" "go-micro.dev/v4/codec" "github.com/tinylib/msgp/msgp" ) type msgpackCodec struct { rwc io.ReadWriteCloser mt codec.MessageType body bool } func (c *msgpackCodec) Close() error { return c.rwc.Close() } func (c *msgpackCodec) String() string { return "msgpack-rpc" } // ReadHeader reads the header from the wire. func (c *msgpackCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { c.mt = mt switch mt { case codec.Request: var h Request if err := msgp.Decode(c.rwc, &h); err != nil { return err } c.body = h.hasBody m.Id = h.ID m.Endpoint = h.Method case codec.Response: var h Response if err := msgp.Decode(c.rwc, &h); err != nil { return err } c.body = h.hasBody m.Id = h.ID m.Error = h.Error case codec.Event: var h Notification if err := msgp.Decode(c.rwc, &h); err != nil { return err } c.body = h.hasBody m.Endpoint = h.Method default: return errors.New("Unrecognized message type") } return nil } // ReadBody reads the body of the message. It is assumed the value being // decoded into is a satisfies the msgp.Decodable interface. func (c *msgpackCodec) ReadBody(v interface{}) error { if !c.body { return nil } r := msgp.NewReader(c.rwc) // Body is present, but no value to decode into. if v == nil { return r.Skip() } switch c.mt { case codec.Request, codec.Response, codec.Event: return decodeBody(r, v) default: return fmt.Errorf("Unrecognized message type: %v", c.mt) } } // Write writes a message to the wire which contains the header followed by the body. // The body is assumed to satisfy the msgp.Encodable interface. func (c *msgpackCodec) Write(m *codec.Message, b interface{}) error { switch m.Type { case codec.Request: h := Request{ ID: m.Id, Method: m.Endpoint, Body: b, } return msgp.Encode(c.rwc, &h) case codec.Response: h := Response{ ID: m.Id, Body: b, } h.Error = m.Error return msgp.Encode(c.rwc, &h) case codec.Event: h := Notification{ Method: m.Endpoint, Body: b, } return msgp.Encode(c.rwc, &h) default: return fmt.Errorf("Unrecognized message type: %v", m.Type) } } func NewCodec(rwc io.ReadWriteCloser) codec.Codec { return &msgpackCodec{ rwc: rwc, } }