mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-04-18 04:14:28 +00:00
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package proto
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
// ConnectEndStreamFlag marks the end-of-stream frame (trailers).
|
|
ConnectEndStreamFlag byte = 0x02
|
|
// ConnectCompressionFlag indicates the payload is compressed (not supported).
|
|
ConnectCompressionFlag byte = 0x01
|
|
// ConnectFrameHeaderSize is the fixed 5-byte frame header.
|
|
ConnectFrameHeaderSize = 5
|
|
)
|
|
|
|
// FrameConnectMessage wraps a protobuf payload in a Connect frame.
|
|
// Frame format: [1 byte flags][4 bytes payload length (big-endian)][payload]
|
|
func FrameConnectMessage(data []byte, flags byte) []byte {
|
|
frame := make([]byte, ConnectFrameHeaderSize+len(data))
|
|
frame[0] = flags
|
|
binary.BigEndian.PutUint32(frame[1:5], uint32(len(data)))
|
|
copy(frame[5:], data)
|
|
return frame
|
|
}
|
|
|
|
// ParseConnectFrame extracts one frame from a buffer.
|
|
// Returns (flags, payload, bytesConsumed, ok).
|
|
// ok is false when the buffer is too short for a complete frame.
|
|
func ParseConnectFrame(buf []byte) (flags byte, payload []byte, consumed int, ok bool) {
|
|
if len(buf) < ConnectFrameHeaderSize {
|
|
return 0, nil, 0, false
|
|
}
|
|
flags = buf[0]
|
|
length := binary.BigEndian.Uint32(buf[1:5])
|
|
total := ConnectFrameHeaderSize + int(length)
|
|
if len(buf) < total {
|
|
return 0, nil, 0, false
|
|
}
|
|
return flags, buf[5:total], total, true
|
|
}
|
|
|
|
// ParseConnectEndStream parses a Connect end-of-stream frame payload (JSON).
|
|
// Returns nil if there is no error in the trailer.
|
|
func ParseConnectEndStream(data []byte) error {
|
|
if len(data) == 0 {
|
|
return nil
|
|
}
|
|
var trailer struct {
|
|
Error *struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
} `json:"error"`
|
|
}
|
|
if err := json.Unmarshal(data, &trailer); err != nil {
|
|
return fmt.Errorf("failed to parse Connect end stream: %w", err)
|
|
}
|
|
if trailer.Error != nil {
|
|
code := trailer.Error.Code
|
|
if code == "" {
|
|
code = "unknown"
|
|
}
|
|
msg := trailer.Error.Message
|
|
if msg == "" {
|
|
msg = "Unknown error"
|
|
}
|
|
return fmt.Errorf("Connect error %s: %s", code, msg)
|
|
}
|
|
return nil
|
|
}
|