Files
mqtt_explorer/backend/internal/settings/store.go
Gilles Soulier 383ad292d3 first
2025-12-24 14:47:39 +01:00

149 lines
4.6 KiB
Go

package settings
import (
"fmt"
"os"
"path/filepath"
"sync"
"gopkg.in/yaml.v3"
)
type Store struct {
mu sync.RWMutex
path string
}
type Settings struct {
Theme string `yaml:"theme" json:"theme"`
RepoURL string `yaml:"repoUrl" json:"repoUrl"`
TTLDays int `yaml:"ttlDays" json:"ttlDays"`
MaxPayloadBytes int `yaml:"maxPayloadBytes" json:"maxPayloadBytes"`
AutoPurgePayloads bool `yaml:"autoPurgePayloads" json:"autoPurgePayloads"`
AutoPurgePayloadBytes int `yaml:"autoPurgePayloadBytes" json:"autoPurgePayloadBytes"`
AutoExpandDepth int `yaml:"autoExpandDepth" json:"autoExpandDepth"`
ImageDetection bool `yaml:"imageDetectionEnabled" json:"imageDetectionEnabled"`
HighlightMs int `yaml:"highlightMs" json:"highlightMs"`
MQTTProfiles []MQTTProfile `yaml:"mqttProfiles" json:"mqttProfiles"`
ActiveProfileID string `yaml:"activeProfileId" json:"activeProfileId"`
ApplyViewFilter bool `yaml:"applyViewFilter" json:"applyViewFilter"`
ExpandTreeOnStart bool `yaml:"expandTreeOnStart" json:"expandTreeOnStart"`
TopicFilters []TopicFilter `yaml:"topicFilters" json:"topicFilters"`
UIFontSize int `yaml:"uiFontSize" json:"uiFontSize"`
TopicFontSize int `yaml:"topicFontSize" json:"topicFontSize"`
PayloadFontSize int `yaml:"payloadFontSize" json:"payloadFontSize"`
StatsRefreshMs int `yaml:"statsRefreshMs" json:"statsRefreshMs"`
ResizeHandlePx int `yaml:"resizeHandlePx" json:"resizeHandlePx"`
}
type MQTTProfile struct {
ID string `yaml:"id" json:"id"`
Name string `yaml:"name" json:"name"`
Host string `yaml:"host" json:"host"`
Port int `yaml:"port" json:"port"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
IsDefault bool `yaml:"isDefault" json:"isDefault"`
}
type TopicFilter struct {
Topic string `yaml:"topic" json:"topic"`
Save bool `yaml:"save" json:"save"`
View bool `yaml:"view" json:"view"`
}
func NewStore(path string) *Store {
return &Store{path: path}
}
func (s *Store) Load(defaults Settings) (Settings, error) {
s.mu.RLock()
defer s.mu.RUnlock()
content, err := os.ReadFile(s.path)
if err != nil {
if os.IsNotExist(err) {
return defaults, nil
}
return defaults, fmt.Errorf("lecture settings: %w", err)
}
var loaded Settings
if err := yaml.Unmarshal(content, &loaded); err != nil {
return defaults, fmt.Errorf("yaml settings: %w", err)
}
return merge(defaults, loaded), nil
}
func (s *Store) Save(next Settings) error {
s.mu.Lock()
defer s.mu.Unlock()
dir := filepath.Dir(s.path)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("mkdir settings: %w", err)
}
content, err := yaml.Marshal(next)
if err != nil {
return fmt.Errorf("marshal settings: %w", err)
}
return os.WriteFile(s.path, content, 0o644)
}
func merge(base, override Settings) Settings {
merged := base
if override.Theme != "" {
merged.Theme = override.Theme
}
if override.RepoURL != "" {
merged.RepoURL = override.RepoURL
}
if override.TTLDays != 0 {
merged.TTLDays = override.TTLDays
}
if override.MaxPayloadBytes != 0 {
merged.MaxPayloadBytes = override.MaxPayloadBytes
}
merged.AutoPurgePayloads = override.AutoPurgePayloads
if override.AutoPurgePayloadBytes != 0 {
merged.AutoPurgePayloadBytes = override.AutoPurgePayloadBytes
}
if override.AutoExpandDepth != 0 {
merged.AutoExpandDepth = override.AutoExpandDepth
}
merged.ImageDetection = override.ImageDetection
if override.HighlightMs != 0 {
merged.HighlightMs = override.HighlightMs
}
if len(override.MQTTProfiles) > 0 {
merged.MQTTProfiles = override.MQTTProfiles
}
if override.ActiveProfileID != "" {
merged.ActiveProfileID = override.ActiveProfileID
}
merged.ApplyViewFilter = override.ApplyViewFilter
merged.ExpandTreeOnStart = override.ExpandTreeOnStart
if len(override.TopicFilters) > 0 {
merged.TopicFilters = override.TopicFilters
}
if override.UIFontSize != 0 {
merged.UIFontSize = override.UIFontSize
}
if override.TopicFontSize != 0 {
merged.TopicFontSize = override.TopicFontSize
}
if override.PayloadFontSize != 0 {
merged.PayloadFontSize = override.PayloadFontSize
}
if override.StatsRefreshMs != 0 {
merged.StatsRefreshMs = override.StatsRefreshMs
}
if override.ResizeHandlePx != 0 {
merged.ResizeHandlePx = override.ResizeHandlePx
}
return merged
}