package storage import ( "encoding/json" "errors" "os" "path/filepath" "filefast/backend/internal/model" ) const ( runtimeConfigKey = "transfer_policy" ) type runtimeConfigPayload struct { MaxMinIOFallbackSizeBytes *int64 `json:"max_minio_fallback_size_bytes"` MaxMinIOFallbackGB *int64 `json:"max_minio_fallback_gb"` MinIOCapacityBytes *int64 `json:"minio_capacity_bytes"` MinIOCapacityGB *int64 `json:"minio_capacity_gb"` MinIORetentionHours *int `json:"minio_retention_hours"` MinIOUsageAlertPercent *int `json:"minio_usage_alert_percent"` P2PConnectTimeoutSec *int `json:"p2p_connect_timeout_sec"` TURNConnectTimeoutSec *int `json:"turn_connect_timeout_sec"` MinIOFallbackEnabled *bool `json:"minio_fallback_enabled"` TURNURLs []string `json:"turn_urls"` TURNUsername *string `json:"turn_username"` TURNPassword *string `json:"turn_password"` } func decodeRuntimeConfig(raw []byte, fallback model.RuntimeConfig) (model.RuntimeConfig, error) { cfg := fallback if len(raw) == 0 { return cfg, nil } var payload runtimeConfigPayload if err := json.Unmarshal(raw, &payload); err != nil { return model.RuntimeConfig{}, err } if payload.MaxMinIOFallbackSizeBytes != nil { cfg.MaxMinIOFallbackSizeBytes = *payload.MaxMinIOFallbackSizeBytes } else if payload.MaxMinIOFallbackGB != nil { cfg.MaxMinIOFallbackSizeBytes = *payload.MaxMinIOFallbackGB * 1024 * 1024 * 1024 } if payload.MinIOCapacityBytes != nil { cfg.MinIOCapacityBytes = *payload.MinIOCapacityBytes } else if payload.MinIOCapacityGB != nil { cfg.MinIOCapacityBytes = *payload.MinIOCapacityGB * 1024 * 1024 * 1024 } if payload.MinIORetentionHours != nil { cfg.MinIORetentionHours = *payload.MinIORetentionHours } if payload.MinIOUsageAlertPercent != nil { cfg.MinIOUsageAlertPercent = *payload.MinIOUsageAlertPercent } if payload.P2PConnectTimeoutSec != nil { cfg.P2PConnectTimeoutSec = *payload.P2PConnectTimeoutSec } if payload.TURNConnectTimeoutSec != nil { cfg.TURNConnectTimeoutSec = *payload.TURNConnectTimeoutSec } if payload.MinIOFallbackEnabled != nil { cfg.MinIOFallbackEnabled = *payload.MinIOFallbackEnabled } if payload.TURNURLs != nil { cfg.TURNURLs = payload.TURNURLs } if payload.TURNUsername != nil { cfg.TURNUsername = *payload.TURNUsername } if payload.TURNPassword != nil { cfg.TURNPassword = *payload.TURNPassword } return cfg, nil } func readFirstExistingFile(paths ...string) ([]byte, error) { candidates := make([]string, 0, len(paths)*8) seen := make(map[string]struct{}) cwd, err := os.Getwd() if err == nil { current := cwd for { for _, path := range paths { candidate := filepath.Clean(filepath.Join(current, path)) if _, ok := seen[candidate]; ok { continue } seen[candidate] = struct{}{} candidates = append(candidates, candidate) } parent := filepath.Dir(current) if parent == current { break } current = parent } } for _, path := range paths { candidate := filepath.Clean(path) if _, ok := seen[candidate]; ok { continue } seen[candidate] = struct{}{} candidates = append(candidates, candidate) } for _, candidate := range candidates { data, err := os.ReadFile(candidate) if err == nil { return data, nil } if !errors.Is(err, os.ErrNotExist) { return nil, err } } return nil, os.ErrNotExist }