3x-ui/main.go

720 lines
20 KiB
Go
Raw Normal View History

2025-09-20 07:35:50 +00:00
// 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.
2023-02-09 19:18:06 +00:00
package main
import (
"encoding/json"
"flag"
2023-02-09 19:18:06 +00:00
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
2023-02-09 19:18:06 +00:00
"syscall"
_ "unsafe"
2025-09-19 08:05:43 +00:00
"github.com/mhsanaei/3x-ui/v2/config"
"github.com/mhsanaei/3x-ui/v2/database"
"github.com/mhsanaei/3x-ui/v2/logger"
"github.com/mhsanaei/3x-ui/v2/sub"
"github.com/mhsanaei/3x-ui/v2/util/crypto"
2026-02-20 01:07:46 +00:00
"github.com/mhsanaei/3x-ui/v2/util/sys"
2025-09-19 08:05:43 +00:00
"github.com/mhsanaei/3x-ui/v2/web"
"github.com/mhsanaei/3x-ui/v2/web/entity"
2025-09-19 08:05:43 +00:00
"github.com/mhsanaei/3x-ui/v2/web/global"
"github.com/mhsanaei/3x-ui/v2/web/service"
2023-02-09 19:18:06 +00:00
2025-05-17 10:33:22 +00:00
"github.com/joho/godotenv"
2023-02-09 19:18:06 +00:00
"github.com/op/go-logging"
)
2025-09-20 07:35:50 +00:00
// runWebServer initializes and starts the web server for the 3x-ui panel.
2023-02-09 19:18:06 +00:00
func runWebServer() {
2024-07-08 21:08:00 +00:00
log.Printf("Starting %v %v", config.GetName(), config.GetVersion())
2023-02-09 19:18:06 +00:00
switch config.GetLogLevel() {
case config.Debug:
logger.InitLogger(logging.DEBUG)
case config.Info:
logger.InitLogger(logging.INFO)
2023-06-16 14:55:33 +00:00
case config.Notice:
logger.InitLogger(logging.NOTICE)
case config.Warning:
2023-02-09 19:18:06 +00:00
logger.InitLogger(logging.WARNING)
case config.Error:
logger.InitLogger(logging.ERROR)
default:
2024-07-08 21:08:00 +00:00
log.Fatalf("Unknown log level: %v", config.GetLogLevel())
2023-02-09 19:18:06 +00:00
}
2025-05-17 10:33:22 +00:00
godotenv.Load()
err := database.InitDB()
2023-02-09 19:18:06 +00:00
if err != nil {
2024-07-08 21:08:00 +00:00
log.Fatalf("Error initializing database: %v", err)
2023-02-09 19:18:06 +00:00
}
var server *web.Server
server = web.NewServer()
global.SetWebServer(server)
err = server.Start()
if err != nil {
2024-07-08 21:08:00 +00:00
log.Fatalf("Error starting web server: %v", err)
2023-02-09 19:18:06 +00:00
return
}
2023-05-22 18:21:52 +00:00
var subServer *sub.Server
subServer = sub.NewServer()
global.SetSubServer(subServer)
err = subServer.Start()
if err != nil {
2024-07-08 21:08:00 +00:00
log.Fatalf("Error starting sub server: %v", err)
2023-05-22 18:21:52 +00:00
return
}
2023-02-09 19:18:06 +00:00
sigCh := make(chan os.Signal, 1)
// Trap shutdown signals
2026-02-20 01:07:46 +00:00
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGTERM, sys.SIGUSR1)
2023-02-09 19:18:06 +00:00
for {
sig := <-sigCh
switch sig {
case syscall.SIGHUP:
2024-07-08 21:08:00 +00:00
logger.Info("Received SIGHUP signal. Restarting servers...")
// --- FIX FOR TELEGRAM BOT CONFLICT (409): Stop bot before restart ---
service.StopBot()
// --
2023-02-09 19:18:06 +00:00
err := server.Stop()
if err != nil {
2024-08-08 15:40:26 +00:00
logger.Debug("Error stopping web server:", err)
2023-02-09 19:18:06 +00:00
}
2023-05-22 18:21:52 +00:00
err = subServer.Stop()
if err != nil {
2024-08-08 15:40:26 +00:00
logger.Debug("Error stopping sub server:", err)
2023-05-22 18:21:52 +00:00
}
2023-02-09 19:18:06 +00:00
server = web.NewServer()
global.SetWebServer(server)
err = server.Start()
if err != nil {
2024-07-08 21:08:00 +00:00
log.Fatalf("Error restarting web server: %v", err)
2023-02-09 19:18:06 +00:00
return
}
2024-07-08 21:08:00 +00:00
log.Println("Web server restarted successfully.")
2023-05-22 18:21:52 +00:00
subServer = sub.NewServer()
global.SetSubServer(subServer)
err = subServer.Start()
if err != nil {
2024-07-08 21:08:00 +00:00
log.Fatalf("Error restarting sub server: %v", err)
2023-05-22 18:21:52 +00:00
return
}
2024-07-08 21:08:00 +00:00
log.Println("Sub server restarted successfully.")
2026-02-20 01:07:46 +00:00
case sys.SIGUSR1:
logger.Info("Received USR1 signal, restarting xray-core...")
err := server.RestartXray()
if err != nil {
logger.Error("Failed to restart xray-core:", err)
}
2024-07-08 21:08:00 +00:00
2023-02-09 19:18:06 +00:00
default:
// --- FIX FOR TELEGRAM BOT CONFLICT (409) on full shutdown ---
service.StopBot()
// ------------------------------------------------------------
server.Stop()
2023-05-22 18:21:52 +00:00
subServer.Stop()
2024-07-08 21:08:00 +00:00
log.Println("Shutting down servers.")
2023-02-09 19:18:06 +00:00
return
}
}
}
2025-09-20 07:35:50 +00:00
// resetSetting resets all panel settings to their default values.
2023-02-09 19:18:06 +00:00
func resetSetting() {
err := database.InitDB()
2023-02-09 19:18:06 +00:00
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Failed to initialize database:", err)
2023-02-09 19:18:06 +00:00
return
}
settingService := service.SettingService{}
err = settingService.ResetSettings()
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Failed to reset settings:", err)
2023-02-09 19:18:06 +00:00
} else {
2024-07-08 21:08:00 +00:00
fmt.Println("Settings successfully reset.")
2023-02-09 19:18:06 +00:00
}
}
2025-09-20 07:35:50 +00:00
// showSetting displays the current panel settings if show is true.
2023-02-09 19:18:06 +00:00
func showSetting(show bool) {
if show {
settingService := service.SettingService{}
port, err := settingService.GetPort()
if err != nil {
fmt.Println("get current port failed, error info:", err)
2023-02-09 19:18:06 +00:00
}
subPort, err := settingService.GetSubPort()
if err != nil {
fmt.Println("get current sub port failed, error info:", err)
}
webBasePath, err := settingService.GetBasePath()
if err != nil {
fmt.Println("get webBasePath failed, error info:", err)
}
listen, err := settingService.GetListen()
if err != nil {
fmt.Println("get current listen failed, error info:", err)
}
subListen, err := settingService.GetSubListen()
if err != nil {
fmt.Println("get current sub listen failed, error info:", err)
}
2024-10-30 19:26:37 +00:00
certFile, err := settingService.GetCertFile()
if err != nil {
fmt.Println("get cert file failed, error info:", err)
}
keyFile, err := settingService.GetKeyFile()
if err != nil {
fmt.Println("get key file failed, error info:", err)
}
2023-02-09 19:18:06 +00:00
userService := service.UserService{}
userModel, err := userService.GetFirstUser()
if err != nil {
fmt.Println("get current user info failed, error info:", err)
2023-02-09 19:18:06 +00:00
}
if userModel.Username == "" || userModel.Password == "" {
2023-02-09 19:18:06 +00:00
fmt.Println("current username or password is empty")
}
2023-04-14 13:52:49 +00:00
fmt.Println("current panel settings as follows:")
2024-10-30 19:26:37 +00:00
if certFile == "" || keyFile == "" {
fmt.Println("Warning: Panel is not secure with SSL")
} else {
fmt.Println("Panel is secure with SSL")
}
hasDefaultCredential := func() bool {
return userModel.Username == "admin" && crypto.CheckPasswordHash(userModel.Password, "admin")
}()
fmt.Println("hasDefaultCredential:", hasDefaultCredential)
2023-02-09 19:18:06 +00:00
fmt.Println("port:", port)
fmt.Println("listen:", listen)
fmt.Println("subPort:", subPort)
fmt.Println("subListen:", subListen)
2024-10-30 19:26:37 +00:00
fmt.Println("webBasePath:", webBasePath)
2023-02-09 19:18:06 +00:00
}
}
2025-09-20 07:35:50 +00:00
// updateTgbotEnableSts enables or disables the Telegram bot notifications based on the status parameter.
2023-02-09 19:18:06 +00:00
func updateTgbotEnableSts(status bool) {
settingService := service.SettingService{}
2024-07-07 09:55:59 +00:00
currentTgSts, err := settingService.GetTgbotEnabled()
2023-02-09 19:18:06 +00:00
if err != nil {
fmt.Println(err)
return
}
logger.Infof("current enabletgbot status[%v],need update to status[%v]", currentTgSts, status)
if currentTgSts != status {
2024-07-07 09:55:59 +00:00
err := settingService.SetTgbotEnabled(status)
2023-02-09 19:18:06 +00:00
if err != nil {
fmt.Println(err)
return
} else {
2024-07-07 09:55:59 +00:00
logger.Infof("SetTgbotEnabled[%v] success", status)
2023-02-09 19:18:06 +00:00
}
}
}
2025-09-20 07:35:50 +00:00
// updateTgbotSetting updates Telegram bot settings including token, chat ID, and runtime schedule.
2023-03-17 16:07:49 +00:00
func updateTgbotSetting(tgBotToken string, tgBotChatid string, tgBotRuntime string) {
err := database.InitDB()
2023-02-09 19:18:06 +00:00
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Error initializing database:", err)
2023-02-09 19:18:06 +00:00
return
}
settingService := service.SettingService{}
if tgBotToken != "" {
err := settingService.SetTgBotToken(tgBotToken)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Printf("Error setting Telegram bot token: %v\n", err)
2023-02-09 19:18:06 +00:00
return
}
2024-07-08 21:08:00 +00:00
logger.Info("Successfully updated Telegram bot token.")
2023-02-09 19:18:06 +00:00
}
if tgBotRuntime != "" {
err := settingService.SetTgbotRuntime(tgBotRuntime)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Printf("Error setting Telegram bot runtime: %v\n", err)
2023-02-09 19:18:06 +00:00
return
}
2024-07-08 21:08:00 +00:00
logger.Infof("Successfully updated Telegram bot runtime to [%s].", tgBotRuntime)
2023-02-09 19:18:06 +00:00
}
2023-03-17 16:07:49 +00:00
if tgBotChatid != "" {
2023-02-09 19:18:06 +00:00
err := settingService.SetTgBotChatId(tgBotChatid)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Printf("Error setting Telegram bot chat ID: %v\n", err)
2023-02-09 19:18:06 +00:00
return
}
2024-07-08 21:08:00 +00:00
logger.Info("Successfully updated Telegram bot chat ID.")
2023-02-09 19:18:06 +00:00
}
}
// updateSetting updates various panel settings including ports, credentials, base path, listen IPs, and two-factor authentication.
func updateSetting(port int, subPort int, username string, password string, webBasePath string, listenIP string, subListenIP string, resetTwoFactor bool) {
err := database.InitDB()
2023-02-09 19:18:06 +00:00
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Database initialization failed:", err)
2023-02-09 19:18:06 +00:00
return
}
settingService := service.SettingService{}
2024-07-08 21:08:00 +00:00
userService := service.UserService{}
2023-02-09 19:18:06 +00:00
if port > 0 {
err := settingService.SetPort(port)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Failed to set port:", err)
2023-02-09 19:18:06 +00:00
} else {
2024-07-08 21:08:00 +00:00
fmt.Printf("Port set successfully: %v\n", port)
2023-02-09 19:18:06 +00:00
}
}
2023-02-09 19:18:06 +00:00
if username != "" || password != "" {
err := userService.UpdateFirstUser(username, password)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Failed to update username and password:", err)
2023-02-09 19:18:06 +00:00
} else {
2024-07-08 21:08:00 +00:00
fmt.Println("Username and password updated successfully")
2023-02-09 19:18:06 +00:00
}
}
if webBasePath != "" {
err := settingService.SetBasePath(webBasePath)
if err != nil {
2024-07-08 21:08:00 +00:00
fmt.Println("Failed to set base URI path:", err)
} else {
2024-07-08 21:08:00 +00:00
fmt.Println("Base URI path set successfully")
}
}
if resetTwoFactor {
err := settingService.SetTwoFactorEnable(false)
if err != nil {
fmt.Println("Failed to reset two-factor authentication:", err)
} else {
settingService.SetTwoFactorToken("")
fmt.Println("Two-factor authentication reset successfully")
}
}
if listenIP != "" {
err := settingService.SetListen(listenIP)
if err != nil {
fmt.Println("Failed to set listen IP:", err)
} else {
fmt.Printf("listen %v set successfully\n", listenIP)
}
}
if subPort > 0 {
err := settingService.SetSubPort(subPort)
if err != nil {
fmt.Println("Failed to set sub port:", err)
} else {
fmt.Printf("Sub port set successfully: %v\n", subPort)
}
}
if subListenIP != "" {
err := settingService.SetSubListen(subListenIP)
if err != nil {
fmt.Println("Failed to set sub listen IP:", err)
} else {
fmt.Printf("sub listen %v set successfully\n", subListenIP)
}
}
2023-02-09 19:18:06 +00:00
}
2025-09-20 07:35:50 +00:00
// updateCert updates the SSL certificate files for the panel.
func updateCert(publicKey string, privateKey string) {
err := database.InitDB()
if err != nil {
fmt.Println(err)
return
}
if (privateKey != "" && publicKey != "") || (privateKey == "" && publicKey == "") {
settingService := service.SettingService{}
err = settingService.SetCertFile(publicKey)
if err != nil {
fmt.Println("set certificate public key failed:", err)
} else {
fmt.Println("set certificate public key success")
}
err = settingService.SetKeyFile(privateKey)
if err != nil {
fmt.Println("set certificate private key failed:", err)
} else {
fmt.Println("set certificate private key success")
}
err = settingService.SetSubCertFile(publicKey)
if err != nil {
fmt.Println("set certificate for subscription public key failed:", err)
} else {
fmt.Println("set certificate for subscription public key success")
}
err = settingService.SetSubKeyFile(privateKey)
if err != nil {
fmt.Println("set certificate for subscription private key failed:", err)
} else {
fmt.Println("set certificate for subscription private key success")
}
} else {
fmt.Println("both public and private key should be entered.")
}
}
2025-09-20 07:35:50 +00:00
// GetCertificate displays the current SSL certificate settings if getCert is true.
2024-10-30 19:26:37 +00:00
func GetCertificate(getCert bool) {
if getCert {
settingService := service.SettingService{}
certFile, err := settingService.GetCertFile()
if err != nil {
fmt.Println("get cert file failed, error info:", err)
}
keyFile, err := settingService.GetKeyFile()
if err != nil {
fmt.Println("get key file failed, error info:", err)
}
fmt.Println("cert:", certFile)
fmt.Println("key:", keyFile)
}
}
2025-09-20 07:35:50 +00:00
// GetListenIP displays the current panel listen IP address if getListen is true.
2024-10-30 19:26:37 +00:00
func GetListenIP(getListen bool) {
if getListen {
settingService := service.SettingService{}
ListenIP, err := settingService.GetListen()
if err != nil {
log.Printf("Failed to retrieve listen IP: %v", err)
return
}
fmt.Println("listenIP:", ListenIP)
}
}
2025-09-20 07:35:50 +00:00
// migrateDb performs database migration operations for the 3x-ui panel.
func migrateDb() {
inboundService := service.InboundService{}
err := database.InitDB()
if err != nil {
log.Fatal(err)
}
fmt.Println("Start migrating database...")
inboundService.MigrateDB()
fmt.Println("Migration done!")
}
func defaultDatabaseSetting() *entity.DatabaseSetting {
databaseService := &service.DatabaseService{}
setting, err := databaseService.GetSetting()
if err == nil && setting != nil {
return setting
}
return entity.DatabaseSettingFromConfig(config.DefaultDatabaseConfig())
}
func addDatabaseFlags(fs *flag.FlagSet, setting *entity.DatabaseSetting) {
fs.StringVar(&setting.Driver, "driver", setting.Driver, "Database driver: sqlite or postgres")
fs.StringVar(&setting.SQLitePath, "sqlite-path", setting.SQLitePath, "SQLite database path")
fs.StringVar(&setting.PostgresMode, "postgres-mode", setting.PostgresMode, "PostgreSQL mode: local or external")
fs.StringVar(&setting.PostgresHost, "postgres-host", setting.PostgresHost, "PostgreSQL host")
fs.IntVar(&setting.PostgresPort, "postgres-port", setting.PostgresPort, "PostgreSQL port")
fs.StringVar(&setting.PostgresDBName, "postgres-db", setting.PostgresDBName, "PostgreSQL database name")
fs.StringVar(&setting.PostgresUser, "postgres-user", setting.PostgresUser, "PostgreSQL user")
fs.StringVar(&setting.PostgresPassword, "postgres-password", "", "PostgreSQL password")
fs.StringVar(&setting.PostgresSSLMode, "postgres-sslmode", setting.PostgresSSLMode, "PostgreSQL sslmode")
fs.BoolVar(&setting.ManagedLocally, "postgres-local", setting.ManagedLocally, "Treat PostgreSQL as locally managed")
}
func writeExportFile(outputPath string, defaultName string, data []byte) (string, error) {
targetPath := outputPath
if targetPath == "" {
targetPath = defaultName
} else if info, err := os.Stat(targetPath); err == nil && info.IsDir() {
targetPath = filepath.Join(targetPath, defaultName)
}
if err := os.WriteFile(targetPath, data, 0o600); err != nil {
return "", err
}
return targetPath, nil
}
func handleDatabaseCommand(args []string) {
if len(args) == 0 {
fmt.Println("Usage:")
fmt.Println(" x-ui database show")
fmt.Println(" x-ui database test [database flags]")
fmt.Println(" x-ui database switch [database flags]")
fmt.Println(" x-ui database export -type portable|sqlite [-out path]")
fmt.Println(" x-ui database import -file backup.xui-backup")
fmt.Println(" x-ui database install-postgres")
return
}
databaseService := service.DatabaseService{}
switch args[0] {
case "show":
setting, err := databaseService.GetSetting()
if err != nil {
fmt.Println("Failed to load database settings:", err)
return
}
contents, err := json.MarshalIndent(setting, "", " ")
if err != nil {
fmt.Println("Failed to serialize database settings:", err)
return
}
fmt.Println(string(contents))
case "test":
setting := defaultDatabaseSetting()
testCmd := flag.NewFlagSet("database test", flag.ExitOnError)
addDatabaseFlags(testCmd, setting)
_ = testCmd.Parse(args[1:])
if err := databaseService.TestSetting(setting); err != nil {
fmt.Println("Database connection test failed:", err)
return
}
fmt.Println("Database connection test succeeded.")
case "switch":
setting := defaultDatabaseSetting()
switchCmd := flag.NewFlagSet("database switch", flag.ExitOnError)
addDatabaseFlags(switchCmd, setting)
_ = switchCmd.Parse(args[1:])
if err := databaseService.SwitchDatabase(setting); err != nil {
fmt.Println("Database switch failed:", err)
return
}
fmt.Println("Database configuration updated. Restart the panel service to apply changes.")
case "export":
exportCmd := flag.NewFlagSet("database export", flag.ExitOnError)
exportType := exportCmd.String("type", "portable", "Export type: portable or sqlite")
outputPath := exportCmd.String("out", "", "Output path or directory")
_ = exportCmd.Parse(args[1:])
if err := database.InitDB(); err != nil {
fmt.Println("Failed to initialize database:", err)
return
}
var (
data []byte
filename string
err error
)
switch *exportType {
case "sqlite":
data, filename, err = databaseService.ExportNativeSQLite()
default:
data, filename, err = databaseService.ExportPortableBackup()
}
if err != nil {
fmt.Println("Export failed:", err)
return
}
targetPath, err := writeExportFile(*outputPath, filename, data)
if err != nil {
fmt.Println("Failed to write backup:", err)
return
}
fmt.Println("Backup exported to:", targetPath)
case "import":
importCmd := flag.NewFlagSet("database import", flag.ExitOnError)
backupFile := importCmd.String("file", "", "Path to .xui-backup or legacy SQLite .db file")
_ = importCmd.Parse(args[1:])
if *backupFile == "" {
fmt.Println("Import requires -file")
return
}
if err := database.InitDB(); err != nil {
fmt.Println("Failed to initialize database:", err)
return
}
file, err := os.Open(*backupFile)
if err != nil {
fmt.Println("Failed to open backup file:", err)
return
}
defer file.Close()
backupType, err := databaseService.ImportBackup(file)
if err != nil {
fmt.Println("Import failed:", err)
return
}
fmt.Println("Import completed using", backupType, "backup. Restart the panel service to apply changes.")
case "install-postgres":
output, err := databaseService.InstallLocalPostgres()
if err != nil {
fmt.Println("PostgreSQL installation failed:", err)
return
}
fmt.Print(output)
default:
fmt.Println("Unknown database subcommand:", args[0])
}
}
2025-09-20 07:35:50 +00:00
// 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.
2023-02-09 19:18:06 +00:00
func main() {
if len(os.Args) < 2 {
runWebServer()
return
2023-02-09 19:18:06 +00:00
}
var showVersion bool
flag.BoolVar(&showVersion, "v", false, "show version")
runCmd := flag.NewFlagSet("run", flag.ExitOnError)
settingCmd := flag.NewFlagSet("setting", flag.ExitOnError)
var port int
var subPort int
var username string
var password string
var webBasePath string
var listenIP string
var subListenIP string
2024-10-30 19:26:37 +00:00
var getListen bool
var webCertFile string
var webKeyFile string
var tgbottoken string
var tgbotchatid string
var enabletgbot bool
var tgbotRuntime string
var reset bool
var show bool
2024-10-30 19:26:37 +00:00
var getCert bool
var resetTwoFactor bool
2024-07-08 21:08:00 +00:00
settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
settingCmd.BoolVar(&show, "show", false, "Display current settings")
settingCmd.IntVar(&port, "port", 0, "Set panel port number")
settingCmd.IntVar(&subPort, "subPort", 0, "Set subscription port number")
2024-07-08 21:08:00 +00:00
settingCmd.StringVar(&username, "username", "", "Set login username")
settingCmd.StringVar(&password, "password", "", "Set login password")
settingCmd.StringVar(&webBasePath, "webBasePath", "", "Set base path for Panel")
2024-10-30 19:26:37 +00:00
settingCmd.StringVar(&listenIP, "listenIP", "", "set panel listenIP IP")
settingCmd.StringVar(&subListenIP, "subListenIP", "", "set subscription listenIP IP")
settingCmd.BoolVar(&resetTwoFactor, "resetTwoFactor", false, "Reset two-factor authentication settings")
2024-10-30 19:26:37 +00:00
settingCmd.BoolVar(&getListen, "getListen", false, "Display current panel listenIP IP")
settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings")
2024-07-08 21:08:00 +00:00
settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel")
settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel")
settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot")
settingCmd.StringVar(&tgbotRuntime, "tgbotRuntime", "", "Set cron time for Telegram bot notifications")
settingCmd.StringVar(&tgbotchatid, "tgbotchatid", "", "Set chat ID for Telegram bot notifications")
settingCmd.BoolVar(&enabletgbot, "enabletgbot", false, "Enable notifications via Telegram bot")
oldUsage := flag.Usage
flag.Usage = func() {
oldUsage()
fmt.Println()
fmt.Println("Commands:")
fmt.Println(" run run web panel")
fmt.Println(" migrate migrate form other/old x-ui")
fmt.Println(" setting set settings")
fmt.Println(" database manage database backend")
}
flag.Parse()
if showVersion {
fmt.Println(config.GetVersion())
return
}
switch os.Args[1] {
case "run":
err := runCmd.Parse(os.Args[2:])
if err != nil {
fmt.Println(err)
return
}
runWebServer()
case "migrate":
migrateDb()
case "setting":
err := settingCmd.Parse(os.Args[2:])
if err != nil {
fmt.Println(err)
return
}
if reset {
2023-02-09 19:18:06 +00:00
resetSetting()
} else {
updateSetting(port, subPort, username, password, webBasePath, listenIP, subListenIP, resetTwoFactor)
}
if show {
showSetting(show)
}
2024-10-30 19:26:37 +00:00
if getListen {
GetListenIP(getListen)
}
if getCert {
GetCertificate(getCert)
}
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
}
if enabletgbot {
updateTgbotEnableSts(enabletgbot)
}
case "cert":
err := settingCmd.Parse(os.Args[2:])
if err != nil {
fmt.Println(err)
return
}
if reset {
updateCert("", "")
} else {
updateCert(webCertFile, webKeyFile)
}
case "database":
handleDatabaseCommand(os.Args[2:])
default:
fmt.Println("Invalid subcommands")
fmt.Println()
runCmd.Usage()
fmt.Println()
settingCmd.Usage()
2023-02-09 19:18:06 +00:00
}
}