112 lines
3 KiB
Go
112 lines
3 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.nakama.town/fmartingr/hako/internal/archival/rules"
|
|
"github.com/huandu/go-sqlbuilder"
|
|
)
|
|
|
|
// SettingsStore handles database operations for settings
|
|
type SettingsStore struct {
|
|
readDB *sql.DB
|
|
writeDB *sql.DB
|
|
}
|
|
|
|
// NewSettingsStore creates a new SettingsStore
|
|
func NewSettingsStore(readDB, writeDB *sql.DB) *SettingsStore {
|
|
return &SettingsStore{
|
|
readDB: readDB,
|
|
writeDB: writeDB,
|
|
}
|
|
}
|
|
|
|
// Get retrieves a setting value by key
|
|
func (s *SettingsStore) Get(ctx context.Context, key string) (string, error) {
|
|
sb := sqlbuilder.NewSelectBuilder()
|
|
sb.Select("value")
|
|
sb.From("settings")
|
|
sb.Where(sb.Equal("key", key))
|
|
|
|
query, args := sb.Build()
|
|
row := s.readDB.QueryRowContext(ctx, query, args...)
|
|
|
|
var value string
|
|
err := row.Scan(&value)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return "", nil // Not found is not an error, return empty string
|
|
}
|
|
return "", fmt.Errorf("failed to get setting: %w", err)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
// Set creates or updates a setting value by key
|
|
func (s *SettingsStore) Set(ctx context.Context, key, value string) error {
|
|
// SQLite supports INSERT OR REPLACE
|
|
query := `INSERT OR REPLACE INTO settings (key, value, updated_at) VALUES (?, ?, ?)`
|
|
now := time.Now().Format("2006-01-02 15:04:05")
|
|
_, err := s.writeDB.ExecContext(ctx, query, key, value, now)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to set setting: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetRulesConfig retrieves and parses the rules configuration
|
|
func (s *SettingsStore) GetRulesConfig(ctx context.Context) (*rules.RuleConfig, error) {
|
|
value, err := s.Get(ctx, "rules")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get rules setting: %w", err)
|
|
}
|
|
|
|
if value == "" {
|
|
// Return default config if not set
|
|
return &rules.RuleConfig{
|
|
Rules: []rules.Rule{},
|
|
DefaultArchivers: []rules.ArchiverConfig{{Key: "obelisk"}, {Key: "thumbnail"}},
|
|
}, nil
|
|
}
|
|
|
|
// Parse JSON
|
|
config, err := rules.UnmarshalRuleConfig([]byte(value))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse rules config: %w", err)
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// SetRulesConfig serializes and stores the rules configuration
|
|
func (s *SettingsStore) SetRulesConfig(ctx context.Context, config *rules.RuleConfig) error {
|
|
// Serialize to JSON
|
|
// We need to manually construct JSON since Rule is an interface
|
|
// Convert rules to JSON by marshaling each rule individually
|
|
rulesJSON := make([]json.RawMessage, len(config.Rules))
|
|
for i, rule := range config.Rules {
|
|
ruleBytes, err := json.Marshal(rule)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal rule %d: %w", i, err)
|
|
}
|
|
rulesJSON[i] = ruleBytes
|
|
}
|
|
|
|
jsonData := map[string]interface{}{
|
|
"rules": rulesJSON,
|
|
"default_extractors": config.DefaultArchivers, // JSON key kept for backward compatibility
|
|
}
|
|
|
|
valueBytes, err := json.Marshal(jsonData)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal rules config: %w", err)
|
|
}
|
|
|
|
return s.Set(ctx, "rules", string(valueBytes))
|
|
}
|