package main import ( "github.com/fsnotify/fsnotify" "flag" "log" "os" "encoding/json" "time" "path/filepath" ) type Cert struct { PrivateKey string PublicKey string Owner string } type Config struct { Source Cert Target Cert Reload string WatchDelay string watcher *fsnotify.Watcher delay_time time.Duration } func LoadConfig(path string) Config { var config Config config_data, err := os.ReadFile(path) if err != nil { log.Fatal("invalid config path %s: %v", path, err) } err = json.Unmarshal(config_data, &config) if err != nil { log.Fatal(err, "json format error") } config.delay_time, err = time.ParseDuration(config.WatchDelay) if err != nil { log.Fatalf("can't parse watch_delay setting %s: %v", config.WatchDelay, err) } return config } func ParseOpts() Config { var config_file string flag.StringVar(&config_file, "config", "cert-bouncer.json", ".json config to use.") flag.Parse() return LoadConfig(config_file) } func (cfg *Config) SyncCerts() { log.Println("SYNC CERTS CALLED"); } func (cfg *Config) HandleEvents() { doit := time.NewTimer(cfg.delay_time) doit.Stop() for { select { case event, ok := <-cfg.watcher.Events: if !ok { return } log.Println("EVENT", event) if event.Name == cfg.Source.PrivateKey { doit.Reset(cfg.delay_time) } case <-doit.C: cfg.SyncCerts() case err, ok := <-cfg.watcher.Errors: if !ok { return } log.Println("failed to watch", err) } } } func (cfg *Config) WatchFiles() { var err error cfg.watcher, err = fsnotify.NewWatcher() if err != nil { log.Fatal(err, "Can't watch files.") } defer cfg.watcher.Close() go cfg.HandleEvents() cfg.Source.PrivateKey, err = filepath.Abs(cfg.Source.PrivateKey) if err != nil { log.Fatalf("can't convert %s to absolut path: %v", cfg.Source.PrivateKey, err) } err = cfg.watcher.Add(cfg.Source.PrivateKey) if err != nil { log.Fatalf("can't watch %s: %v", err, cfg.Source.PrivateKey) } <-make(chan struct{}) } func main() { config := ParseOpts() config.WatchFiles() }