Files

298 lines
8.9 KiB
Go

package models
import (
"time"
"github.com/google/uuid"
)
type User struct {
ID uuid.UUID `json:"id"`
Email string `json:"email"`
PasswordHash string `json:"-"`
Name string `json:"name"`
Role string `json:"role"`
CreatedAt time.Time `json:"created_at"`
}
type Protocol struct {
ID uuid.UUID `json:"id"`
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description"`
Port int `json:"port"`
Enabled bool `json:"enabled"`
SortOrder int `json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
InstalledOn []NodeProtoRef `json:"installed_on,omitempty"`
EnabledOn []NodeProtoRef `json:"enabled_on,omitempty"`
}
type NodeProtoRef struct {
NodeID uuid.UUID `json:"node_id"`
NodeName string `json:"node_name"`
Host string `json:"host"`
Status NodeStatus `json:"status"`
}
type NodeProtocol struct {
NodeID uuid.UUID `json:"node_id"`
ProtocolID uuid.UUID `json:"protocol_id"`
ProtocolCode string `json:"protocol_code"`
ProtocolName string `json:"protocol_name"`
Port int `json:"port"`
Installed bool `json:"installed"`
Enabled bool `json:"enabled"`
UpdatedAt time.Time `json:"updated_at"`
}
func (p Protocol) EnabledLabel() string {
if p.Enabled {
return "Включён"
}
return "Выключен"
}
func (p Protocol) InstallCount() int { return len(p.InstalledOn) }
func (p Protocol) ActiveCount() int { return len(p.EnabledOn) }
type NodeStatus string
const (
NodeStatusPending NodeStatus = "pending"
NodeStatusInstalling NodeStatus = "installing"
NodeStatusOnline NodeStatus = "online"
NodeStatusOffline NodeStatus = "offline"
NodeStatusError NodeStatus = "error"
)
type Node struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Host string `json:"host"`
SSHPort int `json:"ssh_port"`
SSHUser string `json:"ssh_user"`
SSHAuthType string `json:"ssh_auth_type"` // password | key
SSHSecretEnc string `json:"-"`
NodePort int `json:"node_port"`
SecretKey string `json:"-"`
ProfileID *uuid.UUID `json:"profile_id,omitempty"`
ProfileName string `json:"profile_name,omitempty"`
Status NodeStatus `json:"status"`
InstallMode string `json:"install_mode"` // auto | manual
LastError string `json:"last_error"`
InstallLog string `json:"install_log"`
RuntimeLog string `json:"runtime_log"`
AgentVersion string `json:"agent_version"`
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
func (n Node) StatusLabel() string {
switch n.Status {
case NodeStatusOnline:
return "Online"
case NodeStatusInstalling:
return "Установка"
case NodeStatusOffline:
return "Offline"
case NodeStatusError:
return "Ошибка"
default:
return "Ожидание"
}
}
func (n Node) ProfileIDString() string {
if n.ProfileID == nil {
return ""
}
return n.ProfileID.String()
}
type ConfigProfile struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
InboundCount int `json:"inbound_count"`
NodeCount int `json:"node_count"`
Inbounds []Inbound `json:"inbounds,omitempty"`
}
type Inbound struct {
ID uuid.UUID `json:"id"`
ProfileID uuid.UUID `json:"profile_id"`
Tag string `json:"tag"`
ProtocolID uuid.UUID `json:"protocol_id"`
ProtocolCode string `json:"protocol_code"`
ProtocolName string `json:"protocol_name"`
Port int `json:"port"`
Network string `json:"network"` // tcp, ws, grpc, quic, udp
Security string `json:"security"` // none, tls, reality
Listen string `json:"listen"`
Enabled bool `json:"enabled"` // definition enabled in profile
SortOrder int `json:"sort_order"`
Remark string `json:"remark"`
// Transport / TLS / Reality / SS settings
Path string `json:"path"`
Host string `json:"host"`
SNI string `json:"sni"`
Fingerprint string `json:"fingerprint"`
Flow string `json:"flow"`
ALPN string `json:"alpn"`
RealityDest string `json:"reality_dest"`
RealityServerNames string `json:"reality_server_names"`
RealityPrivateKey string `json:"reality_private_key"`
RealityPublicKey string `json:"reality_public_key"`
RealityShortID string `json:"reality_short_id"`
RealityShortIDs string `json:"reality_short_ids"`
SpiderX string `json:"spider_x"`
RealityXver int `json:"reality_xver"`
SSMethod string `json:"ss_method"`
Password string `json:"password"`
FallbackDest string `json:"fallback_dest"`
FallbacksJSON string `json:"fallbacks_json"`
TLSCertPEM string `json:"tls_cert_pem"`
TLSKeyPEM string `json:"tls_key_pem"`
Sniffing bool `json:"sniffing"`
SniffingRouteOnly bool `json:"sniffing_route_only"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Per-node activation when listed under a node
NodeEnabled bool `json:"node_enabled,omitempty"`
}
type DashboardStats struct {
ProtocolsTotal int
ProtocolsEnabled int
AdminsTotal int
NodesTotal int
NodesOnline int
ProfilesTotal int
ClientsTotal int
ClientsActive int
}
type ClientStatus string
const (
ClientStatusActive ClientStatus = "active"
ClientStatusDisabled ClientStatus = "disabled"
ClientStatusExpired ClientStatus = "expired"
)
type Client struct {
ID uuid.UUID `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
UUID uuid.UUID `json:"uuid"` // VLESS/VMess user id
Status ClientStatus `json:"status"`
TrafficLimitBytes int64 `json:"traffic_limit_bytes"` // 0 = unlimited
TrafficUsedBytes int64 `json:"traffic_used_bytes"`
ExpireAt *time.Time `json:"expire_at,omitempty"`
SubToken string `json:"sub_token"`
Note string `json:"note"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
InboundIDs []uuid.UUID `json:"inbound_ids,omitempty"`
InboundCount int `json:"inbound_count"`
}
func (c Client) StatusLabel() string {
switch c.Status {
case ClientStatusActive:
return "Активен"
case ClientStatusDisabled:
return "Отключён"
case ClientStatusExpired:
return "Истёк"
default:
return string(c.Status)
}
}
func (c Client) IsActive() bool {
if c.Status != ClientStatusActive {
return false
}
if c.ExpireAt != nil && time.Now().After(*c.ExpireAt) {
return false
}
if c.TrafficLimitBytes > 0 && c.TrafficUsedBytes >= c.TrafficLimitBytes {
return false
}
return true
}
func (c Client) TrafficLimitGB() float64 {
if c.TrafficLimitBytes <= 0 {
return 0
}
return float64(c.TrafficLimitBytes) / (1024 * 1024 * 1024)
}
func (c Client) HasInbound(id uuid.UUID) bool {
for _, x := range c.InboundIDs {
if x == id {
return true
}
}
return false
}
// SubHost is one subscription endpoint (inbound on a node), Remnawave-style host.
type SubHost struct {
InboundID uuid.UUID `json:"inbound_id"`
Tag string `json:"tag"`
Remark string `json:"remark"`
ProtocolCode string `json:"protocol"`
ProtocolName string `json:"protocol_name"`
Port int `json:"port"`
Network string `json:"network"`
Security string `json:"security"`
Path string `json:"path,omitempty"`
HostHeader string `json:"host_header,omitempty"`
SNI string `json:"sni,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Flow string `json:"flow,omitempty"`
ALPN string `json:"alpn,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ShortID string `json:"short_id,omitempty"`
SpiderX string `json:"spider_x,omitempty"`
SSMethod string `json:"ss_method,omitempty"`
Password string `json:"password,omitempty"`
Address string `json:"address"`
NodeName string `json:"node_name"`
NodeOnline bool `json:"node_online"`
Available bool `json:"available"`
Link string `json:"link"`
}
func (h SubHost) Title() string {
if h.Remark != "" {
return h.Remark
}
if h.NodeName != "" {
return h.Tag + " · " + h.NodeName
}
return h.Tag
}
type SubscriptionInfo struct {
Client Client `json:"client"`
Hosts []SubHost `json:"hosts"`
Links []string `json:"links"`
ExpireUnix int64 `json:"expire_unix"`
}