mirror of
https://codeberg.org/cunicu/cunicu.git
synced 2025-10-26 18:21:22 +08:00
119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
// SPDX-FileCopyrightText: 2023 Steffen Vogel <post@steffenvogel.de>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"time"
|
|
|
|
"cunicu.li/cunicu/pkg/log"
|
|
"github.com/knadh/koanf/parsers/yaml"
|
|
"github.com/knadh/koanf/providers/confmap"
|
|
"github.com/knadh/koanf/v2"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type runtimeSource struct {
|
|
*LocalFileProvider
|
|
*koanf.Koanf
|
|
|
|
watchCallback func(event any, err error)
|
|
}
|
|
|
|
func newRuntimeSource() *runtimeSource {
|
|
source := &runtimeSource{
|
|
LocalFileProvider: NewLocalFileProvider(RuntimeConfigFile),
|
|
Koanf: koanf.New("."),
|
|
}
|
|
|
|
return source
|
|
}
|
|
|
|
func (s *runtimeSource) Config() *koanf.Koanf {
|
|
return s.Koanf
|
|
}
|
|
|
|
func (s *runtimeSource) Load() error {
|
|
parser := yaml.Parser()
|
|
if err := s.Koanf.Load(s.LocalFileProvider, parser); err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
return nil
|
|
} else if errors.Is(err, os.ErrPermission) {
|
|
log.Global.Warn("Failed to load runtime configuration", zap.Error(err))
|
|
return nil
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *runtimeSource) Watch(cb func(event any, err error)) error {
|
|
if !hasRuntimeConfig() {
|
|
s.watchCallback = cb
|
|
return nil
|
|
}
|
|
|
|
return s.LocalFileProvider.Watch(cb)
|
|
}
|
|
|
|
// SaveRuntime saves the current runtime configuration to disk
|
|
func (s *runtimeSource) Save() error {
|
|
f, err := os.OpenFile(RuntimeConfigFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
fmt.Fprintln(f, "# This is the cunīcu runtime configuration file.")
|
|
fmt.Fprintln(f, "# It contains configuration adjustments made by")
|
|
fmt.Fprintln(f, "# by the user with the cunicu-config-set(1) command.")
|
|
fmt.Fprintln(f, "#")
|
|
fmt.Fprintln(f, "# Please do not edit this file by hand as it will")
|
|
fmt.Fprintln(f, "# be overwritten by cunīcu.")
|
|
fmt.Fprintln(f, "#")
|
|
fmt.Fprintf(f, "# Last modification at %s\n", time.Now().Format(time.RFC1123Z))
|
|
fmt.Fprintln(f, "---")
|
|
|
|
if s.watchCallback != nil {
|
|
if err := s.LocalFileProvider.Watch(s.watchCallback); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return s.Marshal(f)
|
|
}
|
|
|
|
func (s *runtimeSource) Marshal(wr io.Writer) error {
|
|
return marshal(s.Koanf, wr)
|
|
}
|
|
|
|
// Update sets multiple settings in the provided map.
|
|
func (s *runtimeSource) Update(sets map[string]any) error {
|
|
newKoanf := koanf.New(".")
|
|
|
|
if err := newKoanf.Load(confmap.Provider(sets, "."), nil); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check if settings are valid
|
|
if _, err := unmarshal(newKoanf); err != nil {
|
|
return err
|
|
}
|
|
|
|
s.Koanf = newKoanf
|
|
|
|
return nil
|
|
}
|
|
|
|
func hasRuntimeConfig() bool {
|
|
fi, err := os.Stat(RuntimeConfigFile)
|
|
return err == nil && !fi.IsDir()
|
|
}
|