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 } }