middleware-manager/util/id_normalizer.go
hhftechnologies 9d0b772458
Some checks are pending
Build and Push Docker Image / build-and-push (push) Waiting to run
Tests / Run Tests (push) Waiting to run
Tests / Lint (push) Waiting to run
Tests / Build (push) Blocked by required conditions
Improve error handling, tests, and defaults
Add robust error checks and helpers, improve transaction safety, and refine default templates handling.

- Add api/handlers/test_helpers_test.go with mustUnmarshalResponse and mustScan helpers and update many handler tests to use them or to check json.Unmarshal errors to fail fast.
- Replace direct DB Scan calls in tests with mustScan or explicit error checks to surface query failures.
- Improve transaction rollback handling across codepaths (config handlers, database migrations, transaction utils, CertGenerator) to log rollback errors and avoid silent failures.
- Make WithTransaction/WithTimeoutTransaction/BatchTransaction formatting consistent and add panic-safe rollback logging.
- In main, log a warning instead of ignoring EnsureDefaultDataSources errors.
- Add/cleanup various helper blank assignments and small refactors in services (config_proxy, config_generator) and switch tests to shared response writers (writeJSONResponse/writeResponseBody) where applicable.
- Large cleanup and enhancements in config/defaults.go to preserve string formatting for YAML templates, ensure special fields are quoted/preserved, and tidy whitespace/formatting.

These changes improve test reliability, make DB/tx failures more visible, and ensure default template YAML preserves important string values.
2026-04-15 20:00:48 +05:30

120 lines
3.2 KiB
Go

package util
import (
"regexp"
"strings"
"sync"
)
const maxCacheSize = 1000
var (
// Regular expression to match cascading auth suffixes
authCascadeRegex = regexp.MustCompile(`(-auth)+$`)
// Regular expression for router suffix with auth patterns
routerAuthRegex = regexp.MustCompile(`-router(-auth)*$`)
// Bounded memoization cache for normalized IDs
cacheMu sync.RWMutex
normalizedIDCache = make(map[string]string, maxCacheSize)
)
// NormalizeID provides a standard way to normalize any ID across the application
// It removes provider suffixes and handles special cases like auth cascades
// Uses memoization for improved performance on repeated calls
func NormalizeID(id string) string {
// Check cache first (read lock)
cacheMu.RLock()
if cached, ok := normalizedIDCache[id]; ok {
cacheMu.RUnlock()
return cached
}
cacheMu.RUnlock()
// Perform normalization
normalized := normalizeIDInternal(id)
// Store in cache (write lock), flush if full
cacheMu.Lock()
if len(normalizedIDCache) >= maxCacheSize {
normalizedIDCache = make(map[string]string, maxCacheSize)
}
normalizedIDCache[id] = normalized
cacheMu.Unlock()
return normalized
}
// normalizeIDInternal performs the actual normalization logic
func normalizeIDInternal(id string) string {
// First, remove any provider suffix (if present)
baseName := id
if idx := strings.Index(baseName, "@"); idx > 0 {
baseName = baseName[:idx]
}
// Handle cascading auth patterns
baseName = authCascadeRegex.ReplaceAllString(baseName, "-auth")
// Special handling for router resources
if strings.Contains(baseName, "-router") {
// For router-auth, router-auth-auth patterns, normalize to router-auth
baseName = routerAuthRegex.ReplaceAllString(baseName, "-router-auth")
// Handle redirect suffixes in routers
if strings.Contains(baseName, "-redirect") {
// Normalize router-redirect-auth to router-redirect
baseName = strings.TrimSuffix(baseName, "-auth")
}
}
return baseName
}
// ClearNormalizationCache clears the ID normalization cache
// Useful for testing or when IDs change
func ClearNormalizationCache() {
cacheMu.Lock()
normalizedIDCache = make(map[string]string, maxCacheSize)
cacheMu.Unlock()
}
// GetProviderSuffix extracts the provider suffix from an ID
func GetProviderSuffix(id string) string {
if idx := strings.Index(id, "@"); idx > 0 {
return id[idx:]
}
return ""
}
// AddProviderSuffix adds a provider suffix if one doesn't exist
// If the ID already has a suffix, it returns the original ID
func AddProviderSuffix(id string, suffix string) string {
if suffix == "" || strings.Contains(id, "@") {
return id
}
// Ensure suffix starts with @
if !strings.HasPrefix(suffix, "@") {
suffix = "@" + suffix
}
return id + suffix
}
// DetermineProviderSuffix returns the appropriate provider suffix based on context
func DetermineProviderSuffix(sourceType string, activeDataSourceType string) string {
// Use file provider for custom services
if sourceType == "file" {
return "@file"
}
// For Traefik API, prefer docker provider for matching source types
if activeDataSourceType == "traefik" && sourceType == "traefik" {
return "@docker"
}
// Default to http provider
return "@http"
}