package settings import ( "log" "os" "strings" "sync" "time" "github.com/0xJacky/Nginx-UI/internal/helper" "github.com/caarlos0/env/v11" "github.com/elliotchance/orderedmap/v3" "github.com/spf13/cast" "github.com/uozi-tech/cosy/settings" "gopkg.in/ini.v1" ) var ( buildTime string LastModified string EnvPrefix = "NGINX_UI_" settingsMu sync.Mutex ) var sections = orderedmap.NewOrderedMap[string, any]() var envPrefixMap = map[string]interface{}{ // Cosy "APP": settings.AppSettings, "SERVER": settings.ServerSettings, // Nginx UI "DB": DatabaseSettings, "AUTH": AuthSettings, "CASDOOR": CasdoorSettings, "CERT": CertSettings, "CLUSTER": ClusterSettings, "CRYPTO": CryptoSettings, "HTTP": HTTPSettings, "LOGROTATE": LogrotateSettings, "NGINX": NginxSettings, "NGINX_LOG": NginxLogSettings, "NODE": NodeSettings, "OPENAI": OpenAISettings, "TERMINAL": TerminalSettings, "WEBAUTHN": WebAuthnSettings, "BACKUP": BackupSettings, "OIDC": OIDCSettings, } func init() { t := time.Unix(cast.ToInt64(buildTime), 0) LastModified = strings.ReplaceAll(t.Format(time.RFC1123), "UTC", "GMT") sections.Set("database", DatabaseSettings) sections.Set("auth", AuthSettings) sections.Set("backup", BackupSettings) sections.Set("casdoor", CasdoorSettings) sections.Set("oidc", OIDCSettings) sections.Set("cert", CertSettings) sections.Set("cluster", ClusterSettings) sections.Set("crypto", CryptoSettings) sections.Set("http", HTTPSettings) sections.Set("logrotate", LogrotateSettings) sections.Set("nginx", NginxSettings) sections.Set("nginx_log", NginxLogSettings) sections.Set("node", NodeSettings) sections.Set("openai", OpenAISettings) sections.Set("terminal", TerminalSettings) sections.Set("webauthn", WebAuthnSettings) for k, v := range sections.AllFromFront() { settings.Register(k, v) } settings.WithoutRedis() settings.WithoutSonyflake() } func Init(confPath string) { migrate(confPath) settings.Init(confPath) // Set Default Port if settings.ServerSettings.Port == 0 { settings.ServerSettings.Port = 9000 } for prefix, ptr := range envPrefixMap { parseEnv(ptr, prefix+"_") } // if in official docker, set the restart cmd of nginx to "nginx -s stop", // then the supervisor of s6-overlay will start the nginx again. if helper.InNginxUIOfficialDocker() { NginxSettings.RestartCmd = "nginx -s stop" } if AuthSettings.BanThresholdMinutes <= 0 { AuthSettings.BanThresholdMinutes = 10 } if AuthSettings.MaxAttempts <= 0 { AuthSettings.MaxAttempts = 10 } } func Update(fn func()) (err error) { settingsMu.Lock() defer settingsMu.Unlock() fn() return saveLocked() } func Save() (err error) { settingsMu.Lock() defer settingsMu.Unlock() return saveLocked() } func saveLocked() (err error) { // "fix" unable to save empty slice if len(CertSettings.RecursiveNameservers) == 0 { settings.Conf.Section("cert").Key("RecursiveNameservers").SetValue("") } settings.ReflectFrom("app", settings.AppSettings) settings.ReflectFrom("server", settings.ServerSettings) settings.ReflectFrom("log", settings.LogSettings) settings.ReflectFrom("sls", settings.SLSSettings) for name, ptr := range sections.AllFromFront() { settings.ReflectFrom(name, ptr) } err = saveConfAtomically(settings.Conf, settings.ConfPath) if err != nil { return } err = settings.Reload() if err != nil { return } err = settings.MapTo("app", settings.AppSettings) if err != nil { return } err = settings.MapTo("server", settings.ServerSettings) if err != nil { return } err = settings.MapTo("log", settings.LogSettings) if err != nil { return } err = settings.MapTo("sls", settings.SLSSettings) if err != nil { return } for name, ptr := range sections.AllFromFront() { err = settings.MapTo(name, ptr) if err != nil { return } } return } func saveConfAtomically(conf *ini.File, confPath string) (err error) { tmpPath := confPath + ".tmp" err = conf.SaveTo(tmpPath) if err != nil { return } err = os.Rename(tmpPath, confPath) if err != nil { _ = os.Remove(tmpPath) return } return } func parseEnv(ptr interface{}, prefix string) { err := env.ParseWithOptions(ptr, env.Options{ Prefix: EnvPrefix + prefix, UseFieldNameByDefault: true, }) if err != nil { log.Fatalf("settings.parseEnv: %v\n", err) } }