Documentation
¶
Overview ¶
Package panel orchestrates multiple nodes, periodic panel tasks and hot reload. Placeholder — implemented in Phase 1 (doc/03 T11).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AutoSpeedLimitConfig ¶
type AutoSpeedLimitConfig struct {
Limit int `mapstructure:"Limit"`
WarnTimes int `mapstructure:"WarnTimes"`
LimitSpeed int `mapstructure:"LimitSpeed"`
LimitDuration int `mapstructure:"LimitDuration"`
}
AutoSpeedLimitConfig is the T7 dynamic speed-limit policy (doc/09 §5.3). Consumed by the Controller when Limit > 0.
type CertConfig ¶
type CertConfig struct {
CertMode string `mapstructure:"CertMode"`
CertDomain string `mapstructure:"CertDomain"`
CertFile string `mapstructure:"CertFile"`
KeyFile string `mapstructure:"KeyFile"`
Provider string `mapstructure:"Provider"`
Email string `mapstructure:"Email"`
DNSEnv map[string]string `mapstructure:"DNSEnv"`
}
CertConfig — T10 cert automation policy (doc/09 §5.3). Mapped onto cert.CertConfig by the Controller before AddNode.
type Config ¶
type Config struct {
Log LogConfig `mapstructure:"Log"`
Nodes []NodeConfig `mapstructure:"Nodes"`
// --- sing-box passthrough blocks (doc/09 §6.1, §6.2) ---
//
// These are NOT parsed by viper: they carry literal sing-box config, which
// the base decodes itself (core/singbox/passthrough.go). They are held as raw
// JSON because viper LOWERCASES every map key it reads — harmless for
// sing-box's own snake_case keys, but it would silently mangle case-sensitive
// values such as a transport's `headers: {Host: ...}`. loadPassthrough reads
// them straight from the YAML instead, preserving case exactly.
//
// Empty means "not configured": DNS falls back to the Box default, outbounds
// fall back to a lone direct, and routing is absent (everything egresses via
// the default outbound).
DNSRaw json.RawMessage `mapstructure:"-"`
OutboundRaw json.RawMessage `mapstructure:"-"`
RouteRaw json.RawMessage `mapstructure:"-"`
// AccessLog is the process-level access-log reporting policy (doc/09 §4.3,
// doc/11 §13.1). It is the billing/accesslog.Config directly; the Manager's
// normalize() fills defaults. Enable=false (the zero value) leaves access
// logging off, so existing configs without an AccessLog block load cleanly.
AccessLog accesslog.Config `mapstructure:"AccessLog"`
// ConnectionConfig is node-local connection tuning, applied to every
// inbound. Absent means "leave every base default alone".
ConnectionConfig *ConnectionConfig `mapstructure:"ConnectionConfig"`
}
Config is the top-level config.yml shape (doc/09 §3).
func LoadConfig ¶
LoadConfig reads a YAML config.yml from path (viper), unmarshals it into Config, and fills defaults. Key matching is case-insensitive (mapstructure), matching XrayR semantics.
type ConnLimitConfig ¶
type ConnLimitConfig struct {
Enable bool `mapstructure:"Enable"`
MaxConnPerUser int `mapstructure:"MaxConnPerUser"`
}
ConnLimitConfig — net-new (doc/09 §5.3): per-user concurrent-connection cap, pushed to the shared ConnLimiter per node tag before AddNode.
type ConnectionConfig ¶ added in v0.0.3
type ConnectionConfig struct {
UDPTimeout int `mapstructure:"UDPTimeout"` // seconds; base default ~5min
TCPKeepAlive int `mapstructure:"TCPKeepAlive"` // seconds; idle before first probe
TCPKeepAliveInterval int `mapstructure:"TCPKeepAliveInterval"` // seconds; gap between probes
DisableTCPKeepAlive bool `mapstructure:"DisableTCPKeepAlive"`
// --- XrayR compatibility: parsed, warned about, never applied ---
Handshake int `mapstructure:"Handshake"`
ConnIdle int `mapstructure:"ConnIdle"`
UplinkOnly int `mapstructure:"UplinkOnly"`
DownlinkOnly int `mapstructure:"DownlinkOnly"`
BufferSize int `mapstructure:"BufferSize"`
}
ConnectionConfig is config.yml's connection-tuning block (doc/09 §7).
The first four fields are real: they map onto sing-box ListenOptions and take effect on every inbound. The five after them are XrayR's — kept ONLY so that a config carried over from XrayR gets a specific migration message per key instead of being silently ignored. They never change behaviour. See core/singbox.ConnPolicy for the field-by-field reasoning on why sing-box has no equivalent for them.
Durations are whole SECONDS (int), matching ControllerConfig.UpdatePeriodic and XrayR's own convention. A duration string is deliberately not accepted: viper's default decode hook turns a bare `15` into 15 NANOseconds when the target is time.Duration, and a timeout that silently becomes 15ns is worse than one that will not parse.
func (*ConnectionConfig) Policy ¶ added in v0.0.3
func (c *ConnectionConfig) Policy() singbox.ConnPolicy
Policy converts the block into the core-side policy.
func (*ConnectionConfig) Warnings ¶ added in v0.0.3
func (c *ConnectionConfig) Warnings() []string
Warnings reports the XrayR-only keys present in the config, each with what to do instead. Returning them (rather than logging here) keeps LoadConfig free of logging and lets the tests assert on the text.
This exists because the alternative — accepting the key and doing nothing — is the worst outcome available: the operator believes a timeout is in force, and finds out otherwise only when a node misbehaves under load.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller drives one node. It satisfies Service.
func NewController ¶
func NewController(server *singbox.Server, apiClient api.API, config *ControllerConfig) *Controller
NewController wires a node orchestrator over a shared Core and a panel client. A dynamic speed limiter is constructed when the node enables one (Limit > 0).
func (*Controller) Close ¶
func (c *Controller) Close() error
Close stops the monitor and removes the node from the Core.
func (*Controller) Start ¶
func (c *Controller) Start() error
Start performs the initial sync and launches the periodic monitor.
type ControllerConfig ¶
type ControllerConfig struct {
ListenIP string `mapstructure:"ListenIP"`
SendIP string `mapstructure:"SendIP"`
UpdatePeriodic int `mapstructure:"UpdatePeriodic"`
EnableDNS bool `mapstructure:"EnableDNS"`
DNSType string `mapstructure:"DNSType"`
// EnableProxyProtocol makes Sing2 own the public listener and accept a
// PROXY header on it (core/singbox/proxyproto.go), so a node behind
// haproxy's send-proxy still sees real client addresses. Any sender is
// believed — keep the port reachable only from the load balancer.
EnableProxyProtocol bool `mapstructure:"EnableProxyProtocol"`
EnableFallback bool `mapstructure:"EnableFallback"`
// Node-local REALITY: legacy panels keep the private key node-side and do not
// deliver reality-opts, so the Controller injects REALITYConfigs into the
// NodeInfo before AddNode when EnableREALITY is set (unless the operator forces
// the panel copy via DisableLocalREALITYConfig). doc/09 §5.3.
EnableREALITY bool `mapstructure:"EnableREALITY"`
DisableLocalREALITYConfig bool `mapstructure:"DisableLocalREALITYConfig"`
REALITYConfigs RealityConfig `mapstructure:"REALITYConfigs"`
// MieruUserHintIsMandatory forces mieru's per-connection user hint on or off
// for this node, overriding whatever the panel says.
//
// Node-local authority is correct here, unlike the panel-wins rule that
// governs protocol identity (enable_vless and friends): this flag changes
// nothing about what a subscription contains or how a client is configured
// — mieru clients ALWAYS emit the hint (mieru pkg/protocol/mux.go:646,661 →
// addUserHintToNonce, skipped only when the username is empty). It only
// decides whether the SERVER still falls back to trying every user when the
// hint misses. That fallback is the node's CPU bill, so the node's operator
// gets to decide. Same category as the REALITY private key being node-local.
//
// nil = defer to the panel. true = require the hint, which removes the
// try-every-user path entirely (~10x cheaper on junk traffic; see
// protocol/mieru/metrics.go and upstream enfein/mieru#273) at the cost of
// locking out mieru clients older than v3.31.0. false = force the fallback
// back on, the escape hatch when that lockout bites.
MieruUserHintIsMandatory *bool `mapstructure:"MieruUserHintIsMandatory"`
// Local control sub-blocks, all consumed by the Controller: AutoSpeedLimit
// drives the T7 dynamic throttle; GlobalDeviceLimit / ConnLimit are pushed to
// the shared limiter before AddNode; Cert feeds the T10 inbound TLS build.
AutoSpeedLimitConfig AutoSpeedLimitConfig `mapstructure:"AutoSpeedLimitConfig"` // T7 dynamic speed limit
ConnLimitConfig ConnLimitConfig `mapstructure:"ConnLimitConfig"` // per-user concurrent conns
CertConfig CertConfig `mapstructure:"CertConfig"` // T10 cert automation
}
ControllerConfig is the node-level local control policy (doc/09 §5.3). Only ListenIP and UpdatePeriodic are load-bearing for increment D; the rest are parsed so configs round-trip and later increments can wire them.
type LogConfig ¶
type LogConfig struct {
Level string `mapstructure:"Level"`
AccessPath string `mapstructure:"AccessPath"`
ErrorPath string `mapstructure:"ErrorPath"`
// Timezone stamps the access log. Empty = the machine's local time.
// Accepts a fixed offset ("+08:00") or an IANA name ("Asia/Shanghai");
// the offset form always works, the name needs system tzdata.
Timezone string `mapstructure:"Timezone"`
}
LogConfig mirrors XrayR LogConfig (doc/09 §4.1).
type NodeConfig ¶
type NodeConfig struct {
PanelType string `mapstructure:"PanelType"`
ApiConfig api.Config `mapstructure:"ApiConfig"`
ControllerConfig ControllerConfig `mapstructure:"ControllerConfig"`
}
NodeConfig is one entry of Nodes[] (doc/09 §5): panel type + panel connection (api.Config) + local control policy.
type Panel ¶
type Panel struct {
// contains filtered or unexported fields
}
Panel owns the shared Core and the per-node services.
type RealityConfig ¶
type RealityConfig struct {
Show bool `mapstructure:"Show"`
Dest string `mapstructure:"Dest"`
ProxyProtocolVer uint64 `mapstructure:"ProxyProtocolVer"`
ServerNames []string `mapstructure:"ServerNames"`
PrivateKey string `mapstructure:"PrivateKey"`
MinClientVer string `mapstructure:"MinClientVer"`
MaxClientVer string `mapstructure:"MaxClientVer"`
MaxTimeDiff uint64 `mapstructure:"MaxTimeDiff"`
ShortIds []string `mapstructure:"ShortIds"`
}
RealityConfig is the node-local REALITY server config (doc/09 §5.3), mirroring api.REALITYConfig. Fields map to the REALITYConfigs YAML block.