134 lines
3.0 KiB
Go
134 lines
3.0 KiB
Go
package settings
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"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 (nsf *NextSettingsFile) GetId() int64 {
|
|
return nsf.Id
|
|
}
|
|
|
|
func (nsf *NextSettingsFile) GetDate() *time.Time {
|
|
return &nsf.Date
|
|
}
|
|
|
|
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 {
|
|
if len(file.Name()) < 10 {
|
|
continue
|
|
}
|
|
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 {
|
|
if reflect.TypeOf(v) != reflect.ValueOf(¤t).Elem().FieldByName(field.Name).Type() {
|
|
nv := reflect.New(reflect.ValueOf(¤t).Elem().FieldByName(field.Name).Type())
|
|
mv, _ := json.Marshal(v)
|
|
json.Unmarshal(mv, nv.Interface())
|
|
v = nv.Elem().Interface()
|
|
}
|
|
|
|
reflect.ValueOf(¤t).Elem().FieldByName(field.Name).Set(reflect.ValueOf(v))
|
|
}
|
|
}
|
|
|
|
return ¤t
|
|
}
|