package services import ( "strings" "sync" ) var publicAssetURLRuntime struct { sync.RWMutex resolver func(string) string } // SetPublicAssetURLResolver configures how host-owned asset keys are exposed // to standalone customer-service clients. A nil resolver keeps absolute URLs // and legacy values unchanged. func SetPublicAssetURLResolver(resolver func(string) string) { publicAssetURLRuntime.Lock() publicAssetURLRuntime.resolver = resolver publicAssetURLRuntime.Unlock() } // SetPublicAssetURLSettings applies the same object-key joining rule used by // the management frontend: cloud material keys use the active oss_domain, // while absolute and same-origin URLs stay unchanged. func SetPublicAssetURLSettings(settings map[string]string) { engine := strings.TrimSpace(settings["oss_default_engine"]) if engine == "" || engine == "local" { SetPublicAssetURLResolver(nil) return } domain := strings.TrimSpace(settings["oss_"+engine+"_domain"]) SetPublicAssetURLResolver(func(value string) string { return resolvePublicAssetURLWithDomain(value, domain) }) } func resolvePublicAssetURLWithDomain(value, domain string) string { value = strings.TrimSpace(value) if value == "" || strings.HasPrefix(value, "/") { return value } lower := strings.ToLower(value) if strings.HasPrefix(lower, "http://") || strings.HasPrefix(lower, "https://") || strings.HasPrefix(lower, "data:") { return value } domain = strings.TrimSpace(domain) if domain == "" { return value } if !strings.HasPrefix(strings.ToLower(domain), "http://") && !strings.HasPrefix(strings.ToLower(domain), "https://") { domain = "https://" + domain } return strings.TrimRight(domain, "/") + "/" + strings.TrimLeft(value, "/") } // ResolvePublicAssetURL converts a host-owned object key into a browser-ready // URL. Resolver failures must fall back to the stored value so message delivery // is never affected by an optional avatar. func ResolvePublicAssetURL(value string) string { value = strings.TrimSpace(value) if value == "" { return value } publicAssetURLRuntime.RLock() resolver := publicAssetURLRuntime.resolver publicAssetURLRuntime.RUnlock() if resolver == nil { return value } resolved := strings.TrimSpace(resolver(value)) if resolved == "" { return value } return resolved }