package main import ( "fmt" "io" "io/ioutil" "log" "os" "path" "strconv" "strings" "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() if err != nil { return nil, err } var dlist []DistEvent for _, e := range list { dlist = append(dlist, e) } return &distList{List: dlist, Timer: time.NewTimer(time.Minute)}, nil } func parseSettingsFilename(fname string) (int64, error) { return strconv.ParseInt(strings.TrimSuffix(fname, ".json"), 10, 64) } func newSettingsFile(l *distList, raw_path string) { bpath := path.Base(raw_path) if bpath == "challenge.json" || bpath == "settings.json" { log.Printf("Copying %s to SETTINGDIST...", bpath) // Copy content through tmp file fd, err := os.Open(raw_path) if err != nil { log.Printf("ERROR: Unable to open %s: %s", raw_path, err.Error()) return } defer fd.Close() tmpfile, err := ioutil.TempFile(TmpSettingsDistDirectory, "") if err != nil { log.Printf("ERROR: Unable to create temporary file for %s: %s", bpath, err.Error()) return } _, err = io.Copy(tmpfile, fd) tmpfile.Close() if err != nil { log.Printf("ERROR: Unable to copy content to temporary file (%s): %s", bpath, err.Error()) return } os.Chmod(tmpfile.Name(), 0644) if err = os.Rename(tmpfile.Name(), path.Join(SettingsDistDir, bpath)); err != nil { log.Println("ERROR: Unable to move file:", err) return } } else if ts, err := parseSettingsFilename(bpath); err == nil { activateTime := time.Unix(ts, 0) log.Printf("Preparing %s: activation time at %s", bpath, activateTime) 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 { log.Printf("Unable to read json: %s", err.Error()) } else if cur_settings, err := settings.ReadSettings(path.Join(settings.SettingsDir, settings.SettingsFile)); err != nil { log.Printf("Unable to read settings.json: %s", err.Error()) } else { cur_settings = settings.MergeSettings(*cur_settings, v.Values) 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()) } }