Big refactor to allow for multiple watchers, v2 configuration file with migration and new UI for configuration

This commit is contained in:
2021-10-06 23:12:43 +10:30
parent 7dddc92364
commit 8483fe7db9
8 changed files with 512 additions and 529 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"os"
"strings"
daulog "github.com/tardisx/discord-auto-upload/log"
@@ -21,62 +22,115 @@ type ConfigV1 struct {
Exclude string
}
type ConfigV2Watcher struct {
type Watcher struct {
WebHookURL string
Path string
Username string
NoWatermark bool
Exclude string
Exclude []string
}
type ConfigV2 struct {
WatchInterval int
Version int
Watchers []ConfigV2Watcher
Port int
Watchers []Watcher
}
var Config ConfigV2
var configPath string
type ConfigService struct {
Config ConfigV2
ConfigFilename string
}
func Init() {
configPath = defaultConfigPath()
func DefaultConfigService() *ConfigService {
c := ConfigService{
ConfigFilename: defaultConfigPath(),
}
return &c
}
// LoadOrInit loads the current configuration from the config file, or creates
// a new config file if none exists.
func LoadOrInit() error {
daulog.SendLog(fmt.Sprintf("Trying to load config from %s", configPath), daulog.LogTypeDebug)
_, err := os.Stat(configPath)
func (c *ConfigService) LoadOrInit() error {
daulog.SendLog(fmt.Sprintf("Trying to load config from %s\n", c.ConfigFilename), daulog.LogTypeDebug)
_, err := os.Stat(c.ConfigFilename)
if os.IsNotExist(err) {
daulog.SendLog("NOTE: No config file, writing out sample configuration", daulog.LogTypeInfo)
daulog.SendLog("You need to set the configuration via the web interface", daulog.LogTypeInfo)
Config.Version = 2
Config.WatchInterval = 10
return SaveConfig()
c.Config = *DefaultConfig()
return c.Save()
} else {
return LoadConfig()
return c.Load()
}
}
// LoadConfig will load the configuration from a known-to-exist config file.
func LoadConfig() error {
data, err := ioutil.ReadFile(configPath)
if err != nil {
return fmt.Errorf("cannot read config file %s: %s", configPath, err.Error())
func DefaultConfig() *ConfigV2 {
c := ConfigV2{}
c.Version = 2
c.WatchInterval = 10
c.Port = 9090
w := Watcher{
WebHookURL: "abcedf",
Path: "/Users/justin/tmp",
Username: "",
NoWatermark: false,
Exclude: []string{},
}
err = json.Unmarshal([]byte(data), &Config)
c.Watchers = []Watcher{w}
return &c
}
// Load will load the configuration from a known-to-exist config file.
func (c *ConfigService) Load() error {
fmt.Printf("Loading from %s\n\n", c.ConfigFilename)
data, err := ioutil.ReadFile(c.ConfigFilename)
if err != nil {
return fmt.Errorf("cannot decode config file %s: %s", configPath, err.Error())
return fmt.Errorf("cannot read config file %s: %s", c.ConfigFilename, err.Error())
}
err = json.Unmarshal([]byte(data), &c.Config)
if err != nil {
return fmt.Errorf("cannot decode config file %s: %s", c.ConfigFilename, err.Error())
}
fmt.Printf("Got config: %#v", c.Config)
// Version 0 predates config migrations
if c.Config.Version == 0 {
// need to migrate this
daulog.SendLog("Migrating config to V2", daulog.LogTypeInfo)
configV1 := ConfigV1{}
err = json.Unmarshal([]byte(data), &configV1)
if err != nil {
return fmt.Errorf("cannot decode legacy config file as v1 %s: %s", c.ConfigFilename, err.Error())
}
// copy stuff across
c.Config.Version = 2
c.Config.WatchInterval = configV1.Watch
c.Config.Port = 9090 // this never used to be configurable
onlyWatcher := Watcher{
WebHookURL: configV1.WebHookURL,
Path: configV1.Path,
Username: configV1.Username,
NoWatermark: configV1.NoWatermark,
Exclude: strings.Split(configV1.Exclude, " "),
}
c.Config.Watchers = []Watcher{onlyWatcher}
}
return nil
}
func SaveConfig() error {
func (c *ConfigService) Save() error {
daulog.SendLog("saving configuration", daulog.LogTypeInfo)
jsonString, _ := json.Marshal(Config)
err := ioutil.WriteFile(configPath, jsonString, os.ModePerm)
jsonString, _ := json.Marshal(c.Config)
err := ioutil.WriteFile(c.ConfigFilename, jsonString, os.ModePerm)
if err != nil {
return fmt.Errorf("cannot save config %s: %s", configPath, err.Error())
return fmt.Errorf("cannot save config %s: %s", c.ConfigFilename, err.Error())
}
return nil
}

View File

@@ -7,39 +7,76 @@ import (
)
func TestNoConfig(t *testing.T) {
if Config.Version != 0 {
t.Error("not 0 empty config")
}
c := ConfigService{}
configPath = emptyTempFile()
os.Remove(configPath)
c.ConfigFilename = emptyTempFile()
os.Remove(c.ConfigFilename)
defer os.Remove(c.ConfigFilename) // because we are about to create it
err := LoadOrInit()
err := c.LoadOrInit()
if err != nil {
t.Errorf("unexpected failure from load: %s", err)
}
if Config.Version != 2 {
if c.Config.Version != 2 {
t.Error("not version 2 starting config")
}
if fileSize(configPath) < 40 {
t.Errorf("File is too small %d bytes", fileSize(configPath))
if fileSize(c.ConfigFilename) < 40 {
t.Errorf("File is too small %d bytes", fileSize(c.ConfigFilename))
}
os.Remove(configPath)
}
func TestEmptyFileConfig(t *testing.T) {
c := ConfigService{}
configPath = emptyTempFile()
c.ConfigFilename = emptyTempFile()
defer os.Remove(c.ConfigFilename)
err := LoadOrInit()
err := c.LoadOrInit()
if err == nil {
t.Error("unexpected success from LoadOrInit()")
}
os.Remove(configPath)
}
func TestMigrateFromV1toV2(t *testing.T) {
c := ConfigService{}
c.ConfigFilename = v1Config()
err := c.LoadOrInit()
if err != nil {
t.Error("unexpected error from LoadOrInit()")
}
if c.Config.Version != 2 {
t.Errorf("Version %d not 2", c.Config.Version)
}
if len(c.Config.Watchers) != 1 {
t.Error("wrong amount of watchers")
}
if c.Config.Watchers[0].Path != "/private/tmp" {
t.Error("Wrong path")
}
if c.Config.WatchInterval != 69 {
t.Error("Wrong watch interval")
}
if c.Config.Port != 9090 {
t.Error("Wrong port")
}
}
func v1Config() string {
f, err := ioutil.TempFile("", "dautest-*")
if err != nil {
panic(err)
}
config := `{"WebHookURL":"https://discord.com/api/webhooks/abc123","Path":"/private/tmp","Watch":69,"Username":"abcdedf","NoWatermark":true,"Exclude":"ab cd ef"}`
f.Write([]byte(config))
defer f.Close()
return f.Name()
}
func emptyTempFile() string {