package main import ( "flag" "io/ioutil" "log" "os" "os/signal" "path" "strings" "syscall" "time" "srs.epita.fr/fic-server/settings" "gopkg.in/fsnotify.v1" ) var SettingsDistDir = "./SETTINGSDIST/" var TmpSettingsDirectory string var TmpSettingsDistDirectory string var watchedNotify = fsnotify.Create func watchsubdir(l *distList, watcher *fsnotify.Watcher, pathname string, treat func(l *distList, pathname string)) error { log.Println("Watch new directory:", pathname) if err := watcher.Add(pathname); err != nil { return err } if ds, err := ioutil.ReadDir(pathname); err != nil { return err } else { for _, d := range ds { p := path.Join(pathname, d.Name()) if d.Mode().IsRegular() && d.Name() != ".tmp" { treat(l, p) } } return nil } } func main() { flag.StringVar(&DashboardDir, "dashboard", DashboardDir, "Base directory where read dashboard files") flag.StringVar(&settings.SettingsDir, "settings", settings.SettingsDir, "Base directory where read settings") flag.StringVar(&SettingsDistDir, "settingsDist", SettingsDistDir, "Directory where place settings to distribute") var debugINotify = flag.Bool("debuginotify", false, "Show skipped inotofy events") flag.Parse() log.SetPrefix("[evdist] ") DashboardDir = path.Clean(DashboardDir) settings.SettingsDir = path.Clean(settings.SettingsDir) log.Println("Creating settingsDist directory...") TmpSettingsDistDirectory = path.Join(SettingsDistDir, ".tmp") if _, err := os.Stat(TmpSettingsDistDirectory); os.IsNotExist(err) { if err = os.MkdirAll(TmpSettingsDistDirectory, 0751); err != nil { log.Fatal("Unable to create settingsdist directory:", err) } } TmpSettingsDirectory = path.Join(settings.SettingsDir, ".tmp") if _, err := os.Stat(TmpSettingsDirectory); os.IsNotExist(err) { if err = os.MkdirAll(TmpSettingsDirectory, 0751); err != nil { log.Fatal("Unable to create settings directory:", err) } } log.Println("Registering directory events...") watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal(err) } defer watcher.Close() lDashboard := &distList{} lDashboard.Timer = time.NewTimer(time.Minute) if err := watchsubdir(lDashboard, watcher, DashboardDir, newDashboardFile); err != nil { log.Fatal(err) } lSettings := &distList{} lSettings.Timer = time.NewTimer(time.Minute) if err := watchsubdir(lSettings, watcher, settings.SettingsDir, newSettingsFile); err != nil { log.Fatal(err) } // Register SIGUSR1 and SIGTERM interrupt1 := make(chan os.Signal, 1) signal.Notify(interrupt1, syscall.SIGUSR1) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, syscall.SIGTERM) treatNewFile := func(name string) { if strings.HasPrefix(name, DashboardDir) { newDashboardFile(lDashboard, name) } else { newSettingsFile(lSettings, name) } } loop: for { select { case <-interrupt: break loop case <-interrupt1: log.Println("SIGUSR1 received, displaying queues") log.Println("Seeing settings distlist") lSettings.Print() log.Println("Seeing dashboard distlist") lDashboard.Print() case <-lSettings.Timer.C: if v := lSettings.Pop(); v != nil { log.Printf("TREATING SETTINGS DIFF: %v", v) treatSettingsFile(v) } lSettings.ResetTimer() case <-lDashboard.Timer.C: if v := lDashboard.Pop(); v != nil { log.Printf("TREATING DASHBOARD DIFF: %v", v) if ndf, ok := v.(*NextDashboardFile); ok { treatDashboardFile(ndf) } } lDashboard.ResetTimer() case ev := <-watcher.Events: if d, err := os.Lstat(ev.Name); err == nil && ev.Op&watchedNotify == watchedNotify && d.Name() != ".tmp" && d.Mode().IsRegular() { if *debugINotify { log.Println("Treating event:", ev, "for", ev.Name) } treatNewFile(ev.Name) } else if ev.Op&fsnotify.Remove == fsnotify.Remove { if *debugINotify { log.Println("Treating deletion event:", ev, "for", ev.Name) } if strings.HasPrefix(ev.Name, DashboardDir) { if ts, err := parseDashboardFilename(path.Base(ev.Name)); err != nil { log.Println("Unable to parseint", ev.Name, err.Error()) } else { lDashboard.DelEvent(ts, nil) } } else { if ts, err := parseSettingsFilename(path.Base(ev.Name)); err != nil { log.Println("Unable to parseint", ev.Name, err.Error()) } else { lSettings.DelEvent(ts, updateNextSettingsTime) } } } else if err == nil && ev.Op&fsnotify.Write == fsnotify.Write { log.Println("FSNOTIFY WRITE SEEN. Prefer looking at them, as it appears files are not atomically moved.") watchedNotify = fsnotify.Write treatNewFile(ev.Name) } else if *debugINotify { log.Println("Skipped event:", ev, "for", ev.Name) } case err := <-watcher.Errors: log.Println("error:", err) } } }