settings: Save future changes in a dedicated file
This commit is contained in:
parent
465a48c1c0
commit
3c237819c3
5 changed files with 295 additions and 15 deletions
117
settings/diff.go
Normal file
117
settings/diff.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DiffSettings returns only the fields that differs between the two objects.
|
||||
func DiffSettings(old, new *Settings) (ret map[string]interface{}) {
|
||||
ret = map[string]interface{}{}
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(*old)) {
|
||||
if !reflect.DeepEqual(reflect.ValueOf(*old).FieldByName(field.Name).Interface(), reflect.ValueOf(*new).FieldByName(field.Name).Interface()) {
|
||||
name := field.Name
|
||||
|
||||
if tag, ok := field.Tag.Lookup("json"); ok {
|
||||
name = strings.Split(tag, ",")[0]
|
||||
}
|
||||
|
||||
ret[name] = reflect.ValueOf(*new).FieldByName(field.Name).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type NextSettingsFile struct {
|
||||
Id int64 `json:"id"`
|
||||
Date time.Time `json:"date"`
|
||||
Values map[string]interface{} `json:"values"`
|
||||
}
|
||||
|
||||
func ReadNextSettingsFile(filename string, ts int64) (*NextSettingsFile, error) {
|
||||
fd, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open(%s): %w", filename, err)
|
||||
} else {
|
||||
defer fd.Close()
|
||||
|
||||
var s map[string]interface{}
|
||||
|
||||
jdec := json.NewDecoder(fd)
|
||||
|
||||
if err := jdec.Decode(&s); err != nil {
|
||||
return nil, fmt.Errorf("an error occurs during JSON decoding of %s: %w", filename, err)
|
||||
}
|
||||
|
||||
return &NextSettingsFile{
|
||||
Id: ts,
|
||||
Date: time.Unix(ts, 0),
|
||||
Values: s,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func ListNextSettingsFiles() ([]*NextSettingsFile, error) {
|
||||
files, err := os.ReadDir(SettingsDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret []*NextSettingsFile
|
||||
for _, file := range files {
|
||||
ts, err := strconv.ParseInt(file.Name()[:10], 10, 64)
|
||||
if err == nil {
|
||||
nsf, err := ReadNextSettingsFile(path.Join(SettingsDir, file.Name()), ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret = append(ret, nsf)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func MergeNextSettingsUntil(until *time.Time) (map[string]interface{}, error) {
|
||||
nsfs, err := ListNextSettingsFiles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := map[string]interface{}{}
|
||||
for _, nsf := range nsfs {
|
||||
if until == nil || time.Unix(nsf.Id, 0).Before(*until) {
|
||||
for k, v := range nsf.Values {
|
||||
ret[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func MergeSettings(current Settings, new map[string]interface{}) *Settings {
|
||||
for _, field := range reflect.VisibleFields(reflect.TypeOf(current)) {
|
||||
name := field.Name
|
||||
|
||||
if tag, ok := field.Tag.Lookup("json"); ok {
|
||||
name = strings.Split(tag, ",")[0]
|
||||
}
|
||||
|
||||
if v, ok := new[name]; ok {
|
||||
log.Println(name, field.Name, v)
|
||||
reflect.ValueOf(¤t).Elem().FieldByName(field.Name).Set(reflect.ValueOf(v))
|
||||
}
|
||||
}
|
||||
|
||||
return ¤t
|
||||
}
|
|
@ -103,7 +103,7 @@ func ReadSettings(path string) (*Settings, error) {
|
|||
}
|
||||
|
||||
// SaveSettings saves settings at the given location.
|
||||
func SaveSettings(path string, s *Settings) error {
|
||||
func SaveSettings(path string, s interface{}) error {
|
||||
if fd, err := os.Create(path); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
|
Reference in a new issue