challenge-sync-airbus: Done
This commit is contained in:
parent
268925db0d
commit
0d5b87b3f7
@ -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) {
|
||||
if dryRun {
|
||||
log.Printf("ValidateChallenge: %d, %s, %d", a.SessionID, challengeId.String(), team.Members[0].ID)
|
||||
if dryRun {
|
||||
return
|
||||
}
|
||||
|
||||
@ -174,17 +179,17 @@ func (a *AirbusAPI) AwardUser(team *AirbusTeam, value int64, message string) (er
|
||||
Value: value,
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
log.Printf("AwardUser: %v", awards)
|
||||
if dryRun {
|
||||
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
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
func (w *Walker) BalanceScores() error {
|
||||
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 {
|
||||
fmt.Errorf("unable to retrieve current stats: %w", err)
|
||||
return fmt.Errorf("Unable to open %s/my.json: %w", team_id, err)
|
||||
}
|
||||
|
||||
my_session := stats.Data.GetSession(AirbusUUID(w.API.SessionUUID))
|
||||
if my_session == nil {
|
||||
return fmt.Errorf("session not found")
|
||||
airbusTeam := w.TeamBindings[fmt.Sprintf("%d", myteam.Id)]
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
other_team := my_session.GetTeam(AirbusUUID(airbusTeam.Name))
|
||||
if other_team == nil {
|
||||
return fmt.Errorf("team %q not found", airbusTeam.Name)
|
||||
w.LastSync[airbusTeam.Name].Score = myteam.Points * int64(w.Coeff)
|
||||
w.LastSync[airbusTeam.Name].Time = time.Now()
|
||||
}
|
||||
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user