diff options
Diffstat (limited to 'database')
| -rw-r--r-- | database/db.go | 11 | ||||
| -rw-r--r-- | database/model/model.go | 76 |
2 files changed, 55 insertions, 32 deletions
diff --git a/database/db.go b/database/db.go index 8414b118..6de81d79 100644 --- a/database/db.go +++ b/database/db.go @@ -1,3 +1,5 @@ +// Package database provides database initialization, migration, and management utilities +// for the 3x-ui panel using GORM with SQLite. package database import ( @@ -45,6 +47,7 @@ func initModels() error { return nil } +// initUser creates a default admin user if the users table is empty. func initUser() error { empty, err := isTableEmpty("users") if err != nil { @@ -68,6 +71,7 @@ func initUser() error { return nil } +// runSeeders migrates user passwords to bcrypt and records seeder execution to prevent re-running. func runSeeders(isUsersEmpty bool) error { empty, err := isTableEmpty("history_of_seeders") if err != nil { @@ -107,12 +111,14 @@ func runSeeders(isUsersEmpty bool) error { return nil } +// isTableEmpty returns true if the named table contains zero rows. func isTableEmpty(tableName string) (bool, error) { var count int64 err := db.Table(tableName).Count(&count).Error return count == 0, err } +// InitDB sets up the database connection, migrates models, and runs seeders. func InitDB(dbPath string) error { dir := path.Dir(dbPath) err := os.MkdirAll(dir, fs.ModePerm) @@ -151,6 +157,7 @@ func InitDB(dbPath string) error { return runSeeders(isUsersEmpty) } +// CloseDB closes the database connection if it exists. func CloseDB() error { if db != nil { sqlDB, err := db.DB() @@ -162,14 +169,17 @@ func CloseDB() error { return nil } +// GetDB returns the global GORM database instance. func GetDB() *gorm.DB { return db } +// IsNotFound checks if the given error is a GORM record not found error. func IsNotFound(err error) bool { return err == gorm.ErrRecordNotFound } +// IsSQLiteDB checks if the given file is a valid SQLite database by reading its signature. func IsSQLiteDB(file io.ReaderAt) (bool, error) { signature := []byte("SQLite format 3\x00") buf := make([]byte, len(signature)) @@ -180,6 +190,7 @@ func IsSQLiteDB(file io.ReaderAt) (bool, error) { return bytes.Equal(buf, signature), nil } +// Checkpoint performs a WAL checkpoint on the SQLite database to ensure data consistency. func Checkpoint() error { // Update WAL err := db.Exec("PRAGMA wal_checkpoint;").Error diff --git a/database/model/model.go b/database/model/model.go index abf8075c..720f0223 100644 --- a/database/model/model.go +++ b/database/model/model.go @@ -1,3 +1,4 @@ +// Package model defines the database models and data structures used by the 3x-ui panel. package model import ( @@ -7,8 +8,10 @@ import ( "github.com/mhsanaei/3x-ui/v2/xray" ) +// Protocol represents the protocol type for Xray inbounds. type Protocol string +// Protocol constants for different Xray inbound protocols const ( VMESS Protocol = "vmess" VLESS Protocol = "vless" @@ -20,27 +23,29 @@ const ( WireGuard Protocol = "wireguard" ) +// User represents a user account in the 3x-ui panel. type User struct { Id int `json:"id" gorm:"primaryKey;autoIncrement"` Username string `json:"username"` Password string `json:"password"` } +// Inbound represents an Xray inbound configuration with traffic statistics and settings. type Inbound struct { - Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"` - UserId int `json:"-"` - Up int64 `json:"up" form:"up"` - Down int64 `json:"down" form:"down"` - Total int64 `json:"total" form:"total"` - AllTime int64 `json:"allTime" form:"allTime" gorm:"default:0"` - Remark string `json:"remark" form:"remark"` - Enable bool `json:"enable" form:"enable" gorm:"index:idx_enable_traffic_reset,priority:1"` - ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` - TrafficReset string `json:"trafficReset" form:"trafficReset" gorm:"default:never;index:idx_enable_traffic_reset,priority:2"` - LastTrafficResetTime int64 `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"` - ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"` + Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"` // Unique identifier + UserId int `json:"-"` // Associated user ID + Up int64 `json:"up" form:"up"` // Upload traffic in bytes + Down int64 `json:"down" form:"down"` // Download traffic in bytes + Total int64 `json:"total" form:"total"` // Total traffic limit in bytes + AllTime int64 `json:"allTime" form:"allTime" gorm:"default:0"` // All-time traffic usage + Remark string `json:"remark" form:"remark"` // Human-readable remark + Enable bool `json:"enable" form:"enable" gorm:"index:idx_enable_traffic_reset,priority:1"` // Whether the inbound is enabled + ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` // Expiration timestamp + TrafficReset string `json:"trafficReset" form:"trafficReset" gorm:"default:never;index:idx_enable_traffic_reset,priority:2"` // Traffic reset schedule + LastTrafficResetTime int64 `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"` // Last traffic reset timestamp + ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"` // Client traffic statistics - // config part + // Xray configuration fields Listen string `json:"listen" form:"listen"` Port int `json:"port" form:"port"` Protocol Protocol `json:"protocol" form:"protocol"` @@ -50,6 +55,7 @@ type Inbound struct { Sniffing string `json:"sniffing" form:"sniffing"` } +// OutboundTraffics tracks traffic statistics for Xray outbound connections. type OutboundTraffics struct { Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"` Tag string `json:"tag" form:"tag" gorm:"unique"` @@ -58,17 +64,20 @@ type OutboundTraffics struct { Total int64 `json:"total" form:"total" gorm:"default:0"` } +// InboundClientIps stores IP addresses associated with inbound clients for access control. type InboundClientIps struct { Id int `json:"id" gorm:"primaryKey;autoIncrement"` ClientEmail string `json:"clientEmail" form:"clientEmail" gorm:"unique"` Ips string `json:"ips" form:"ips"` } +// HistoryOfSeeders tracks which database seeders have been executed to prevent re-running. type HistoryOfSeeders struct { Id int `json:"id" gorm:"primaryKey;autoIncrement"` SeederName string `json:"seederName"` } +// GenXrayInboundConfig generates an Xray inbound configuration from the Inbound model. func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig { listen := i.Listen if listen != "" { @@ -85,33 +94,36 @@ func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig { } } +// Setting stores key-value configuration settings for the 3x-ui panel. type Setting struct { Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"` Key string `json:"key" form:"key"` Value string `json:"value" form:"value"` } +// Client represents a client configuration for Xray inbounds with traffic limits and settings. type Client struct { - ID string `json:"id"` - Security string `json:"security"` - Password string `json:"password"` - Flow string `json:"flow"` - Email string `json:"email"` - LimitIP int `json:"limitIp"` - TotalGB int64 `json:"totalGB" form:"totalGB"` - ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` - Enable bool `json:"enable" form:"enable"` - TgID int64 `json:"tgId" form:"tgId"` - SubID string `json:"subId" form:"subId"` - Comment string `json:"comment" form:"comment"` - Reset int `json:"reset" form:"reset"` - CreatedAt int64 `json:"created_at,omitempty"` - UpdatedAt int64 `json:"updated_at,omitempty"` + ID string `json:"id"` // Unique client identifier + Security string `json:"security"` // Security method (e.g., "auto", "aes-128-gcm") + Password string `json:"password"` // Client password + Flow string `json:"flow"` // Flow control (XTLS) + Email string `json:"email"` // Client email identifier + LimitIP int `json:"limitIp"` // IP limit for this client + TotalGB int64 `json:"totalGB" form:"totalGB"` // Total traffic limit in GB + ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` // Expiration timestamp + Enable bool `json:"enable" form:"enable"` // Whether the client is enabled + TgID int64 `json:"tgId" form:"tgId"` // Telegram user ID for notifications + SubID string `json:"subId" form:"subId"` // Subscription identifier + Comment string `json:"comment" form:"comment"` // Client comment + Reset int `json:"reset" form:"reset"` // Reset period in days + CreatedAt int64 `json:"created_at,omitempty"` // Creation timestamp + UpdatedAt int64 `json:"updated_at,omitempty"` // Last update timestamp } +// VLESSSettings contains VLESS protocol-specific configuration settings. type VLESSSettings struct { - Clients []Client `json:"clients"` - Decryption string `json:"decryption"` - Encryption string `json:"encryption"` - Fallbacks []any `json:"fallbacks"` + Clients []Client `json:"clients"` // List of VLESS clients + Decryption string `json:"decryption"` // Decryption method + Encryption string `json:"encryption"` // Encryption method (usually "none" for VLESS) + Fallbacks []any `json:"fallbacks"` // Fallback configurations } |
