Documentation
¶
Overview ¶
Package core ties the store and the Xray supervisor together: mutations go through it so the proxy config is reconciled from the DB after every change.
Index ¶
- type ConnInfo
- type ConnectionsStatus
- type ConnectionsUpdate
- type Manager
- func (m *Manager) AppLogTail() []string
- func (m *Manager) ApplyConnections(u ConnectionsUpdate) error
- func (m *Manager) ApplyRouting(cfg model.RoutingConfig, warpEnabled, operaEnabled bool, operaCountry string) error
- func (m *Manager) BackupManifest() backup.Manifest
- func (m *Manager) CancelTelegramLink() error
- func (m *Manager) CertPinSHA256() string
- func (m *Manager) ChangeAdminPassword(adminID int64, newPassword string) error
- func (m *Manager) Connections(id int64) ([]model.Connection, error)
- func (m *Manager) ConnectionsInfo() (*ConnectionsStatus, error)
- func (m *Manager) CreateUser(name string, dataLimit, expireAt int64) (*model.User, error)
- func (m *Manager) DeleteUser(id int64) error
- func (m *Manager) FetchRoutingTemplate(url string) (string, error)
- func (m *Manager) FinishSetup() error
- func (m *Manager) GenerateTelegramLinkCode() (string, error)
- func (m *Manager) GeoCategories() (geosite, geoip []string, err error)
- func (m *Manager) GeoStatus() []geo.FileInfo
- func (m *Manager) HasValidCert() bool
- func (m *Manager) ListUsers() ([]model.User, error)
- func (m *Manager) Location() *time.Location
- func (m *Manager) MustChangePassword() bool
- func (m *Manager) OperaHealthy() bool
- func (m *Manager) OperaRunning() bool
- func (m *Manager) PollStats() error
- func (m *Manager) ProxyCount() int
- func (m *Manager) Reconcile() error
- func (m *Manager) RecordAccess(email, ip string)
- func (m *Manager) RefreshGeo() ([]geo.FileInfo, error)
- func (m *Manager) RefreshProxies()
- func (m *Manager) RegenerateSecretPath() (string, error)
- func (m *Manager) RenameUser(id int64, name string) error
- func (m *Manager) RenewTLSIfNeeded() (bool, error)
- func (m *Manager) ResetStats() error
- func (m *Manager) ResetTraffic(id int64) error
- func (m *Manager) SaveSubSettings(st *model.Settings) error
- func (m *Manager) SaveTelegram(enabled bool, token, backupCron string) error
- func (m *Manager) SeedProxies()
- func (m *Manager) SetACMETarget(target, email, provider, eabKID, eabHMAC string) error
- func (m *Manager) SetDecoyTemplate(name string) error
- func (m *Manager) SetProxyMode(enabled bool, typ string, port int, user, pass string) error
- func (m *Manager) SetResetPeriod(id int64, period string) error
- func (m *Manager) SetTimezone(name string) error
- func (m *Manager) SetUserEnabled(id int64, enabled bool) error
- func (m *Manager) SetUserLimits(id, dataLimit, expireAt int64) error
- func (m *Manager) SetXrayDNS(dns string) error
- func (m *Manager) Settings() (*model.Settings, error)
- func (m *Manager) StartSysstat(diskPath string)
- func (m *Manager) StatsByUser(from, to string) ([]model.UserTotal, error)
- func (m *Manager) StatsSeries(userID int64, from, to string) ([]model.DailyPoint, error)
- func (m *Manager) Store() *store.Store
- func (m *Manager) SubscribeAppLogs() (<-chan string, func())
- func (m *Manager) SubscribeXrayLogs() (<-chan string, func())
- func (m *Manager) Summary() (*Summary, error)
- func (m *Manager) SystemStatus() (*SystemStatus, error)
- func (m *Manager) TLSStatus() (*TLSStatus, error)
- func (m *Manager) TrackVPNViewer() func()
- func (m *Manager) TriggerReconcile()
- func (m *Manager) TriggerUserSync()
- func (m *Manager) UnlinkTelegramChat(id int64) error
- func (m *Manager) UpdateAdminCredentials(adminID int64, currentPassword, username, password, keepToken string) error
- func (m *Manager) XrayConfig() ([]byte, error)
- func (m *Manager) XrayLogTail() []string
- func (m *Manager) XrayStatus() (running bool, startedAt int64)
- type Summary
- type SystemStatus
- type TLSPaths
- type TLSStatus
- type ValidationError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ConnInfo ¶
type ConnInfo struct {
Key string `json:"key"`
Name string `json:"name"`
Transport string `json:"transport"`
Security string `json:"security"`
Port string `json:"port"`
Note string `json:"note"`
Enabled bool `json:"enabled"`
// Fingerprint is the protocol's uTLS fingerprint (empty for Hysteria2, which
// has no uTLS — the UI then shows no fingerprint control for it).
Fingerprint string `json:"fingerprint"`
}
ConnInfo describes one client-facing protocol endpoint. Key is the stable identifier used to toggle the protocol; Enabled reports whether it currently appears in user subscriptions.
type ConnectionsStatus ¶
type ConnectionsStatus struct {
Host string `json:"host"`
SNI string `json:"sni"`
WSPath string `json:"ws_path"` // Trojan-WS path
Protocols []ConnInfo `json:"protocols"`
// Hysteria2 base port, hop range, and rotation interval (UDP port-hopping).
HysteriaPort int `json:"hysteria_port"`
HopStart int `json:"hop_start"`
HopEnd int `json:"hop_end"`
HopInterval string `json:"hop_interval"`
// VLESS + gRPC + REALITY parameters (public key / shortId / service name are
// generated by the panel and shown read-only for reference).
RealityPort int `json:"reality_port"`
RealityDest string `json:"reality_dest"`
RealityPublicKey string `json:"reality_public_key"`
RealityShortID string `json:"reality_short_id"`
RealityServiceName string `json:"reality_service_name"`
RealityAntiReplay bool `json:"reality_anti_replay"` // REALITY maxTimeDiff > 0
// Anti-DPI transport hardening (cross-protocol).
TLSFragment bool `json:"tls_fragment"` // sing-box ClientHello fragmentation
TLSMin13 bool `json:"tls_min13"` // require TLS 1.3 on :443
BlockQUIC bool `json:"block_quic"` // drop untunneled browser QUIC in client configs
}
ConnectionsStatus is the public connection surface: where clients connect and how, per protocol.
type ConnectionsUpdate ¶
type ConnectionsUpdate struct {
Protocols map[string]bool `json:"protocols"` // key → enabled
Fingerprints map[string]string `json:"fingerprints"` // key → uTLS fingerprint
WSPath string `json:"ws_path"`
HysteriaPort int `json:"hysteria_port"`
HopStart int `json:"hop_start"`
HopEnd int `json:"hop_end"`
HopInterval string `json:"hop_interval"`
RealityPort int `json:"reality_port"`
RealityDest string `json:"reality_dest"`
RealityAntiReplay bool `json:"reality_anti_replay"`
// RegenRealityKeys requests a fresh REALITY keypair / shortId / service name.
RegenRealityKeys bool `json:"regen_reality_keys"`
// Anti-DPI transport hardening (cross-protocol).
TLSFragment bool `json:"tls_fragment"`
TLSMin13 bool `json:"tls_min13"`
BlockQUIC bool `json:"block_quic"`
}
ConnectionsUpdate is the full client-facing connection configuration applied in one shot: protocol toggles, link fingerprint, Trojan-WS path, and the Hysteria2 base port / hop range / rotation interval.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager is the application service layer.
func New ¶
func New(st *store.Store, sup *xray.Supervisor, opts xray.Options, tls TLSPaths, operaDir string) *Manager
New builds a Manager. opts carries non-DB generation parameters (e.g. the panel's loopback fallback dest); tls carries the managed cert paths; operaDir is where the opera-proxy helper binary is downloaded/run from.
func (*Manager) AppLogTail ¶
AppLogTail returns the buffered recent panel log lines (for the dashboard).
func (*Manager) ApplyConnections ¶
func (m *Manager) ApplyConnections(u ConnectionsUpdate) error
ApplyConnections validates and persists the whole connection surface, then does a SINGLE reconcile (and one nft hop refresh) — so a multi-field save restarts Xray at most once instead of once per field. The reconcile is a no-op for the Xray process when only link-level fields (fingerprint, interval) changed.
func (*Manager) ApplyRouting ¶
func (m *Manager) ApplyRouting(cfg model.RoutingConfig, warpEnabled, operaEnabled bool, operaCountry string) error
ApplyRouting persists the routing config plus the WARP/Opera on/off state in one shot, then reconciles once. The first WARP enable provisions a free WARP account (Cloudflare device registration) and caches the WireGuard credentials; later toggles reuse them. Enabling Opera downloads + launches the helper for the chosen region.
func (*Manager) BackupManifest ¶
BackupManifest returns a Manifest describing the current server state for inclusion in backup archives.
func (*Manager) CancelTelegramLink ¶ added in v0.2.0
CancelTelegramLink clears the pending one-time link code (cancels a link request).
func (*Manager) CertPinSHA256 ¶
CertPinSHA256 returns the hex SHA-256 of the active leaf certificate, for clients to pin via pinnedPeerCertSha256 when the cert isn't CA-trusted. "" if unavailable.
func (*Manager) ChangeAdminPassword ¶
ChangeAdminPassword hashes and stores a new password for the given admin and lifts the forced-password-change gate (a successful change is exactly what the gate is waiting for).
func (*Manager) Connections ¶
func (m *Manager) Connections(id int64) ([]model.Connection, error)
Connections returns a user's recent source IPs.
func (*Manager) ConnectionsInfo ¶
func (m *Manager) ConnectionsInfo() (*ConnectionsStatus, error)
ConnectionsInfo reports the enabled protocols and their connection parameters, derived from settings.
func (*Manager) CreateUser ¶
CreateUser creates a user (one credential set for all protocols) with optional data limit (bytes, 0=unlimited) and expiry (unix, 0=never), then reconciles.
func (*Manager) DeleteUser ¶
DeleteUser removes a user and reconciles.
func (*Manager) FetchRoutingTemplate ¶
FetchRoutingTemplate returns the body of a routing-template URL WITHOUT ever blocking the caller on a slow remote when a cached copy exists: a fresh entry is returned as-is, a stale one is returned immediately while a refresh runs in the background (stale-while-revalidate). Only a completely cold cache fetches synchronously — and then with a short budget. This is what keeps the Happ/INCY subscription pull from timing out when GitHub is slow: previously a cold/stale cache forced an inline 8s GET, so the whole subscription response hung.
func (*Manager) FinishSetup ¶
FinishSetup marks the first-run wizard as completed.
func (*Manager) GenerateTelegramLinkCode ¶ added in v0.2.0
GenerateTelegramLinkCode issues a fresh one-time linking code and persists it. The operator sends "/start <code>" to the bot once to authorize their chat; the bot burns the code on use. Refused when the bot is disabled — it isn't polling then, so the code could never be redeemed.
func (*Manager) GeoCategories ¶
GeoCategories returns the geosite + geoip category codes from the on-disk databases, parsed once and cached (the .dat files only change on refresh).
func (*Manager) GeoStatus ¶
GeoStatus reports the on-disk state of the geoip/geosite databases (presence, size, last-download time) for the settings UI.
func (*Manager) HasValidCert ¶
HasValidCert reports whether a non-expired, CA-issued certificate is present. A self-signed fallback cert is deliberately treated as "not valid" so the renew loop stays in its fast-retry cadence until a real ACME cert is obtained.
func (*Manager) ListUsers ¶ added in v0.2.0
ListUsers returns all users, newest first (read-only; used by the Telegram bot).
func (*Manager) Location ¶
Location exposes the operator timezone for handlers that compute date ranges.
func (*Manager) MustChangePassword ¶
MustChangePassword reports whether the panel is gated on a forced default-password change. A store error is treated as "not gated" so a transient read failure can't lock the operator out of their own panel.
func (*Manager) OperaHealthy ¶
OperaHealthy reports the last probe result for the Opera lane.
func (*Manager) OperaRunning ¶
OperaRunning reports whether the opera-proxy helper is currently up.
func (*Manager) PollStats ¶
PollStats reads per-user traffic from Xray, accumulates lifetime totals (handling counter resets on Xray restart), and enforces quotas/expiry.
func (*Manager) ProxyCount ¶
ProxyCount reports how many proxies are currently in the pool (parsed from the URL + manual sources).
func (*Manager) Reconcile ¶
Reconcile regenerates the Xray config from current DB state and applies it. Failures are recorded in settings.last_config_error and returned. It serializes with the live user-sync via applyMu.
func (*Manager) RecordAccess ¶
RecordAccess notes a connection from an Xray access-log line (email "uN" + source IP). Throttled to one DB write per user+IP per 10s to absorb bursts.
func (*Manager) RefreshGeo ¶
RefreshGeo re-downloads the geo databases to their latest version, drops the parsed-category cache, and reloads Xray so routing rules pick up the new data.
func (*Manager) RefreshProxies ¶
func (m *Manager) RefreshProxies()
RefreshProxies reloads the pool from current settings and reconciles if it changed. Runs on a timer and right after the routing config is saved.
func (*Manager) RegenerateSecretPath ¶
RegenerateSecretPath issues a fresh random panel path and persists it. The caller is responsible for swapping the live router. Returns the new path.
func (*Manager) RenameUser ¶
RenameUser updates a user's display name. The name is cosmetic (Xray keys users by "u<id>"), so no config reload is needed.
func (*Manager) RenewTLSIfNeeded ¶
RenewTLSIfNeeded renews an ACME cert when near expiry. It reports whether the certificate actually changed (so the caller can reload Xray only then).
func (*Manager) ResetStats ¶
ResetStats clears the entire per-day traffic history.
func (*Manager) ResetTraffic ¶
ResetTraffic zeroes a user's usage and re-enables them. The raw counters are re-baselined to the live Xray value so the next stats poll doesn't re-add the user's whole lifetime total back (see store.ResetTraffic).
func (*Manager) SaveSubSettings ¶
SaveSubSettings validates and persists the subscription delivery settings. The subscription path must be URL-safe and must not shadow the secret panel path or any reserved panel/system segment.
func (*Manager) SaveTelegram ¶ added in v0.2.0
SaveTelegram validates and persists the Telegram bot configuration: the enable flag, bot token, and backup schedule as a 5-field cron expression (empty = no scheduled backups). The authorized chat set and the pending link code are managed separately (linking happens in the bot / via GenerateTelegramLinkCode).
func (*Manager) SeedProxies ¶
func (m *Manager) SeedProxies()
SeedProxies loads the proxy pool synchronously from current settings WITHOUT triggering a reconcile. Called once at startup, before the first reconcile, so Xray comes up a single time with the URL-sourced proxies already in place.
func (*Manager) SetACMETarget ¶
SetACMETarget sets the ACME target (a domain OR an IP address), saves the chosen CA provider (provider = "letsencrypt" | "zerossl"), obtains a certificate, and reloads Xray. host and sni are both set to the target so the cert, the client link address and the SNI all match.
func (*Manager) SetDecoyTemplate ¶
SetDecoyTemplate persists the chosen masquerade template (caller swaps the live decoy handler).
func (*Manager) SetProxyMode ¶
SetProxyMode persists the forward-proxy inbound (proxy mode) and reloads Xray.
func (*Manager) SetResetPeriod ¶
SetResetPeriod sets a user's automatic quota-reset period (none|daily|weekly| monthly|yearly), anchoring the cycle at now.
func (*Manager) SetTimezone ¶
SetTimezone validates and persists the operator's IANA timezone, then updates the cached location so per-day stats re-bucket immediately.
func (*Manager) SetUserEnabled ¶
SetUserEnabled enables/disables a user (manual on/off) and reconciles so the proxy config drops or re-adds them.
func (*Manager) SetUserLimits ¶
SetUserLimits updates a user's quota/expiry and re-enables them.
func (*Manager) SetXrayDNS ¶
SetXrayDNS persists the Xray DNS servers and reloads Xray with the new config.
func (*Manager) StartSysstat ¶
StartSysstat begins sampling host metrics (CPU/RAM/disk/network) and the live VPN throughput for the dashboard. diskPath selects the filesystem reported under "disk".
func (*Manager) StatsByUser ¶
StatsByUser returns per-user totals over the period.
func (*Manager) StatsSeries ¶
StatsSeries returns per-day traffic between from/to (YYYY-MM-DD); userID 0 = all.
func (*Manager) SubscribeAppLogs ¶
SubscribeAppLogs returns a channel of new panel log lines and an unsubscribe.
func (*Manager) SubscribeXrayLogs ¶
SubscribeXrayLogs returns a channel of new Xray log lines and an unsubscribe.
func (*Manager) SystemStatus ¶
func (m *Manager) SystemStatus() (*SystemStatus, error)
SystemStatus assembles the dashboard payload from the host sampler, the Xray supervisor and the user summary.
func (*Manager) TrackVPNViewer ¶
func (m *Manager) TrackVPNViewer() func()
TrackVPNViewer marks one active dashboard-stream subscriber for the life of the returned release func — call `defer mgr.TrackVPNViewer()()`. vpnSpeedLoop only samples Xray (forking `api statsquery` every 3s) while at least one viewer is connected, so an unattended panel costs nothing extra.
func (*Manager) TriggerReconcile ¶
func (m *Manager) TriggerReconcile()
TriggerReconcile requests a FULL config reload (regenerate + restart Xray) for structural changes (protocols, routing, DNS, WARP, TLS, ports). Non-blocking; the reload happens shortly after so the triggering HTTP response flushes first.
func (*Manager) TriggerUserSync ¶
func (m *Manager) TriggerUserSync()
TriggerUserSync requests a live user-set sync (add/remove users via the Xray API, no restart) for user-only changes — far cheaper than a full reload.
func (*Manager) UnlinkTelegramChat ¶ added in v0.2.0
UnlinkTelegramChat removes one authorized chat (revokes its bot access).
func (*Manager) UpdateAdminCredentials ¶
func (m *Manager) UpdateAdminCredentials(adminID int64, currentPassword, username, password, keepToken string) error
UpdateAdminCredentials changes the admin's login and/or password. Empty username or password fields are left unchanged. The current password must be supplied and is re-verified first — a stolen session cookie alone must not be enough to rewrite the credentials. On success every other session for this admin is revoked (the caller's keepToken survives), so a previously stolen cookie can't outlive the change.
func (*Manager) XrayConfig ¶
XrayConfig returns the live on-disk Xray config.json.
func (*Manager) XrayLogTail ¶
XrayLogTail returns the buffered recent Xray log lines.
func (*Manager) XrayStatus ¶
XrayStatus reports whether Xray is running and the unix start time of the current process (which changes on every reload — clients poll it to detect when a config change has finished restarting Xray).
type Summary ¶
type Summary struct {
Users int `json:"users"`
EnabledUsers int `json:"enabled_users"`
TotalUp int64 `json:"total_up"`
TotalDown int64 `json:"total_down"`
TrafficToday int64 `json:"traffic_today"` // up+down for the current local-time day
XrayRunning bool `json:"xray_running"`
CertDaysLeft int `json:"cert_days_left"`
}
Summary is the dashboard overview.
type SystemStatus ¶
type SystemStatus struct {
sysstat.Stats
XrayRunning bool `json:"xray_running"`
XrayUptime int64 `json:"xray_uptime"` // seconds
XrayVersion string `json:"xray_version"`
Goroutines int `json:"goroutines"`
CPUCores int `json:"cpu_cores"`
ProcMem int64 `json:"proc_mem"` // panel process RSS
VPNUp int64 `json:"vpn_up"` // VPN client throughput (bytes/sec)
VPNDown int64 `json:"vpn_down"`
TotalUp int64 `json:"total_up"`
TotalDown int64 `json:"total_down"`
Users int `json:"users"`
EnabledUsers int `json:"enabled_users"`
TrafficToday int64 `json:"traffic_today"`
CertDaysLeft int `json:"cert_days_left"`
}
SystemStatus is the full dashboard payload: host resources plus Xray/panel state.
type TLSStatus ¶
type TLSStatus struct {
Mode string `json:"mode"`
Domain string `json:"domain"`
SNI string `json:"sni"`
ACMEEmail string `json:"acme_email"`
ACMEProvider string `json:"acme_provider"`
Cert *tlsutil.CertInfo `json:"cert"`
}
TLSStatus is the current TLS configuration plus active cert metadata.
type ValidationError ¶
type ValidationError struct{ Msg string }
ValidationError marks an error caused by bad operator input rather than a server fault. The server layer maps it to HTTP 400 (vs 500 for everything else); its message is operator-facing (Russian) and safe to show in the UI.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string