Add VPN client users with inbound access and subscription links.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-29 04:49:32 +03:00
co-authored by Cursor
parent 4991b313d7
commit c0e78ce949
16 changed files with 930 additions and 11 deletions
+70
View File
@@ -154,4 +154,74 @@ type DashboardStats struct {
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
}