Files
mq/codec/codec.go
2024-10-22 17:35:56 +05:45

104 lines
2.1 KiB
Go

package codec
import (
"bufio"
"context"
"encoding/binary"
"net"
"sync"
"github.com/oarkflow/mq/consts"
)
type Message struct {
Headers map[string]string `msgpack:"h"`
Queue string `msgpack:"q"`
Payload []byte `msgpack:"p"`
Command consts.CMD `msgpack:"c"`
}
func NewMessage(cmd consts.CMD, payload []byte, queue string, headers map[string]string) *Message {
if headers == nil {
headers = make(map[string]string)
}
return &Message{
Headers: headers,
Queue: queue,
Command: cmd,
Payload: payload,
}
}
func (m *Message) Serialize() ([]byte, error) {
data, err := Marshal(m)
if err != nil {
return nil, err
}
return data, nil
}
func Deserialize(data []byte) (*Message, error) {
var msg Message
if err := Unmarshal(data, &msg); err != nil {
return nil, err
}
return &msg, nil
}
var byteBufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 0, 4096)
},
}
func SendMessage(ctx context.Context, conn net.Conn, msg *Message) error {
data, err := msg.Serialize()
if err != nil {
return err
}
totalLength := 4 + len(data)
buffer := byteBufferPool.Get().([]byte)
if cap(buffer) < totalLength {
buffer = make([]byte, totalLength)
} else {
buffer = buffer[:totalLength]
}
defer byteBufferPool.Put(buffer)
binary.BigEndian.PutUint32(buffer[:4], uint32(len(data)))
copy(buffer[4:], data)
writer := bufio.NewWriter(conn)
select {
case <-ctx.Done():
return ctx.Err()
default:
if _, err := writer.Write(buffer); err != nil {
return err
}
}
return writer.Flush()
}
func ReadMessage(ctx context.Context, conn net.Conn) (*Message, error) {
lengthBytes := make([]byte, 4)
if _, err := conn.Read(lengthBytes); err != nil {
return nil, err
}
length := binary.BigEndian.Uint32(lengthBytes)
data := byteBufferPool.Get().([]byte)[:length]
defer byteBufferPool.Put(data)
totalRead := 0
for totalRead < int(length) {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
n, err := conn.Read(data[totalRead:])
if err != nil {
return nil, err
}
totalRead += n
}
}
return Deserialize(data[:length])
}