package main import ( "encoding/json" "fmt" "log" "os" "path/filepath" "srs.epita.fr/fic-server/libfic" ) var ( noValidateChallenge bool ) type Walker struct { LastSync map[string]*TSValue Exercices AirbusExercicesBindings Teams map[string]fic.ExportedTeam RevTeams map[string]string TeamBindings map[string]*AirbusTeam API AirbusAPI Coeff float64 } func (w *Walker) fetchTeams() error { teams, err := w.API.GetTeams() if err != nil { return err } w.RevTeams = map[string]string{} w.TeamBindings = map[string]*AirbusTeam{} for tid, team := range w.Teams { for _, t := range teams { if team.Name == t.Name || team.ExternalId == t.Name { w.TeamBindings[tid] = &t break } } if _, ok := w.TeamBindings[tid]; !ok { log.Printf("Team binding not found: %s - %s", tid, team.Name) } w.RevTeams[team.Name] = tid } return nil } func (w *Walker) treat(path string) { teamid := filepath.Base(filepath.Dir(path)) if _, ok := w.TeamBindings[teamid]; ok { w.TreatScoreGrid(path, w.TeamBindings[teamid]) } } func (w *Walker) LoadScoreState(path string) (int64, error) { mypath := filepath.Join(filepath.Dir(path), "airbus.json") if _, err := os.Stat(mypath); os.IsNotExist(err) { fd, err := os.Create(mypath) if err != nil { return 0, err } defer fd.Close() fd.Write([]byte("0")) return 0, nil } fd, err := os.Open(mypath) if err != nil { return 0, err } defer fd.Close() var ret int64 jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return 0, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return ret, nil } func (w *Walker) LoadScoreGrid(path string) ([]fic.ScoreGridRow, error) { fd, err := os.Open(filepath.Join(filepath.Dir(path), "scores.json")) if err != nil { return nil, err } defer fd.Close() var ret []fic.ScoreGridRow jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return nil, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return ret, nil } func (w *Walker) WalkScoreSync(path string, d os.DirEntry, err error) error { if filepath.Base(path) == "scores.json" { w.treat(path) } for team, ts := range w.LastSync { team_id, ok := w.RevTeams[team] if !ok { continue } myteam, err := w.loadMyFile(filepath.Join(TeamsDir, team_id, "my.json")) if err != nil { return fmt.Errorf("Unable to open %s/my.json: %w", team_id, err) } airbusTeam := w.TeamBindings[fmt.Sprintf("%d", myteam.Id)] if ts.Score != myteam.Points*int64(w.Coeff) { err := w.API.AwardUser(airbusTeam, myteam.Points-ts.Score, "Équilibrage") if err != nil { return fmt.Errorf("Unable to open %s/my.json: %w", team, err) } w.LastSync[airbusTeam.Name].Score = myteam.Points * int64(w.Coeff) } } return nil } func (w *Walker) loadMyFile(path string) (*fic.MyTeam, error) { fd, err := os.Open(path) if err != nil { return nil, err } defer fd.Close() var ret fic.MyTeam jdec := json.NewDecoder(fd) if err := jdec.Decode(&ret); err != nil { return nil, fmt.Errorf("an error occurs when trying to decode airbus.json: %w", err) } return &ret, nil } func (w *Walker) WalkScore(path string, d os.DirEntry, err error) error { if filepath.Base(path) == "scores.json" { go w.treat(path) } return nil } func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { // Read score grid fdscores, err := os.Open(path) if err != nil { return err } defer fdscores.Close() teamscores, err := fic.ReadScoreGrid(fdscores) if err != nil { return err } // Found all new entries maxts := &TSValue{} if ts, ok := w.LastSync[airbusTeam.Name]; ok { maxts = ts } for _, row := range teamscores { if row.Time.After(maxts.Time) { maxts.Time = row.Time } if row.Time.After(w.LastSync[airbusTeam.Name].Time) { if !noValidateChallenge && row.Reason == "Validation" { err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice]) } else { err = w.API.AwardUser(airbusTeam, int64(row.Points*row.Coeff*w.Coeff), row.Reason) } if err != nil { return err } maxts.Score += int64(row.Points * row.Coeff * w.Coeff) } } w.LastSync[airbusTeam.Name] = maxts return nil } func (w *Walker) BalanceScore(score int64, airbusTeam *AirbusTeam) error { // Read current score on other platform stats, err := w.API.GetCurrentStats() if err != nil { fmt.Errorf("unable to retrieve current stats: %w", err) } my_session := stats.Data.GetSession(AirbusUUID(w.API.SessionUUID)) if my_session == nil { return fmt.Errorf("session not found") } other_team := my_session.GetTeam(AirbusUUID(airbusTeam.Name)) if other_team == nil { return fmt.Errorf("team %q not found", airbusTeam.Name) } other_score := other_team.Score // Send diff to the platform if other_score != score { diff := score - other_score return w.API.AwardUser(airbusTeam, diff, "Équilibrage") } return nil }