challenge-sync-airbus: Do job

This commit is contained in:
nemunaire 2023-04-06 03:48:52 +02:00
commit 3344e05e0d
6 changed files with 256 additions and 65 deletions

View file

@ -1,11 +1,11 @@
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"time"
"srs.epita.fr/fic-server/libfic"
)
@ -15,55 +15,144 @@ var (
)
type Walker struct {
LastSync map[AirbusUserId]time.Time
Exercices AirbusExercicesBindings
Teams map[string]fic.ExportedTeam
API AirbusAPI
Coeff float64
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) {
mypath := filepath.Join(filepath.Dir(path), "my.json")
if _, err := os.Stat(mypath); !os.IsNotExist(err) {
// Read team ID
fdmy, err := os.Open(mypath)
if err != nil {
log.Println("Unable to open my.json:", err)
return
}
defer fdmy.Close()
teamid := filepath.Base(filepath.Dir(path))
teammy, err := fic.ReadMyJSON(fdmy)
if err != nil {
log.Println("Unable to parse my.json:", err)
return
}
airbusTeamId := NewAirbusUserId(w.Teams[fmt.Sprintf("%d", teammy.Id)].ExternalId)
// Treat score grid
/*err = w.TreatScoreGrid(path, airbusTeamId)
if err != nil {
log.Println("Unable to treat score grid:", err)
return
}*/
// Balance scores
err = w.BalanceScore(int64(float64(teammy.Points)*w.Coeff), airbusTeamId)
if err != nil {
log.Println("Unable to balance score:", err)
return
}
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)
@ -71,7 +160,7 @@ func (w *Walker) WalkScore(path string, d os.DirEntry, err error) error {
return nil
}
func (w *Walker) TreatScoreGrid(path string, airbusTeamId AirbusUserId) error {
func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error {
// Read score grid
fdscores, err := os.Open(path)
if err != nil {
@ -85,30 +174,35 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeamId AirbusUserId) error {
}
// Found all new entries
maxts := w.LastSync[airbusTeamId]
maxts := &TSValue{}
if ts, ok := w.LastSync[airbusTeam.Name]; ok {
maxts = ts
}
for _, row := range teamscores {
if row.Time.After(maxts) {
maxts = row.Time
if row.Time.After(maxts.Time) {
maxts.Time = row.Time
}
if row.Time.After(w.LastSync[airbusTeamId]) {
if row.Time.After(w.LastSync[airbusTeam.Name].Time) {
if !noValidateChallenge && row.Reason == "Validation" {
err = w.API.ValidateChallengeFromUser(airbusTeamId, w.Exercices[row.IdExercice])
err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice])
} else {
err = w.API.AwardUser(airbusTeamId, int64(row.Points*row.Coeff*w.Coeff), row.Reason)
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[airbusTeamId] = maxts
w.LastSync[airbusTeam.Name] = maxts
return nil
}
func (w *Walker) BalanceScore(score int64, airbusTeamId AirbusUserId) error {
func (w *Walker) BalanceScore(score int64, airbusTeam *AirbusTeam) error {
// Read current score on other platform
stats, err := w.API.GetCurrentStats()
if err != nil {
@ -120,9 +214,9 @@ func (w *Walker) BalanceScore(score int64, airbusTeamId AirbusUserId) error {
return fmt.Errorf("session not found")
}
other_team := my_session.GetTeam(AirbusUUID(airbusTeamId))
other_team := my_session.GetTeam(AirbusUUID(airbusTeam.Name))
if other_team == nil {
return fmt.Errorf("team %q not found", airbusTeamId)
return fmt.Errorf("team %q not found", airbusTeam.Name)
}
other_score := other_team.Score
@ -130,7 +224,7 @@ func (w *Walker) BalanceScore(score int64, airbusTeamId AirbusUserId) error {
// Send diff to the platform
if other_score != score {
diff := score - other_score
return w.API.AwardUser(airbusTeamId, diff, "Équilibrage")
return w.API.AwardUser(airbusTeam, diff, "Équilibrage")
}
return nil