hash-of-wisdom/internal/protocol/message_decoder.go

66 lines
1.7 KiB
Go
Raw Normal View History

2025-08-23 08:18:45 +03:00
package protocol
import (
"encoding/binary"
"fmt"
"io"
)
// MessageDecoder handles decoding of protocol message headers
type MessageDecoder struct{}
// NewMessageDecoder creates a new message decoder
func NewMessageDecoder() *MessageDecoder {
return &MessageDecoder{}
}
// Decode reads the message header and returns a Message with the payload stream
func (d *MessageDecoder) Decode(r io.Reader) (*Message, error) {
// Read message type (1 byte)
var msgType MessageType
if err := binary.Read(r, binary.BigEndian, &msgType); err != nil {
if err == io.EOF {
return nil, err
}
return nil, fmt.Errorf("failed to read message type: %w", err)
}
// Validate message type (only request types are valid for server)
if !isValidRequestType(msgType) {
return nil, fmt.Errorf("invalid message type: 0x%02x", msgType)
}
// Read payload length (4 bytes, big-endian)
var payloadLength uint32
if err := binary.Read(r, binary.BigEndian, &payloadLength); err != nil {
return nil, fmt.Errorf("failed to read payload length: %w", err)
}
// Validate payload length
if payloadLength > MaxPayloadSize {
return nil, fmt.Errorf("payload length %d exceeds maximum %d", payloadLength, MaxPayloadSize)
}
// Create limited reader for the payload
var payloadStream io.Reader
if payloadLength > 0 {
payloadStream = io.LimitReader(r, int64(payloadLength))
}
return &Message{
Type: msgType,
PayloadLength: payloadLength,
PayloadStream: payloadStream,
}, nil
}
// isValidRequestType checks if the message type is a valid request type
func isValidRequestType(msgType MessageType) bool {
switch msgType {
case ChallengeRequestType, SolutionRequestType:
return true
default:
return false
}
}