95 lines
2.0 KiB
Go
95 lines
2.0 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// Protocol constants (mirror of the Java Protocol class; see PROTOCOL.md).
|
|
const (
|
|
IntentRedapricot = 17
|
|
ProtocolVersion = 767 // arbitrary; the hub ignores it
|
|
|
|
MagicControl = 0x01
|
|
MagicWorker = 0x02
|
|
|
|
CIDLen = 16
|
|
|
|
CtlSessionReady = 0x00
|
|
CtlRegister = 0x01
|
|
CtlUnregister = 0x02
|
|
CtlRegisterAck = 0x03
|
|
CtlControlRequest = 0x04
|
|
CtlPing = 0x05
|
|
CtlPong = 0x06
|
|
|
|
MuxSyn = 0x00
|
|
MuxData = 0x01
|
|
MuxFin = 0x02
|
|
MuxRst = 0x03
|
|
|
|
FrameError = 0x7F
|
|
|
|
SaturationThreshold = 8
|
|
)
|
|
|
|
// Mapping routes a registered pattern to a real destination.
|
|
type Mapping struct {
|
|
Pattern string `json:"pattern"`
|
|
Destination string `json:"destination"`
|
|
ProxyProtocol bool `json:"proxyProtocol"`
|
|
}
|
|
|
|
// Config is the client configuration (PROTOCOL.md §9.2).
|
|
type Config struct {
|
|
Server string `json:"server"`
|
|
PSK string `json:"psk"`
|
|
MaxConn int `json:"maxConn"`
|
|
PingIntervalMs int `json:"pingIntervalMs"`
|
|
Mappings []Mapping `json:"mappings"`
|
|
}
|
|
|
|
// LoadConfig reads and validates a JSON config file.
|
|
func LoadConfig(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var c Config
|
|
if err := json.Unmarshal(data, &c); err != nil {
|
|
return nil, fmt.Errorf("parse config: %w", err)
|
|
}
|
|
if c.Server == "" {
|
|
return nil, fmt.Errorf("server is required")
|
|
}
|
|
if c.PSK == "" {
|
|
return nil, fmt.Errorf("psk is required")
|
|
}
|
|
if c.MaxConn < 1 {
|
|
c.MaxConn = 1
|
|
}
|
|
if c.MaxConn > 8 {
|
|
c.MaxConn = 8
|
|
}
|
|
if c.PingIntervalMs <= 0 {
|
|
c.PingIntervalMs = 20000
|
|
}
|
|
if len(c.Mappings) == 0 {
|
|
return nil, fmt.Errorf("at least one mapping is required")
|
|
}
|
|
return &c, nil
|
|
}
|
|
|
|
// NormalizeAddress matches the hub's normalization: lower-cased, FML-suffix and
|
|
// trailing-dot stripped.
|
|
func NormalizeAddress(addr string) string {
|
|
if i := strings.IndexByte(addr, 0); i >= 0 {
|
|
addr = addr[:i]
|
|
}
|
|
addr = strings.ToLower(addr)
|
|
addr = strings.TrimRight(addr, ".")
|
|
return addr
|
|
}
|