From 0d5b87b3f74539bb086f1c1bc8878209abd27850 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Thu, 6 Apr 2023 15:37:05 +0200 Subject: [PATCH] challenge-sync-airbus: Done --- remote/challenge-sync-airbus/api.go | 31 +++++---- remote/challenge-sync-airbus/main.go | 20 ++++-- remote/challenge-sync-airbus/session.go | 2 +- remote/challenge-sync-airbus/team.go | 2 +- remote/challenge-sync-airbus/timestamp.go | 10 +++ remote/challenge-sync-airbus/treat.go | 76 +++++++++-------------- 6 files changed, 73 insertions(+), 68 deletions(-) diff --git a/remote/challenge-sync-airbus/api.go b/remote/challenge-sync-airbus/api.go index 9f4cc4a2..3ef8c0e3 100644 --- a/remote/challenge-sync-airbus/api.go +++ b/remote/challenge-sync-airbus/api.go @@ -1,14 +1,15 @@ package main import ( - "bytes" "crypto/tls" "encoding/json" "fmt" "io" "log" "net/http" + "net/url" "strconv" + "strings" ) type AirbusAPI struct { @@ -18,14 +19,18 @@ type AirbusAPI struct { SessionUUID string } -func (a *AirbusAPI) request(method, endpoint string, data []byte, out interface{}) error { +func (a *AirbusAPI) request(method, endpoint string, data io.Reader, out interface{}) error { var req *http.Request var err error - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + } if data != nil { - req, err = http.NewRequest(method, a.BaseURL+endpoint, bytes.NewReader(data)) + req, err = http.NewRequest(method, a.BaseURL+endpoint, data) } else { req, err = http.NewRequest(method, a.BaseURL+endpoint, nil) } @@ -34,9 +39,9 @@ func (a *AirbusAPI) request(method, endpoint string, data []byte, out interface{ } req.Header.Add("Authorization", "Bearer "+a.Token) - req.Header.Add("Content-Type", "application/json") + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - resp, err := http.DefaultClient.Do(req) + resp, err := client.Do(req) if err != nil { return fmt.Errorf("error during request execution to %q: %w", endpoint, err) } @@ -152,8 +157,8 @@ func (a *AirbusAPI) GetChallengeFromName(name string) (*AirbusChallenge, error) } func (a *AirbusAPI) ValidateChallengeFromUser(team *AirbusTeam, challengeId AirbusChallengeId) (err error) { + log.Printf("ValidateChallenge: %d, %s, %d", a.SessionID, challengeId.String(), team.Members[0].ID) if dryRun { - log.Printf("ValidateChallenge: %d, %s, %d", a.SessionID, challengeId.String(), team.Members[0].ID) return } @@ -174,17 +179,17 @@ func (a *AirbusAPI) AwardUser(team *AirbusTeam, value int64, message string) (er Value: value, } + log.Printf("AwardUser: %v", awards) if dryRun { - log.Printf("AwardUser: %v", awards) return } - j, err := json.Marshal(awards) - if err != nil { - return fmt.Errorf("unable to marshall JSON from awards struct: %w", err) - } + data := url.Values{} + data.Set("gaming_user_id", fmt.Sprintf("%d", awards.UserId)) + data.Set("name", awards.Message) + data.Set("value", fmt.Sprintf("%d", awards.Value)) - err = a.request("POST", fmt.Sprintf("/v1/sessions/%d/awards", a.SessionID), j, nil) + err = a.request("POST", fmt.Sprintf("/v1/sessions/%d/awards", a.SessionID), strings.NewReader(data.Encode()), nil) if err != nil { return err } diff --git a/remote/challenge-sync-airbus/main.go b/remote/challenge-sync-airbus/main.go index de0f1941..7bd16a65 100644 --- a/remote/challenge-sync-airbus/main.go +++ b/remote/challenge-sync-airbus/main.go @@ -62,6 +62,12 @@ func main() { break } } + + if api.SessionID == 0 { + log.Fatal("Session ID not found") + } else { + log.Println("Session ID discovered: ", api.SessionID) + } } if v, exists := os.LookupEnv("AIRBUS_SESSIONUUID"); exists { @@ -83,6 +89,7 @@ func main() { if err != nil { log.Fatal("Unable to open teams bindings file: ", err.Error()) } + log.Println("Team bindings loaded: ", len(teamsbindings)) w := Walker{ LastSync: ts, @@ -103,10 +110,9 @@ func main() { } if !skipInitialSync { - // Iterate over teams scores - err = filepath.WalkDir(TeamsDir, w.WalkScoreSync) + err = w.BalanceScores() if err != nil { - log.Println("Something goes wrong during walking: ", err.Error()) + log.Println("Something goes wrong during score balance: ", err.Error()) } // save current timestamp for teams @@ -116,6 +122,8 @@ func main() { } } + log.Println("initial sync done") + if daemon != nil && *daemon { // Watch teams.json and scores.json log.Println("Registering directory events...") @@ -196,7 +204,7 @@ func main() { if err := watchsubdir(watcher, ev.Name); err != nil { log.Println(err) } - } else if ev.Op&watchedNotify == watchedNotify && d.Mode().IsRegular() { + } else if err == nil && ev.Op&watchedNotify == watchedNotify && d.Mode().IsRegular() { if *debugINotify { log.Println("Treating event:", ev, "for", ev.Name) } @@ -213,10 +221,10 @@ func main() { log.Fatal("Unable to fetch teams: ", err.Error()) } } - } else if ev.Op&fsnotify.Write == fsnotify.Write { + } 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 - } else if *debugINotify { + } else if err == nil && *debugINotify { log.Println("Skipped event:", ev, "for", ev.Name) } case err := <-watcher.Errors: diff --git a/remote/challenge-sync-airbus/session.go b/remote/challenge-sync-airbus/session.go index 67c7b563..f10b8474 100644 --- a/remote/challenge-sync-airbus/session.go +++ b/remote/challenge-sync-airbus/session.go @@ -10,6 +10,6 @@ type Session struct { } func (a *AirbusAPI) GetSessions() (ret []Session, err error) { - err = a.request("GET", "/api/v1/sessions", nil, &ret) + err = a.request("GET", "/v1/sessions", nil, &ret) return } diff --git a/remote/challenge-sync-airbus/team.go b/remote/challenge-sync-airbus/team.go index 69d5db23..e3bba27d 100644 --- a/remote/challenge-sync-airbus/team.go +++ b/remote/challenge-sync-airbus/team.go @@ -23,7 +23,7 @@ type airbusDataTeam struct { func (a *AirbusAPI) GetTeams() ([]AirbusTeam, error) { var data airbusDataTeam - err := a.request("GET", fmt.Sprintf("/api/v1/sessions/%d/teams", a.SessionID), nil, &data) + err := a.request("GET", fmt.Sprintf("/v1/sessions/%d/teams", a.SessionID), nil, &data) if err != nil { return nil, err } else { diff --git a/remote/challenge-sync-airbus/timestamp.go b/remote/challenge-sync-airbus/timestamp.go index d9610366..47133e56 100644 --- a/remote/challenge-sync-airbus/timestamp.go +++ b/remote/challenge-sync-airbus/timestamp.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "log" "os" "time" ) @@ -32,6 +33,15 @@ func loadTS(tspath string) (timestamp map[string]*TSValue, err error) { } func saveTS(tspath string, ts map[string]*TSValue) error { + if dryRun { + tmp := map[string]TSValue{} + for k, v := range ts { + tmp[k] = *v + } + log.Println("saving TS: ", tmp) + return nil + } + if fd, err := os.Create(tspath); err != nil { return err } else { diff --git a/remote/challenge-sync-airbus/treat.go b/remote/challenge-sync-airbus/treat.go index aefc8d8d..562a1713 100644 --- a/remote/challenge-sync-airbus/treat.go +++ b/remote/challenge-sync-airbus/treat.go @@ -6,6 +6,7 @@ import ( "log" "os" "path/filepath" + "time" "srs.epita.fr/fic-server/libfic" ) @@ -51,12 +52,14 @@ func (w *Walker) fetchTeams() error { return nil } -func (w *Walker) treat(path string) { +func (w *Walker) treat(path string) error { teamid := filepath.Base(filepath.Dir(path)) if _, ok := w.TeamBindings[teamid]; ok { - w.TreatScoreGrid(path, w.TeamBindings[teamid]) + return w.TreatScoreGrid(path, w.TeamBindings[teamid]) } + + return nil } func (w *Walker) LoadScoreState(path string) (int64, error) { @@ -107,30 +110,7 @@ func (w *Walker) LoadScoreGrid(path string) ([]fic.ScoreGridRow, error) { 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 w.treat(path) } return nil @@ -174,7 +154,9 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { } // Found all new entries - maxts := &TSValue{} + maxts := &TSValue{ + Time: time.Time{}, + } if ts, ok := w.LastSync[airbusTeam.Name]; ok { maxts = ts } @@ -182,7 +164,7 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { if row.Time.After(maxts.Time) { maxts.Time = row.Time } - if row.Time.After(w.LastSync[airbusTeam.Name].Time) { + if ts, ok := w.LastSync[airbusTeam.Name]; !ok || row.Time.After(ts.Time) { if !noValidateChallenge && row.Reason == "Validation" { err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice]) } else { @@ -202,29 +184,29 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error { 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) - } +func (w *Walker) BalanceScores() error { + for team, ts := range w.LastSync { + team_id, ok := w.RevTeams[team] + if !ok { + continue + } - my_session := stats.Data.GetSession(AirbusUUID(w.API.SessionUUID)) - if my_session == nil { - return fmt.Errorf("session not found") - } + 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) + } - other_team := my_session.GetTeam(AirbusUUID(airbusTeam.Name)) - if other_team == nil { - return fmt.Errorf("team %q not found", airbusTeam.Name) - } + airbusTeam := w.TeamBindings[fmt.Sprintf("%d", myteam.Id)] - other_score := other_team.Score + if ts.Score != myteam.Points*int64(w.Coeff) { + err := w.API.AwardUser(airbusTeam, myteam.Points*int64(w.Coeff)-ts.Score, "Équilibrage") + if err != nil { + return fmt.Errorf("Unable to open %s/my.json: %w", team, err) + } - // Send diff to the platform - if other_score != score { - diff := score - other_score - return w.API.AwardUser(airbusTeam, diff, "Équilibrage") + w.LastSync[airbusTeam.Name].Score = myteam.Points * int64(w.Coeff) + w.LastSync[airbusTeam.Name].Time = time.Now() + } } return nil