227 lines
5.8 KiB
Go
227 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
log "github.com/sirupsen/logrus"
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
var Cfg *Config
|
|
|
|
type Config struct {
|
|
General struct {
|
|
DeleteLogFileAtStart bool `yaml:"delete_log_file_at_start"`
|
|
LogToFile bool `yaml:"log_to_file"`
|
|
Callsign string `yaml:"callsign"`
|
|
LogLevel string `yaml:"log_level"`
|
|
TelnetServer bool `yaml:"telnetserver"`
|
|
FlexRadioSpot bool `yaml:"flexradiospot"`
|
|
SendFreqModeToLog bool `yaml:"sendFreqModeToLog4OM"`
|
|
SpotColorNewEntity string `yaml:"spot_color_new_entity"`
|
|
BackgroundColorNewEntity string `yaml:"background_color_new_entity"`
|
|
SpotColorNewBand string `yaml:"spot_color_new_band"`
|
|
BackgroundColorNewBand string `yaml:"background_color_new_band"`
|
|
SpotColorNewMode string `yaml:"spot_color_new_mode"`
|
|
BackgroundColorNewMode string `yaml:"background_color_new_mode"`
|
|
SpotColorNewBandMode string `yaml:"spot_color_new_band_mode"`
|
|
BackgroundColorNewBandMode string `yaml:"background_color_new_band_mode"`
|
|
SpotColorNewSlot string `yaml:"spot_color_new_slot"`
|
|
BackgroundColorNewSlot string `yaml:"background_color_new_slot"`
|
|
SpotColorMyCallsign string `yaml:"spot_color_my_callsign"`
|
|
BackgroundColorMyCallsign string `yaml:"background_color_my_callsign"`
|
|
SpotColorWorked string `yaml:"spot_color_worked"`
|
|
BackgroundColorWorked string `yaml:"background_color_worked"`
|
|
} `yaml:"general"`
|
|
|
|
Database struct {
|
|
MySQL bool `yaml:"mysql"`
|
|
SQLite bool `yaml:"sqlite"`
|
|
MySQLUser string `yaml:"mysql_db_user"`
|
|
MySQLPassword string `yaml:"mysql_db_password"`
|
|
MySQLDbName string `yaml:"mysql_db_name"`
|
|
MySQLHost string `yaml:"mysql_host"`
|
|
MySQLPort string `yaml:"mysql_port"`
|
|
} `yaml:"database"`
|
|
|
|
SQLite struct {
|
|
SQLitePath string `yaml:"sqlite_path"`
|
|
} `yaml:"sqlite"`
|
|
|
|
Cluster struct {
|
|
Server string `yaml:"server"`
|
|
Port string `yaml:"port"`
|
|
Login string `yaml:"login"`
|
|
Password string `yaml:"password"`
|
|
Skimmer bool `yaml:"skimmer"`
|
|
FT8 bool `yaml:"ft8"`
|
|
FT4 bool `yaml:"ft4"`
|
|
Beacon bool `yaml:"beacon"`
|
|
Command string `yaml:"command"`
|
|
LoginPrompt string `yaml:"login_prompt"`
|
|
} `yaml:"cluster"`
|
|
|
|
Flex struct {
|
|
Discover bool `yaml:"discovery"`
|
|
IP string `yaml:"ip"`
|
|
SpotLife string `yaml:"spot_life"`
|
|
} `yaml:"flex"`
|
|
|
|
TelnetServer struct {
|
|
Host string `yaml:"host"`
|
|
Port string `yaml:"port"`
|
|
} `yaml:"telnetserver"`
|
|
|
|
Gotify struct {
|
|
Enable bool `yaml:"enable"`
|
|
URL string `yaml:"url"`
|
|
Token string `yaml:"token"`
|
|
NewDXCC bool `yaml:"NewDXCC"`
|
|
NewBand bool `yaml:"NewBand"`
|
|
NewMode bool `yaml:"NewMode"`
|
|
NewBandAndMode bool `yaml:"NewBandAndMode"`
|
|
WatchList bool `yaml:"Watchlist"`
|
|
} `yaml:"gotify"`
|
|
}
|
|
|
|
type ConfigWatcher struct {
|
|
watcher *fsnotify.Watcher
|
|
configPath string
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
func NewConfig(configPath string) *Config {
|
|
Cfg = &Config{}
|
|
|
|
file, err := os.Open(configPath)
|
|
if err != nil {
|
|
log.Println("could not open config file")
|
|
}
|
|
defer file.Close()
|
|
d := yaml.NewDecoder(file)
|
|
|
|
if err := d.Decode(&Cfg); err != nil {
|
|
log.Println("could not decode config file")
|
|
}
|
|
|
|
return Cfg
|
|
}
|
|
|
|
func ValidateConfigPath(path string) error {
|
|
s, err := os.Stat(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if s.IsDir() {
|
|
return fmt.Errorf("'%s' is a directory, not a normal file", path)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func NewConfigWatcher(configPath string) (*ConfigWatcher, error) {
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ConfigWatcher{
|
|
watcher: watcher,
|
|
configPath: configPath,
|
|
}, nil
|
|
}
|
|
|
|
func (cw *ConfigWatcher) Start() error {
|
|
if err := cw.watcher.Add(cw.configPath); err != nil {
|
|
return err
|
|
}
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
case event, ok := <-cw.watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
|
Log.Info("Config file modified, reloading...")
|
|
cw.reloadConfig()
|
|
}
|
|
case err, ok := <-cw.watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
Log.Errorf("Config watcher error: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (cw *ConfigWatcher) reloadConfig() {
|
|
cw.mu.Lock()
|
|
defer cw.mu.Unlock()
|
|
|
|
newCfg := &Config{}
|
|
file, err := os.Open(cw.configPath)
|
|
if err != nil {
|
|
Log.Errorf("Could not reload config: %v", err)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
d := yaml.NewDecoder(file)
|
|
if err := d.Decode(newCfg); err != nil {
|
|
Log.Errorf("Could not decode reloaded config: %v", err)
|
|
return
|
|
}
|
|
|
|
// Sauvegarder l'ancienne config
|
|
oldCfg := Cfg
|
|
|
|
// Appliquer la nouvelle config
|
|
Cfg = newCfg
|
|
|
|
// Vérifier les changements qui nécessitent des actions
|
|
cw.applyConfigChanges(oldCfg, newCfg)
|
|
|
|
Log.Info("✅ Config reloaded successfully")
|
|
}
|
|
|
|
func (cw *ConfigWatcher) applyConfigChanges(oldCfg, newCfg *Config) {
|
|
// Log level
|
|
if oldCfg.General.LogLevel != newCfg.General.LogLevel {
|
|
switch newCfg.General.LogLevel {
|
|
case "DEBUG":
|
|
Log.SetLevel(log.DebugLevel)
|
|
case "INFO":
|
|
Log.SetLevel(log.InfoLevel)
|
|
case "WARN":
|
|
Log.SetLevel(log.WarnLevel)
|
|
default:
|
|
Log.SetLevel(log.InfoLevel)
|
|
}
|
|
Log.Infof("Log level changed to %s", newCfg.General.LogLevel)
|
|
}
|
|
|
|
// Gotify
|
|
if oldCfg.Gotify.Enable != newCfg.Gotify.Enable {
|
|
Log.Infof("Gotify notifications %s", map[bool]string{true: "enabled", false: "disabled"}[newCfg.Gotify.Enable])
|
|
}
|
|
|
|
if oldCfg.Cluster.FT8 != newCfg.Cluster.FT8 ||
|
|
oldCfg.Cluster.FT4 != newCfg.Cluster.FT4 ||
|
|
oldCfg.Cluster.Skimmer != newCfg.Cluster.Skimmer ||
|
|
oldCfg.Cluster.Beacon != newCfg.Cluster.Beacon {
|
|
Log.Info("Cluster filters changed, applying")
|
|
httpServerInstance.TCPClient.ReloadFilters()
|
|
}
|
|
}
|
|
|
|
func (cw *ConfigWatcher) Stop() {
|
|
cw.watcher.Close()
|
|
}
|