diff --git a/evdist/dashboard.go b/evdist/dashboard.go index d60c82ea..b0f9ca71 100644 --- a/evdist/dashboard.go +++ b/evdist/dashboard.go @@ -78,7 +78,7 @@ func newDashboardFile(l *distList, raw_path string) { Name: bpath, Screen: s, Date: activateTime, - }) + }, nil) } else { log.Println("WARNING: Unknown file to treat: not a valid timestamp:", err.Error()) } diff --git a/evdist/distlist.go b/evdist/distlist.go index c99cb0e6..108f7284 100644 --- a/evdist/distlist.go +++ b/evdist/distlist.go @@ -37,7 +37,7 @@ func (l *distList) TimerNextEvent() *time.Timer { return time.NewTimer(time.Until(*min)) } -func (l *distList) AddEvent(nsf DistEvent) { +func (l *distList) AddEvent(nsf DistEvent, firstItemChanged func(DistEvent)) { l.Lock.Lock() istop := len(l.List) @@ -59,10 +59,13 @@ func (l *distList) AddEvent(nsf DistEvent) { if istop == 0 { l.ResetTimer() + if firstItemChanged != nil { + firstItemChanged(nsf) + } } } -func (l *distList) DelEvent(id int64) { +func (l *distList) DelEvent(id int64, firstItemChanged func(DistEvent)) { l.Lock.Lock() istop := len(l.List) @@ -83,6 +86,13 @@ func (l *distList) DelEvent(id int64) { if istop == 0 { l.ResetTimer() + if firstItemChanged != nil { + if len(l.List) == 0 { + firstItemChanged(nil) + } else { + firstItemChanged(l.List[0]) + } + } } } diff --git a/evdist/main.go b/evdist/main.go index 2b3b18f3..298b592c 100644 --- a/evdist/main.go +++ b/evdist/main.go @@ -19,6 +19,7 @@ import ( 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) @@ -93,8 +94,6 @@ func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, syscall.SIGTERM) - watchedNotify := fsnotify.Create - treatNewFile := func(name string) { if strings.HasPrefix(name, DashboardDir) { newDashboardFile(lDashboard, name) @@ -139,16 +138,16 @@ loop: log.Println("Treating deletion event:", ev, "for", ev.Name) } if strings.HasPrefix(ev.Name, DashboardDir) { - if ts, err := parseDashboardFilename(ev.Name); err == nil { + if ts, err := parseDashboardFilename(path.Base(ev.Name)); err != nil { log.Println("Unable to parseint", ev.Name, err.Error()) } else { - lDashboard.DelEvent(ts) + lDashboard.DelEvent(ts, nil) } } else { - if ts, err := parseSettingsFilename(ev.Name); err == nil { + if ts, err := parseSettingsFilename(path.Base(ev.Name)); err != nil { log.Println("Unable to parseint", ev.Name, err.Error()) } else { - lSettings.DelEvent(ts) + lSettings.DelEvent(ts, updateNextSettingsTime) } } } else if err == nil && ev.Op&fsnotify.Write == fsnotify.Write { diff --git a/evdist/settings.go b/evdist/settings.go index a9011fa2..3bb31d22 100644 --- a/evdist/settings.go +++ b/evdist/settings.go @@ -12,8 +12,12 @@ import ( "time" "srs.epita.fr/fic-server/settings" + + "gopkg.in/fsnotify.v1" ) +var PublishNextChangeIndication = true + // NewDistList creates a distList from the given src directory func NewSettingsDistList(src string) (*distList, error) { list, err := settings.ListNextSettingsFiles() @@ -74,12 +78,33 @@ func newSettingsFile(l *distList, raw_path string) { l.AddEvent(&settings.NextSettingsFile{ Id: ts, Date: activateTime, - }) + }, updateNextSettingsTime) } else { log.Println("WARNING: Unknown file to treat: not a valid timestamp:", err.Error()) } } +func saveSettingsFile(cur_settings *settings.Settings) error { + if watchedNotify == fsnotify.Create { + err := settings.SaveSettings(path.Join(TmpSettingsDirectory, "settings.json"), cur_settings) + if err != nil { + return fmt.Errorf("Unable to save settings.json to tmp dir: %w", err) + } + + err = os.Rename(path.Join(TmpSettingsDirectory, "settings.json"), path.Join(settings.SettingsDir, "settings.json")) + if err != nil { + return fmt.Errorf("Unable to move settings.json to dest dir: %w", err) + } + } else { + err := settings.SaveSettings(path.Join(settings.SettingsDir, "settings.json"), cur_settings) + if err != nil { + return fmt.Errorf("Unable to save settings.json to tmp dir: %w", err) + } + } + + return nil +} + func treatSettingsFile(e DistEvent) { v, err := settings.ReadNextSettingsFile(path.Join(settings.SettingsDir, fmt.Sprintf("%d.json", e.GetId())), e.GetId()) if err != nil { @@ -89,12 +114,38 @@ func treatSettingsFile(e DistEvent) { } else { cur_settings = settings.MergeSettings(*cur_settings, v.Values) - if err = settings.SaveSettings(path.Join(TmpSettingsDirectory, "settings.json"), cur_settings); err != nil { - log.Printf("Unable to save settings.json to tmp dir: %s", err.Error()) - } else if err = os.Rename(path.Join(TmpSettingsDirectory, "settings.json"), path.Join(settings.SettingsDir, "settings.json")); err != nil { - log.Printf("Unable to move settings.json to dest dir: %s", err.Error()) + if err := saveSettingsFile(cur_settings); err != nil { + log.Printf(err.Error()) } else if err = os.Remove(path.Join(settings.SettingsDir, fmt.Sprintf("%d.json", v.Id))); err != nil { log.Printf("Unable to remove initial diff file (%d.json): %s", v.Id, err.Error()) } } } + +func updateNextSettingsTime(e DistEvent) { + if !PublishNextChangeIndication { + return + } + log.Println("Updating settings.json to include next settings time") + + cur_settings, err := settings.ReadSettings(path.Join(settings.SettingsDir, settings.SettingsFile)) + if err != nil { + log.Printf("Unable to read settings.json: %s", err.Error()) + return + } + + if e == nil { + cur_settings = settings.MergeSettings(*cur_settings, map[string]interface{}{ + "nextchangetime": nil, + }) + } else { + cur_settings = settings.MergeSettings(*cur_settings, map[string]interface{}{ + "nextchangetime": *e.GetDate(), + }) + } + + err = saveSettingsFile(cur_settings) + if err != nil { + log.Printf(err.Error()) + } +} diff --git a/settings/settings.go b/settings/settings.go index e9ff3764..ecec2ce9 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -29,8 +29,8 @@ type Settings struct { Start time.Time `json:"start"` // End is the expected end time (if empty their is no end-date). End *time.Time `json:"end,omitempty"` - // ActivateTime is the time when the current file should be proceed. - ActivateTime time.Time `json:"activateTime"` + // NextChangeTime is the time of the next expected reload. + NextChangeTime *time.Time `json:"nextchangetime,omitempty"` // FirstBlood is the coefficient applied to each first team who solve a challenge. FirstBlood float64 `json:"firstBlood"` @@ -193,11 +193,6 @@ func LoadAndWatchSettings(settingsPath string, reload func(*Settings)) { func tryReload(settingsPath string, reload func(*Settings)) { if config, err := ReadSettings(settingsPath); err != nil { log.Println("ERROR: Unable to read challenge settings:", err) - } else if time.Until(config.ActivateTime) > 0 { - log.Println("Configuration reloading postponed, activating at:", config.ActivateTime) - time.Sleep(time.Until(config.ActivateTime)) - log.Println("Time to activate configuration...") - tryReload(settingsPath, reload) } else { reload(config) }