config.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Package config provides configuration management utilities for the 3x-ui panel,
  2. // including version information, logging levels, database paths, and environment variable handling.
  3. package config
  4. import (
  5. _ "embed"
  6. "fmt"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "runtime"
  11. "strings"
  12. "testing"
  13. )
  14. //go:embed version
  15. var version string
  16. //go:embed name
  17. var name string
  18. // LogLevel represents the logging level for the application.
  19. type LogLevel string
  20. // Logging level constants
  21. const (
  22. Debug LogLevel = "debug"
  23. Info LogLevel = "info"
  24. Notice LogLevel = "notice"
  25. Warning LogLevel = "warning"
  26. Error LogLevel = "error"
  27. )
  28. // GetVersion returns the version string of the 3x-ui application.
  29. func GetVersion() string {
  30. return strings.TrimSpace(version)
  31. }
  32. // GetName returns the name of the 3x-ui application.
  33. func GetName() string {
  34. return strings.TrimSpace(name)
  35. }
  36. // GetLogLevel returns the current logging level based on environment variables or defaults to Info.
  37. func GetLogLevel() LogLevel {
  38. if IsDebug() {
  39. return Debug
  40. }
  41. logLevel := os.Getenv("XUI_LOG_LEVEL")
  42. if logLevel == "" {
  43. return Info
  44. }
  45. return LogLevel(logLevel)
  46. }
  47. // IsDebug returns true if debug mode is enabled via the XUI_DEBUG environment variable.
  48. func IsDebug() bool {
  49. return os.Getenv("XUI_DEBUG") == "true"
  50. }
  51. // IsSkipHSTS returns true if skipping HSTS mode is enabled via the XUI_SKIP_HSTS environment variable.
  52. func IsSkipHSTS() bool {
  53. return os.Getenv("XUI_SKIP_HSTS") == "true"
  54. }
  55. // GetBinFolderPath returns the path to the binary folder, defaulting to "bin" if not set via XUI_BIN_FOLDER.
  56. func GetBinFolderPath() string {
  57. binFolderPath := os.Getenv("XUI_BIN_FOLDER")
  58. if binFolderPath == "" {
  59. binFolderPath = "bin"
  60. }
  61. return binFolderPath
  62. }
  63. func getBaseDir() string {
  64. exePath, err := os.Executable()
  65. if err != nil {
  66. return "."
  67. }
  68. exeDir := filepath.Dir(exePath)
  69. exeDirLower := strings.ToLower(filepath.ToSlash(exeDir))
  70. if strings.Contains(exeDirLower, "/appdata/local/temp/") || strings.Contains(exeDirLower, "/go-build") {
  71. wd, err := os.Getwd()
  72. if err != nil {
  73. return "."
  74. }
  75. return wd
  76. }
  77. return exeDir
  78. }
  79. // GetDBFolderPath returns the path to the database folder based on environment variables or platform defaults.
  80. func GetDBFolderPath() string {
  81. dbFolderPath := os.Getenv("XUI_DB_FOLDER")
  82. if dbFolderPath != "" {
  83. return dbFolderPath
  84. }
  85. if runtime.GOOS == "windows" {
  86. return getBaseDir()
  87. }
  88. return "/etc/x-ui"
  89. }
  90. // GetDBPath returns the full path to the database file.
  91. func GetDBPath() string {
  92. return fmt.Sprintf("%s/%s.db", GetDBFolderPath(), GetName())
  93. }
  94. // GetDBKind returns the configured database backend: "sqlite" (default) or "postgres".
  95. func GetDBKind() string {
  96. v := strings.ToLower(strings.TrimSpace(os.Getenv("XUI_DB_TYPE")))
  97. switch v {
  98. case "postgres", "postgresql", "pg":
  99. return "postgres"
  100. default:
  101. return "sqlite"
  102. }
  103. }
  104. // GetDBDSN returns the PostgreSQL DSN from XUI_DB_DSN. Empty for sqlite.
  105. func GetDBDSN() string {
  106. return strings.TrimSpace(os.Getenv("XUI_DB_DSN"))
  107. }
  108. // GetEnvFilePaths returns the candidate service environment file paths (the file
  109. // systemd loads via EnvironmentFile) across the supported distro families.
  110. func GetEnvFilePaths() []string {
  111. if runtime.GOOS == "windows" {
  112. return nil
  113. }
  114. return []string{
  115. "/etc/default/x-ui",
  116. "/etc/conf.d/x-ui",
  117. "/etc/sysconfig/x-ui",
  118. }
  119. }
  120. // GetLogFolder returns the path to the log folder based on environment variables or platform defaults.
  121. func GetLogFolder() string {
  122. logFolderPath := os.Getenv("XUI_LOG_FOLDER")
  123. if logFolderPath != "" {
  124. return logFolderPath
  125. }
  126. // Under `go test` the Windows default below is CWD-relative ("./log"), which
  127. // scatters a log/ directory through the source tree (one per tested package).
  128. // Redirect test runs to a shared temp folder so the source tree stays clean.
  129. if testing.Testing() {
  130. return filepath.Join(os.TempDir(), "3x-ui-test-log")
  131. }
  132. if runtime.GOOS == "windows" {
  133. return filepath.Join(".", "log")
  134. }
  135. return "/var/log/x-ui"
  136. }
  137. func copyFile(src, dst string) error {
  138. in, err := os.Open(src)
  139. if err != nil {
  140. return err
  141. }
  142. defer in.Close()
  143. out, err := os.Create(dst)
  144. if err != nil {
  145. return err
  146. }
  147. defer out.Close()
  148. _, err = io.Copy(out, in)
  149. if err != nil {
  150. return err
  151. }
  152. return out.Sync()
  153. }
  154. func init() {
  155. if runtime.GOOS != "windows" {
  156. return
  157. }
  158. if os.Getenv("XUI_DB_FOLDER") != "" {
  159. return
  160. }
  161. oldDBFolder := "/etc/x-ui"
  162. oldDBPath := fmt.Sprintf("%s/%s.db", oldDBFolder, GetName())
  163. newDBFolder := GetDBFolderPath()
  164. newDBPath := fmt.Sprintf("%s/%s.db", newDBFolder, GetName())
  165. _, err := os.Stat(newDBPath)
  166. if err == nil {
  167. return // new exists
  168. }
  169. _, err = os.Stat(oldDBPath)
  170. if os.IsNotExist(err) {
  171. return // old does not exist
  172. }
  173. _ = copyFile(oldDBPath, newDBPath) // ignore error
  174. }