mirror of
https://github.com/Gouryella/drip.git
synced 2026-02-23 21:00:44 +00:00
130 lines
3.3 KiB
Go
130 lines
3.3 KiB
Go
package protocol
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
)
|
|
|
|
// EncodeDataPayload encodes a data header and payload into a frame payload
|
|
// Uses binary encoding (optimized format)
|
|
func EncodeDataPayload(header DataHeader, data []byte) ([]byte, error) {
|
|
return EncodeDataPayloadV2(header, data)
|
|
}
|
|
|
|
// EncodeDataPayloadV1 encodes using JSON (legacy)
|
|
// Format: JSON_HEADER\nDATA
|
|
func EncodeDataPayloadV1(header DataHeader, data []byte) ([]byte, error) {
|
|
headerBytes, err := json.Marshal(header)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Combine: header + newline + data
|
|
payload := make([]byte, 0, len(headerBytes)+1+len(data))
|
|
payload = append(payload, headerBytes...)
|
|
payload = append(payload, '\n')
|
|
payload = append(payload, data...)
|
|
|
|
return payload, nil
|
|
}
|
|
|
|
// EncodeDataPayloadV2 encodes using binary format (optimized)
|
|
// Format: BINARY_HEADER + DATA
|
|
func EncodeDataPayloadV2(header DataHeader, data []byte) ([]byte, error) {
|
|
// Convert to binary header
|
|
var h2 DataHeaderV2
|
|
h2.FromDataHeader(header)
|
|
|
|
// Encode header to binary
|
|
headerBytes := h2.MarshalBinary()
|
|
|
|
// Combine: binary header + data
|
|
payload := make([]byte, 0, len(headerBytes)+len(data))
|
|
payload = append(payload, headerBytes...)
|
|
payload = append(payload, data...)
|
|
|
|
return payload, nil
|
|
}
|
|
|
|
// DecodeDataPayload decodes a frame payload into header and data
|
|
// Auto-detects protocol version
|
|
func DecodeDataPayload(payload []byte) (DataHeader, []byte, error) {
|
|
if len(payload) == 0 {
|
|
return DataHeader{}, nil, errors.New("empty payload")
|
|
}
|
|
|
|
// Try to detect version:
|
|
// - V1 (JSON): starts with '{'
|
|
// - V2 (Binary): first byte is flags (0x00-0x1F typically)
|
|
if payload[0] == '{' {
|
|
// V1: JSON format
|
|
return DecodeDataPayloadV1(payload)
|
|
}
|
|
|
|
// V2: Binary format
|
|
return DecodeDataPayloadV2(payload)
|
|
}
|
|
|
|
// DecodeDataPayloadV1 decodes JSON format (legacy)
|
|
// Format: JSON_HEADER\nDATA
|
|
func DecodeDataPayloadV1(payload []byte) (DataHeader, []byte, error) {
|
|
// Find newline separator
|
|
sepIdx := -1
|
|
for i, b := range payload {
|
|
if b == '\n' {
|
|
sepIdx = i
|
|
break
|
|
}
|
|
}
|
|
|
|
if sepIdx == -1 {
|
|
return DataHeader{}, nil, errors.New("invalid v1 payload: no newline separator")
|
|
}
|
|
|
|
// Parse JSON header
|
|
var header DataHeader
|
|
if err := json.Unmarshal(payload[:sepIdx], &header); err != nil {
|
|
return DataHeader{}, nil, err
|
|
}
|
|
|
|
// Extract data (after newline)
|
|
data := payload[sepIdx+1:]
|
|
|
|
return header, data, nil
|
|
}
|
|
|
|
// DecodeDataPayloadV2 decodes binary format (optimized)
|
|
// Format: BINARY_HEADER + DATA
|
|
func DecodeDataPayloadV2(payload []byte) (DataHeader, []byte, error) {
|
|
if len(payload) < binaryHeaderMinSize {
|
|
return DataHeader{}, nil, errors.New("invalid v2 payload: too short")
|
|
}
|
|
|
|
// Decode binary header
|
|
var h2 DataHeaderV2
|
|
if err := h2.UnmarshalBinary(payload); err != nil {
|
|
return DataHeader{}, nil, err
|
|
}
|
|
|
|
// Extract data (after header)
|
|
headerSize := h2.Size()
|
|
if len(payload) < headerSize {
|
|
return DataHeader{}, nil, errors.New("invalid v2 payload: data missing")
|
|
}
|
|
|
|
data := payload[headerSize:]
|
|
|
|
// Convert to DataHeader
|
|
header := h2.ToDataHeader()
|
|
|
|
return header, data, nil
|
|
}
|
|
|
|
// GetPayloadHeaderSize returns the size of the header in the payload
|
|
// This is useful for pre-allocating buffers
|
|
func GetPayloadHeaderSize(header DataHeader) int {
|
|
var h2 DataHeaderV2
|
|
h2.FromDataHeader(header)
|
|
return h2.Size()
|
|
}
|