server/evdist/main.go

165 lines
4.7 KiB
Go

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)
}
}
}