diff options
| author | mhsanaei <ho3ein.sanaei@gmail.com> | 2025-09-20 10:35:50 +0300 |
|---|---|---|
| committer | mhsanaei <ho3ein.sanaei@gmail.com> | 2025-09-20 10:35:50 +0300 |
| commit | 6ced549deaecb42b9bb93ea9efcb4c1bbaabe8a4 (patch) | |
| tree | 28d8d82530476cf607e4d05ca189ae05868711e6 | |
| parent | f60682a6b7cb749fee403c84e2587c3ad7e7ced0 (diff) | |
docs: add comments for all functions
63 files changed, 624 insertions, 113 deletions
diff --git a/config/config.go b/config/config.go index d5fe65ff..c9a3e83c 100644 --- a/config/config.go +++ b/config/config.go @@ -1,3 +1,5 @@ +// Package config provides configuration management utilities for the 3x-ui panel, +// including version information, logging levels, database paths, and environment variable handling. package config import ( @@ -16,8 +18,10 @@ var version string //go:embed name var name string +// LogLevel represents the logging level for the application. type LogLevel string +// Logging level constants const ( Debug LogLevel = "debug" Info LogLevel = "info" @@ -26,14 +30,17 @@ const ( Error LogLevel = "error" ) +// GetVersion returns the version string of the 3x-ui application. func GetVersion() string { return strings.TrimSpace(version) } +// GetName returns the name of the 3x-ui application. func GetName() string { return strings.TrimSpace(name) } +// GetLogLevel returns the current logging level based on environment variables or defaults to Info. func GetLogLevel() LogLevel { if IsDebug() { return Debug @@ -45,10 +52,12 @@ func GetLogLevel() LogLevel { return LogLevel(logLevel) } +// IsDebug returns true if debug mode is enabled via the XUI_DEBUG environment variable. func IsDebug() bool { return os.Getenv("XUI_DEBUG") == "true" } +// GetBinFolderPath returns the path to the binary folder, defaulting to "bin" if not set via XUI_BIN_FOLDER. func GetBinFolderPath() string { binFolderPath := os.Getenv("XUI_BIN_FOLDER") if binFolderPath == "" { @@ -74,6 +83,7 @@ func getBaseDir() string { return exeDir } +// GetDBFolderPath returns the path to the database folder based on environment variables or platform defaults. func GetDBFolderPath() string { dbFolderPath := os.Getenv("XUI_DB_FOLDER") if dbFolderPath != "" { @@ -85,10 +95,12 @@ func GetDBFolderPath() string { return "/etc/x-ui" } +// GetDBPath returns the full path to the database file. func GetDBPath() string { return fmt.Sprintf("%s/%s.db", GetDBFolderPath(), GetName()) } +// GetLogFolder returns the path to the log folder based on environment variables or platform defaults. func GetLogFolder() string { logFolderPath := os.Getenv("XUI_LOG_FOLDER") if logFolderPath != "" { 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 } diff --git a/logger/logger.go b/logger/logger.go index 3705c3df..ccacf697 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,3 +1,5 @@ +// Package logger provides logging functionality for the 3x-ui panel with +// buffered log storage and multiple log levels. package logger import ( @@ -9,7 +11,11 @@ import ( ) var ( - logger *logging.Logger + logger *logging.Logger + + // addToBuffer appends a log entry into the in-memory ring buffer used for + // retrieving recent logs via the web UI. It keeps the buffer bounded to avoid + // uncontrolled growth. logBuffer []struct { time string level logging.Level @@ -21,6 +27,7 @@ func init() { InitLogger(logging.INFO) } +// InitLogger initializes the logger with the specified logging level. func InitLogger(level logging.Level) { newLogger := logging.MustGetLogger("x-ui") var err error @@ -47,51 +54,61 @@ func InitLogger(level logging.Level) { logger = newLogger } +// Debug logs a debug message and adds it to the log buffer. func Debug(args ...any) { logger.Debug(args...) addToBuffer("DEBUG", fmt.Sprint(args...)) } +// Debugf logs a formatted debug message and adds it to the log buffer. func Debugf(format string, args ...any) { logger.Debugf(format, args...) addToBuffer("DEBUG", fmt.Sprintf(format, args...)) } +// Info logs an info message and adds it to the log buffer. func Info(args ...any) { logger.Info(args...) addToBuffer("INFO", fmt.Sprint(args...)) } +// Infof logs a formatted info message and adds it to the log buffer. func Infof(format string, args ...any) { logger.Infof(format, args...) addToBuffer("INFO", fmt.Sprintf(format, args...)) } +// Notice logs a notice message and adds it to the log buffer. func Notice(args ...any) { logger.Notice(args...) addToBuffer("NOTICE", fmt.Sprint(args...)) } +// Noticef logs a formatted notice message and adds it to the log buffer. func Noticef(format string, args ...any) { logger.Noticef(format, args...) addToBuffer("NOTICE", fmt.Sprintf(format, args...)) } +// Warning logs a warning message and adds it to the log buffer. func Warning(args ...any) { logger.Warning(args...) addToBuffer("WARNING", fmt.Sprint(args...)) } +// Warningf logs a formatted warning message and adds it to the log buffer. func Warningf(format string, args ...any) { logger.Warningf(format, args...) addToBuffer("WARNING", fmt.Sprintf(format, args...)) } +// Error logs an error message and adds it to the log buffer. func Error(args ...any) { logger.Error(args...) addToBuffer("ERROR", fmt.Sprint(args...)) } +// Errorf logs a formatted error message and adds it to the log buffer. func Errorf(format string, args ...any) { logger.Errorf(format, args...) addToBuffer("ERROR", fmt.Sprintf(format, args...)) @@ -115,6 +132,7 @@ func addToBuffer(level string, newLog string) { }) } +// GetLogs retrieves up to c log entries from the buffer that are at or below the specified level. func GetLogs(c int, level string) []string { var output []string logLevel, _ := logging.LogLevel(level) @@ -1,3 +1,5 @@ +// Package main is the entry point for the 3x-ui web panel application. +// It initializes the database, web server, and handles command-line operations for managing the panel. package main import ( @@ -22,6 +24,7 @@ import ( "github.com/op/go-logging" ) +// runWebServer initializes and starts the web server for the 3x-ui panel. func runWebServer() { log.Printf("Starting %v %v", config.GetName(), config.GetVersion()) @@ -111,6 +114,7 @@ func runWebServer() { } } +// resetSetting resets all panel settings to their default values. func resetSetting() { err := database.InitDB(config.GetDBPath()) if err != nil { @@ -127,6 +131,7 @@ func resetSetting() { } } +// showSetting displays the current panel settings if show is true. func showSetting(show bool) { if show { settingService := service.SettingService{} @@ -176,6 +181,7 @@ func showSetting(show bool) { } } +// updateTgbotEnableSts enables or disables the Telegram bot notifications based on the status parameter. func updateTgbotEnableSts(status bool) { settingService := service.SettingService{} currentTgSts, err := settingService.GetTgbotEnabled() @@ -195,6 +201,7 @@ func updateTgbotEnableSts(status bool) { } } +// updateTgbotSetting updates Telegram bot settings including token, chat ID, and runtime schedule. func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) { err := database.InitDB(config.GetDBPath()) if err != nil { @@ -232,6 +239,7 @@ func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime stri } } +// updateSetting updates various panel settings including port, credentials, base path, listen IP, and two-factor authentication. func updateSetting(port int, username string, password string, webBasePath string, listenIP string, resetTwoFactor bool) { err := database.InitDB(config.GetDBPath()) if err != nil { @@ -290,6 +298,7 @@ func updateSetting(port int, username string, password string, webBasePath strin } } +// updateCert updates the SSL certificate files for the panel. func updateCert(publicKey string, privateKey string) { err := database.InitDB(config.GetDBPath()) if err != nil { @@ -317,6 +326,7 @@ func updateCert(publicKey string, privateKey string) { } } +// GetCertificate displays the current SSL certificate settings if getCert is true. func GetCertificate(getCert bool) { if getCert { settingService := service.SettingService{} @@ -334,6 +344,7 @@ func GetCertificate(getCert bool) { } } +// GetListenIP displays the current panel listen IP address if getListen is true. func GetListenIP(getListen bool) { if getListen { @@ -348,6 +359,7 @@ func GetListenIP(getListen bool) { } } +// migrateDb performs database migration operations for the 3x-ui panel. func migrateDb() { inboundService := service.InboundService{} @@ -360,6 +372,8 @@ func migrateDb() { fmt.Println("Migration done!") } +// main is the entry point of the 3x-ui application. +// It parses command-line arguments to run the web server, migrate database, or update settings. func main() { if len(os.Args) < 2 { |
