Files
Piik/internal/client/loopback/protocol.go
T
AAA da47189fc3 refactor: unify Go runtime and audited frontend
Squash integration of the reviewed Go core, frontend audit fixes, release tooling, and deployment hygiene. CI passed all Server/Client jobs.
2026-09-06 23:26:01 +08:00

74 lines
1.8 KiB
Go

package loopback
import (
"bytes"
"encoding/json"
"errors"
"io"
"regexp"
)
const (
ProtocolVersion = 8
ServiceName = "screener-client"
ControlSubprotocol = "screener-client-v8"
MaxControlMessageBytes = 256 << 10
DefaultPortStart = 39721
DefaultPortEnd = 39730
)
var (
requestIDPattern = regexp.MustCompile(`^[A-Za-z0-9_-]{8,256}$`)
errInvalidMessage = errors.New("loopback control message is invalid")
)
type controlMessage struct {
Version int `json:"version"`
ID string `json:"id"`
Type string `json:"type"`
}
func decodeEnvelope(payload []byte) (controlMessage, error) {
var message controlMessage
decoder := json.NewDecoder(bytes.NewReader(payload))
if decoder.Decode(&message) != nil || decoder.Decode(&struct{}{}) != io.EOF ||
message.Version != ProtocolVersion || !requestIDPattern.MatchString(message.ID) ||
message.Type == "" {
return controlMessage{}, errInvalidMessage
}
return message, nil
}
func decodeRequest(payload []byte) (controlMessage, error) {
var message controlMessage
decoder := json.NewDecoder(bytes.NewReader(payload))
decoder.DisallowUnknownFields()
if decoder.Decode(&message) != nil || decoder.Decode(&struct{}{}) != io.EOF ||
message.Version != ProtocolVersion || !requestIDPattern.MatchString(message.ID) {
return controlMessage{}, errInvalidMessage
}
return message, nil
}
func validateHello(message controlMessage) error {
if message.Type != "hello" {
return errInvalidMessage
}
return nil
}
func validatePing(message controlMessage) error {
if message.Type != "ping" {
return errInvalidMessage
}
return nil
}
func encodeMessage(value any) ([]byte, error) {
payload, err := json.Marshal(value)
if err != nil || len(payload) == 0 || len(payload) > MaxControlMessageBytes {
return nil, errInvalidMessage
}
return payload, nil
}