challenge-sync-airbus: Done
This commit is contained in:
parent
268925db0d
commit
0d5b87b3f7
@ -1,14 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AirbusAPI struct {
|
type AirbusAPI struct {
|
||||||
@ -18,14 +19,18 @@ type AirbusAPI struct {
|
|||||||
SessionUUID string
|
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 req *http.Request
|
||||||
var err error
|
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 {
|
if data != nil {
|
||||||
req, err = http.NewRequest(method, a.BaseURL+endpoint, bytes.NewReader(data))
|
req, err = http.NewRequest(method, a.BaseURL+endpoint, data)
|
||||||
} else {
|
} else {
|
||||||
req, err = http.NewRequest(method, a.BaseURL+endpoint, nil)
|
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("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 {
|
if err != nil {
|
||||||
return fmt.Errorf("error during request execution to %q: %w", endpoint, err)
|
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) {
|
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 {
|
if dryRun {
|
||||||
log.Printf("ValidateChallenge: %d, %s, %d", a.SessionID, challengeId.String(), team.Members[0].ID)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,17 +179,17 @@ func (a *AirbusAPI) AwardUser(team *AirbusTeam, value int64, message string) (er
|
|||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("AwardUser: %v", awards)
|
||||||
if dryRun {
|
if dryRun {
|
||||||
log.Printf("AwardUser: %v", awards)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
j, err := json.Marshal(awards)
|
data := url.Values{}
|
||||||
if err != nil {
|
data.Set("gaming_user_id", fmt.Sprintf("%d", awards.UserId))
|
||||||
return fmt.Errorf("unable to marshall JSON from awards struct: %w", err)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,12 @@ func main() {
|
|||||||
break
|
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 {
|
if v, exists := os.LookupEnv("AIRBUS_SESSIONUUID"); exists {
|
||||||
@ -83,6 +89,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Unable to open teams bindings file: ", err.Error())
|
log.Fatal("Unable to open teams bindings file: ", err.Error())
|
||||||
}
|
}
|
||||||
|
log.Println("Team bindings loaded: ", len(teamsbindings))
|
||||||
|
|
||||||
w := Walker{
|
w := Walker{
|
||||||
LastSync: ts,
|
LastSync: ts,
|
||||||
@ -103,10 +110,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !skipInitialSync {
|
if !skipInitialSync {
|
||||||
// Iterate over teams scores
|
err = w.BalanceScores()
|
||||||
err = filepath.WalkDir(TeamsDir, w.WalkScoreSync)
|
|
||||||
if err != nil {
|
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
|
// save current timestamp for teams
|
||||||
@ -116,6 +122,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("initial sync done")
|
||||||
|
|
||||||
if daemon != nil && *daemon {
|
if daemon != nil && *daemon {
|
||||||
// Watch teams.json and scores.json
|
// Watch teams.json and scores.json
|
||||||
log.Println("Registering directory events...")
|
log.Println("Registering directory events...")
|
||||||
@ -196,7 +204,7 @@ func main() {
|
|||||||
if err := watchsubdir(watcher, ev.Name); err != nil {
|
if err := watchsubdir(watcher, ev.Name); err != nil {
|
||||||
log.Println(err)
|
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 {
|
if *debugINotify {
|
||||||
log.Println("Treating event:", ev, "for", ev.Name)
|
log.Println("Treating event:", ev, "for", ev.Name)
|
||||||
}
|
}
|
||||||
@ -213,10 +221,10 @@ func main() {
|
|||||||
log.Fatal("Unable to fetch teams: ", err.Error())
|
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.")
|
log.Println("FSNOTIFY WRITE SEEN. Prefer looking at them, as it appears files are not atomically moved.")
|
||||||
watchedNotify = fsnotify.Write
|
watchedNotify = fsnotify.Write
|
||||||
} else if *debugINotify {
|
} else if err == nil && *debugINotify {
|
||||||
log.Println("Skipped event:", ev, "for", ev.Name)
|
log.Println("Skipped event:", ev, "for", ev.Name)
|
||||||
}
|
}
|
||||||
case err := <-watcher.Errors:
|
case err := <-watcher.Errors:
|
||||||
|
@ -10,6 +10,6 @@ type Session struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AirbusAPI) GetSessions() (ret []Session, err error) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ type airbusDataTeam struct {
|
|||||||
|
|
||||||
func (a *AirbusAPI) GetTeams() ([]AirbusTeam, error) {
|
func (a *AirbusAPI) GetTeams() ([]AirbusTeam, error) {
|
||||||
var data airbusDataTeam
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -32,6 +33,15 @@ func loadTS(tspath string) (timestamp map[string]*TSValue, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func saveTS(tspath string, ts map[string]*TSValue) 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 {
|
if fd, err := os.Create(tspath); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
)
|
)
|
||||||
@ -51,12 +52,14 @@ func (w *Walker) fetchTeams() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Walker) treat(path string) {
|
func (w *Walker) treat(path string) error {
|
||||||
teamid := filepath.Base(filepath.Dir(path))
|
teamid := filepath.Base(filepath.Dir(path))
|
||||||
|
|
||||||
if _, ok := w.TeamBindings[teamid]; ok {
|
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) {
|
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 {
|
func (w *Walker) WalkScoreSync(path string, d os.DirEntry, err error) error {
|
||||||
if filepath.Base(path) == "scores.json" {
|
if filepath.Base(path) == "scores.json" {
|
||||||
w.treat(path)
|
return 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
|
return nil
|
||||||
@ -174,7 +154,9 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Found all new entries
|
// Found all new entries
|
||||||
maxts := &TSValue{}
|
maxts := &TSValue{
|
||||||
|
Time: time.Time{},
|
||||||
|
}
|
||||||
if ts, ok := w.LastSync[airbusTeam.Name]; ok {
|
if ts, ok := w.LastSync[airbusTeam.Name]; ok {
|
||||||
maxts = ts
|
maxts = ts
|
||||||
}
|
}
|
||||||
@ -182,7 +164,7 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error {
|
|||||||
if row.Time.After(maxts.Time) {
|
if row.Time.After(maxts.Time) {
|
||||||
maxts.Time = row.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" {
|
if !noValidateChallenge && row.Reason == "Validation" {
|
||||||
err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice])
|
err = w.API.ValidateChallengeFromUser(airbusTeam, w.Exercices[row.IdExercice])
|
||||||
} else {
|
} else {
|
||||||
@ -202,29 +184,29 @@ func (w *Walker) TreatScoreGrid(path string, airbusTeam *AirbusTeam) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Walker) BalanceScore(score int64, airbusTeam *AirbusTeam) error {
|
func (w *Walker) BalanceScores() error {
|
||||||
// Read current score on other platform
|
for team, ts := range w.LastSync {
|
||||||
stats, err := w.API.GetCurrentStats()
|
team_id, ok := w.RevTeams[team]
|
||||||
if err != nil {
|
if !ok {
|
||||||
fmt.Errorf("unable to retrieve current stats: %w", err)
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
my_session := stats.Data.GetSession(AirbusUUID(w.API.SessionUUID))
|
myteam, err := w.loadMyFile(filepath.Join(TeamsDir, team_id, "my.json"))
|
||||||
if my_session == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("session not found")
|
return fmt.Errorf("Unable to open %s/my.json: %w", team_id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
other_team := my_session.GetTeam(AirbusUUID(airbusTeam.Name))
|
airbusTeam := w.TeamBindings[fmt.Sprintf("%d", myteam.Id)]
|
||||||
if other_team == nil {
|
|
||||||
return fmt.Errorf("team %q not found", airbusTeam.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
w.LastSync[airbusTeam.Name].Score = myteam.Points * int64(w.Coeff)
|
||||||
if other_score != score {
|
w.LastSync[airbusTeam.Name].Time = time.Now()
|
||||||
diff := score - other_score
|
}
|
||||||
return w.API.AwardUser(airbusTeam, diff, "Équilibrage")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
x
Reference in New Issue
Block a user