feat(desktop): add client release updater
Desktop Client Build / Resolve Build Metadata (push) Successful in 19s
Frontend CI / Frontend (push) Successful in 3m20s
Backend CI / Backend (push) Successful in 16m48s
Desktop Client Build / Build Desktop Client (push) Successful in 24m46s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 37s

This commit is contained in:
2026-05-25 19:23:49 +08:00
parent 41b4a765ac
commit 5f6e9f11da
46 changed files with 5508 additions and 160 deletions
+63 -12
View File
@@ -20,18 +20,19 @@ import (
)
type Config struct {
Server sharedconfig.ServerConfig `mapstructure:"server"`
Database sharedconfig.DatabaseConfig `mapstructure:"database"`
MonitoringDatabase sharedconfig.DatabaseConfig `mapstructure:"monitoring_database"`
Redis sharedconfig.RedisConfig `mapstructure:"redis"`
Cache sharedconfig.CacheConfig `mapstructure:"cache"`
RabbitMQ sharedconfig.RabbitMQConfig `mapstructure:"rabbitmq"`
Log sharedconfig.LogConfig `mapstructure:"log"`
JWT JWTConfig `mapstructure:"jwt"`
Auth sharedconfig.AuthConfig `mapstructure:"auth"`
DefaultAdmin DefaultAdminConfig `mapstructure:"default_admin"`
AdminUsers AdminUsersConfig `mapstructure:"admin_users"`
IPRegion IPRegionConfig `mapstructure:"ip_region"`
Server sharedconfig.ServerConfig `mapstructure:"server"`
Database sharedconfig.DatabaseConfig `mapstructure:"database"`
MonitoringDatabase sharedconfig.DatabaseConfig `mapstructure:"monitoring_database"`
Redis sharedconfig.RedisConfig `mapstructure:"redis"`
Cache sharedconfig.CacheConfig `mapstructure:"cache"`
RabbitMQ sharedconfig.RabbitMQConfig `mapstructure:"rabbitmq"`
ObjectStorage sharedconfig.ObjectStorageConfig `mapstructure:"object_storage"`
Log sharedconfig.LogConfig `mapstructure:"log"`
JWT JWTConfig `mapstructure:"jwt"`
Auth sharedconfig.AuthConfig `mapstructure:"auth"`
DefaultAdmin DefaultAdminConfig `mapstructure:"default_admin"`
AdminUsers AdminUsersConfig `mapstructure:"admin_users"`
IPRegion IPRegionConfig `mapstructure:"ip_region"`
}
type JWTConfig struct {
@@ -237,6 +238,9 @@ func Diff(previous, current *Config) []FieldChange {
if previous.RabbitMQ != current.RabbitMQ {
add("rabbitmq", false)
}
if previous.ObjectStorage != current.ObjectStorage {
add("object_storage", false)
}
if previous.Log != current.Log {
add("log", false)
}
@@ -466,9 +470,56 @@ func applyEnvOverrides(cfg *Config) error {
if v := os.Getenv("OPS_RABBITMQ_URL"); v != "" {
cfg.RabbitMQ.URL = v
}
applyOpsObjectStorageEnvOverrides(cfg)
return nil
}
func applyOpsObjectStorageEnvOverrides(cfg *Config) {
if endpoint := firstNonEmptyEnv("OPS_OBJECT_STORAGE_ENDPOINT", "OBJECT_STORAGE_ENDPOINT"); endpoint != "" {
cfg.ObjectStorage.Endpoint = endpoint
}
if accessKey := firstNonEmptyEnv("OPS_OBJECT_STORAGE_ACCESS_KEY", "OBJECT_STORAGE_ACCESS_KEY"); accessKey != "" {
cfg.ObjectStorage.AccessKey = accessKey
}
if secretKey := firstNonEmptyEnv("OPS_OBJECT_STORAGE_SECRET_KEY", "OBJECT_STORAGE_SECRET_KEY"); secretKey != "" {
cfg.ObjectStorage.SecretKey = secretKey
}
if bucket := firstNonEmptyEnv("OPS_OBJECT_STORAGE_BUCKET", "OBJECT_STORAGE_BUCKET"); bucket != "" {
cfg.ObjectStorage.Bucket = bucket
}
if provider := firstNonEmptyEnv("OPS_OBJECT_STORAGE_PROVIDER", "OBJECT_STORAGE_PROVIDER"); provider != "" {
cfg.ObjectStorage.Provider = provider
}
if publicBaseURL := firstNonEmptyEnv("OPS_OBJECT_STORAGE_PUBLIC_BASE_URL", "OBJECT_STORAGE_PUBLIC_BASE_URL"); publicBaseURL != "" {
cfg.ObjectStorage.PublicBaseURL = publicBaseURL
}
if objectACL := firstNonEmptyEnv("OPS_OBJECT_STORAGE_OBJECT_ACL", "OBJECT_STORAGE_OBJECT_ACL"); objectACL != "" {
cfg.ObjectStorage.ObjectACL = objectACL
}
if v := firstNonEmptyEnv("OPS_OBJECT_STORAGE_SIGNED_URL_TTL", "OBJECT_STORAGE_SIGNED_URL_TTL"); v != "" {
if ttl, err := time.ParseDuration(v); err == nil {
cfg.ObjectStorage.SignedURLTTL = ttl
}
}
if region := firstNonEmptyEnv("OPS_OBJECT_STORAGE_REGION", "OBJECT_STORAGE_REGION"); region != "" {
cfg.ObjectStorage.Region = region
}
if v := firstNonEmptyEnv("OPS_OBJECT_STORAGE_USE_SSL", "OBJECT_STORAGE_USE_SSL"); v != "" {
if useSSL, err := parseBoolEnv("OPS_OBJECT_STORAGE_USE_SSL", v); err == nil {
cfg.ObjectStorage.UseSSL = useSSL
}
}
}
func firstNonEmptyEnv(names ...string) string {
for _, name := range names {
if value := strings.TrimSpace(os.Getenv(name)); value != "" {
return value
}
}
return ""
}
func parseBoolEnv(name, value string) (bool, error) {
switch strings.ToLower(strings.TrimSpace(value)) {
case "1", "true", "yes", "y", "on":