turash/bugulma/backend/internal/service/settings_service.go
2025-12-15 10:06:41 +01:00

97 lines
2.5 KiB
Go

package service
import (
"context"
"fmt"
"sync"
"time"
"bugulma/backend/internal/domain"
)
type MaintenanceSetting struct {
Enabled bool `json:"enabled"`
Message string `json:"message"`
AllowedIPs []string `json:"allowed_ips,omitempty"`
}
type SettingsService struct {
repo domain.SystemSettingsRepository
// caching
cacheTTL time.Duration
cacheMutex sync.RWMutex
cachedMaintenance *MaintenanceSetting
cacheExpiry time.Time
}
func NewSettingsService(repo domain.SystemSettingsRepository) *SettingsService {
return &SettingsService{repo: repo, cacheTTL: 5 * time.Second}
}
func (s *SettingsService) GetMaintenance(ctx context.Context) (*MaintenanceSetting, error) {
m, err := s.repo.Get(ctx, "maintenance")
if err != nil {
return nil, fmt.Errorf("failed to get maintenance: %w", err)
}
if m == nil {
return &MaintenanceSetting{Enabled: false, Message: ""}, nil
}
enabled, _ := m["enabled"].(bool)
msg, _ := m["message"].(string)
// allowed_ips may be stored as []interface{} from DB JSON decode
var allowed []string
if v, ok := m["allowed_ips"]; ok {
switch vv := v.(type) {
case []any:
for _, it := range vv {
if s, ok := it.(string); ok {
allowed = append(allowed, s)
}
}
case []string:
allowed = vv
}
}
return &MaintenanceSetting{Enabled: enabled, Message: msg, AllowedIPs: allowed}, nil
}
func (s *SettingsService) SetMaintenance(ctx context.Context, in *MaintenanceSetting) error {
value := map[string]any{"enabled": in.Enabled, "message": in.Message}
if in.AllowedIPs != nil {
value["allowed_ips"] = in.AllowedIPs
}
if err := s.repo.Set(ctx, "maintenance", value); err != nil {
return fmt.Errorf("failed to set maintenance: %w", err)
}
// Invalidate cache
s.cacheMutex.Lock()
s.cachedMaintenance = nil
s.cacheExpiry = time.Time{}
s.cacheMutex.Unlock()
return nil
}
// GetMaintenanceCached returns a cached maintenance setting for low-latency checks.
// Cache is refreshed after s.cacheTTL.
func (s *SettingsService) GetMaintenanceCached(ctx context.Context) (*MaintenanceSetting, error) {
s.cacheMutex.RLock()
if s.cachedMaintenance != nil && time.Now().Before(s.cacheExpiry) {
m := s.cachedMaintenance
s.cacheMutex.RUnlock()
return m, nil
}
s.cacheMutex.RUnlock()
// Fetch fresh
m, err := s.GetMaintenance(ctx)
if err != nil {
return nil, err
}
s.cacheMutex.Lock()
s.cachedMaintenance = m
s.cacheExpiry = time.Now().Add(s.cacheTTL)
s.cacheMutex.Unlock()
return m, nil
}