Documentation
¶
Index ¶
- type APIClient
- func (c *APIClient) CancelInFlight()
- func (c *APIClient) Debug()
- func (c *APIClient) Describe() api.ClientInfo
- func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error)
- func (c *APIClient) GetNodeRule() ([]api.DetectRule, error)
- func (c *APIClient) GetUserList() (UserList []api.UserInfo, err error)
- func (c *APIClient) ParseMieruNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ParseNativeCustomConfig(nodeInfoResponse *NodeInfoResponse, body map[string]json.RawMessage) (*api.NodeInfo, error)
- func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ParseSSPluginNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ParseUserListResponse(userInfoResponse *[]UserResponse) ([]api.UserInfo, error)
- func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
- func (c *APIClient) ReportAccessLog(entries []api.AccessLogEntry) error
- func (c *APIClient) ReportIllegal(detectResultList []api.DetectResult) error
- func (c *APIClient) ReportNodeOnlineUsers(onlineUserList []api.OnlineUser) error
- func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error)
- func (c *APIClient) ReportUserTraffic(userTraffic []api.UserTraffic, windowID string) error
- type CustomConfig
- type IllegalItem
- type NodeInfoResponse
- type OnlineUser
- type PostData
- type REALITYConfig
- type Response
- type RuleItem
- type SystemLoad
- type UserResponse
- type UserTraffic
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIClient ¶
type APIClient struct {
APIHost string
NodeID int
Key string
NodeType string
EnableVless bool
VlessFlow string
SpeedLimit float64
DeviceLimit int
// PanelType selects the node-payload dialect: SSpanel means the traditional
// 6-segment `server` string, Rigel means custom_config. See GetNodeInfo.
PanelType string
LocalRuleList []api.DetectRule
LastReportOnline map[int]int
// contains filtered or unexported fields
}
APIClient create a api client to the panel.
func New ¶
New create api instance
TWO clients, split by whether a re-send is safe (doc/14 C-08):
- client — the three GET pull endpoints. Read-only, so resty's automatic retry is free reliability and keeps its stock semantics (including "do not retry a body that failed to unmarshal").
- postClient — every report. Retry DISABLED. These change panel state and neither panel deduplicates: the traditional one does `u += ...` with nothing to key on, and Rigel's uniqueness key contains the server-side SECOND, which a re-send arriving a client-timeout later can never collide with. The failure we cannot tell apart on the wire — "the panel committed and the response was lost" — is exactly the one where a re-send charges the customer twice.
Two clients rather than one with a method-aware RetryCondition, because registering any condition REPLACES resty's default rule instead of narrowing it (retry.go:125-132 assigns rather than ORs), which silently turned the no-retry marking on unmarshal failures back on.
func (*APIClient) CancelInFlight ¶ added in v0.1.0
func (c *APIClient) CancelInFlight()
CancelInFlight aborts every request currently waiting on the network. Implements api.InFlightCanceler.
Without it, a Controller shutting down had to WAIT OUT whatever the sync loop was doing, and the fixed 30s cap is off by more than an order of magnitude against the real worst case: three retrying GETs (4 attempts × the 30s default timeout) plus five single-shot POSTs is ~8.5 minutes. So Close's "wait for the loop to stop" was not a guarantee at all whenever the panel was slow — which is exactly when a shutdown happens (doc/14 C-15).
It cancels the CURRENT requests and then installs a fresh context, rather than killing the client for good. Shutdown is not done talking to the panel when it calls this: the final traffic settlement and the access-log final flush both POST afterwards (doc/14 C-07, panel/panel.go stopAll ordering). A permanently poisoned client would fail both — silently reintroducing the whole-period loss C-07 exists to prevent, on every graceful stop. What keeps a straggler cycle from doing damage after this is the Controller's generation fence, not a dead client.
func (*APIClient) Describe ¶
func (c *APIClient) Describe() api.ClientInfo
Describe return a description of the client
func (*APIClient) GetNodeInfo ¶
GetNodeInfo will pull NodeInfo Config from ssPanel
func (*APIClient) GetNodeRule ¶
func (c *APIClient) GetNodeRule() ([]api.DetectRule, error)
GetNodeRule will pull the audit rule form ssPanel
func (*APIClient) GetUserList ¶
GetUserList will pull user form ssPanel
func (*APIClient) ParseMieruNodeResponse ¶
func (c *APIClient) ParseMieruNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseMieruNodeResponse parses a traditional-panel Mieru node (doc/13 T7, and the wulala panel plan §3.2). The traditional panel has no custom_config, so Mieru's parameters ride the same `k=v|k=v` extra segment every other legacy node type uses:
<addr>;<listen port>;0;;;server=<addr>|mieru_transport=TCP|mieru_ports=2090-2099|…
Slots 3 and 4 are empty — Mieru has neither a stream transport nor TLS (it carries its own XChaCha20, keyed off username+password).
| extra key | meaning | |------------------------|--------------------------------------------| | mieru_transport | "TCP" (default) or "UDP" | | mieru_ports | port range, e.g. "2090-2099"; wins over | | | the segment-1 port | | mieru_pattern | base64 traffic_pattern | | mieru_user_hint | 1 → user_hint_is_mandatory | | outside_port | subscription port; NOT the listener |
per-user credentials come from /mod_mu/users: username "u{uid}" (built by the translation layer, doc/13 §3.4) + password = passwd.
func (*APIClient) ParseNativeCustomConfig ¶
func (c *APIClient) ParseNativeCustomConfig(nodeInfoResponse *NodeInfoResponse, body map[string]json.RawMessage) (*api.NodeInfo, error)
ParseNativeCustomConfig converts a sing-box-native `custom_config` into a NodeInfo carrying the body opaquely. Returns an error when `type` is missing or unknown — better to fail the sync loudly than to start the wrong inbound.
func (*APIClient) ParseSSNodeResponse ¶
func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseSSNodeResponse parse the response for the given node info format
func (*APIClient) ParseSSPanelNodeInfo ¶
func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseSSPanelNodeInfo parses a version >= 2021.11 `custom_config`.
Two dialects arrive here (doc/13 §2.2, §3.1):
XrayR-flat offset_port_node / network / security / enable_vless / …
→ parsed field-by-field below (unchanged behaviour).
sing-box-native listen_port(+s) and inbound-shaped keys (Rigel's
Hysteria2/TUIC/AnyTLS/Mieru/TrustTunnel nodes)
→ handed to ParseNativeCustomConfig, which keeps the body
opaque for the base fork to unmarshal.
Dispatch is on the payload's SHAPE, not the version: Rigel emits both dialects under version="2021.11" depending on the protocol.
func (*APIClient) ParseSSPluginNodeResponse ¶
func (c *APIClient) ParseSSPluginNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseSSPluginNodeResponse parse the response for the given node info format
func (*APIClient) ParseTrojanNodeResponse ¶
func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseTrojanNodeResponse parse the response for the given node info format
func (*APIClient) ParseUserListResponse ¶
func (c *APIClient) ParseUserListResponse(userInfoResponse *[]UserResponse) ([]api.UserInfo, error)
ParseUserListResponse parse the response for the given node info format. Return regularized *[]api.UserInfo → []api.UserInfo (doc/10 §2.2).
func (*APIClient) ParseV2rayNodeResponse ¶
func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error)
ParseV2rayNodeResponse parses the legacy (SSpanel < 2021.11) 6-segment server string (doc/13 §2.8, T2).
Beyond XrayR v0.9.4 this now reads the protocol-selecting keys the traditional panel already ships but upstream discarded — `enable_vless`, `flow`, `enable_reality`, `servername`, `reality_short_id` — so ONE binary with ONE config.yml can serve VMess-TCP, VMess-WS-TLS and VLESS-Vision-REALITY nodes side by side instead of having the protocol pinned globally by NodeType / EnableVless / VlessFlow. Panel values win; the local config.yml stays the fallback (and remains the ONLY source of the REALITY private key — it must never enter the server string, which is also rendered into user subscriptions; see doc/13 §2.8 and the merge in panel.applyLocalReality, T3).
Port offset (doc/13 §2.7): segment 1 is the port the node LISTENS on; `outside_port` is the port clients dial (the panel rewrites subscriptions to it, Tools.php:538-544) with NAT/forwarding in between. It is deliberately not applied to the listener — only surfaced on NodeInfo for logging/diagnostics.
func (*APIClient) ReportAccessLog ¶
func (c *APIClient) ReportAccessLog(entries []api.AccessLogEntry) error
ReportAccessLog reports a batch of access log entries. Implements api.AccessLogReporter; same endpoint base/auth as the other reporters.
func (*APIClient) ReportIllegal ¶
func (c *APIClient) ReportIllegal(detectResultList []api.DetectResult) error
ReportIllegal reports the user illegal behaviors
func (*APIClient) ReportNodeOnlineUsers ¶
func (c *APIClient) ReportNodeOnlineUsers(onlineUserList []api.OnlineUser) error
ReportNodeOnlineUsers reports online user ip
func (*APIClient) ReportNodeStatus ¶
func (c *APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error)
ReportNodeStatus reports the node status to the ssPanel
func (*APIClient) ReportUserTraffic ¶
func (c *APIClient) ReportUserTraffic(userTraffic []api.UserTraffic, windowID string) error
ReportUserTraffic reports the user traffic.
windowID identifies the accounting period this payload belongs to, and is STABLE across any re-send of the same period. It is sent to Rigel only, as api.HeaderReportID — the traditional panel has no dedup to hang it on and would just ignore it (doc/10 §7.1, doc/14 C-08).
This is the cross-project half of the double-billing fix: node-side we simply stopped re-sending POSTs, which costs a period on every lost report. Once Rigel keys its user_traffic_logs uniqueness on (node, windowID) instead of (node, server-side second), a re-send becomes provably free and the retry can come back — see doc/10 §7.1.
type CustomConfig ¶
type CustomConfig struct {
OffsetPortNode string `json:"offset_port_node"`
Host string `json:"host"`
Method string `json:"method"`
TLS string `json:"tls"`
EnableVless string `json:"enable_vless"`
Network string `json:"network"`
Security string `json:"security"`
Path string `json:"path"`
VerifyCert bool `json:"verify_cert"`
Obfs string `json:"obfs"`
Header json.RawMessage `json:"header"`
AllowInsecure string `json:"allow_insecure"`
Servicename string `json:"servicename"`
EnableXtls string `json:"enable_xtls"`
Flow string `json:"flow"`
EnableREALITY bool `json:"enable_reality"`
RealityOpts *REALITYConfig `json:"reality-opts"`
}
type IllegalItem ¶
type NodeInfoResponse ¶
type NodeInfoResponse struct {
Group int `json:"node_group"`
Class int `json:"node_class"`
SpeedLimit float64 `json:"node_speedlimit"`
TrafficRate float64 `json:"traffic_rate"`
Sort int `json:"sort"`
RawServerString string `json:"server"`
Type string `json:"type"`
CustomConfig json.RawMessage `json:"custom_config"`
Version string `json:"version"`
}
NodeInfoResponse is the response of node
type OnlineUser ¶
OnlineUser is the data structure of online user
type PostData ¶
type PostData struct {
Data interface{} `json:"data"`
}
PostData is the data structure of post data
type REALITYConfig ¶
type REALITYConfig struct {
Dest string `json:"dest,omitempty"`
ProxyProtocolVer uint64 `json:"proxy_protocol_ver,omitempty"`
ServerNames []string `json:"server_names,omitempty"`
PrivateKey string `json:"private_key,omitempty"`
MinClientVer string `json:"min_client_ver,omitempty"`
MaxClientVer string `json:"max_client_ver,omitempty"`
MaxTimeDiff uint64 `json:"max_time_diff,omitempty"`
ShortIds []string `json:"short_ids,omitempty"`
}
type Response ¶
type Response struct {
Ret uint `json:"ret"`
Data json.RawMessage `json:"data"`
}
Response is the common response
type SystemLoad ¶
SystemLoad is the data structure of system load
type UserResponse ¶
type UserResponse struct {
ID int `json:"id"`
Email string `json:"email"`
Passwd string `json:"passwd"`
Port uint32 `json:"port"`
Method string `json:"method"`
SpeedLimit float64 `json:"node_speedlimit"`
DeviceLimit int `json:"node_iplimit"`
UUID string `json:"uuid"`
AliveIP int `json:"alive_ip"`
}
UserResponse is the response of user
type UserTraffic ¶
type UserTraffic struct {
UID int `json:"user_id"`
Upload int64 `json:"u"`
Download int64 `json:"d"`
}
UserTraffic is the data structure of traffic