better sharecode api handling, renamed endpoint to /player/id/track

This commit is contained in:
2021-10-17 12:27:35 +02:00
parent 9973951d4b
commit d39cdf8ed6
3 changed files with 114 additions and 15 deletions

101
main.go
View File

@@ -90,8 +90,22 @@ func housekeeping() {
for _, tPlayer := range tPlayerNeedShareCodeUpdate { for _, tPlayer := range tPlayerNeedShareCodeUpdate {
shareCodes, err := utils.GetNewShareCodesForPlayer(tPlayer, db.Lock, conf.Steam.APIKey, rL) shareCodes, err := utils.GetNewShareCodesForPlayer(tPlayer, db.Lock, conf.Steam.APIKey, rL)
if err != nil { if err != nil {
log.Errorf("[HK] Error while request sharecodes: %v", err) switch err.(type) {
continue case utils.AuthcodeUnauthorizedError:
db.Lock.Lock()
err = tPlayer.Update().ClearAuthCode().ClearSharecodeUpdated().Exec(context.Background())
db.Lock.Unlock()
if err != nil {
log.Warningf("[HK] Unable to clear authcode for player %d: %v", tPlayer.ID, err)
}
continue
case utils.SharecodeNoMatchError:
log.Warningf("[HK] last shareCode for player %d does not match player", tPlayer.ID)
continue
default:
log.Errorf("[HK] Error while request sharecodes: %v", err)
continue
}
} }
for _, code := range shareCodes { for _, code := range shareCodes {
@@ -256,11 +270,62 @@ func getPlayer(w http.ResponseWriter, r *http.Request) {
} }
} }
func postPlayerTrackMe(w http.ResponseWriter, r *http.Request) { func deletePlayerTrack(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", conf.Httpd.CORSAllowDomains) w.Header().Set("Access-Control-Allow-Origin", conf.Httpd.CORSAllowDomains)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
log.Infof("[PPTM] Unable to parse form data: %v", err) log.Infof("[DPT] Unable to parse form data: %v", err)
w.WriteHeader(http.StatusBadRequest)
return
}
id := r.Form.Get("id")
authCode := r.Form.Get("authcode")
if id == "" || authCode == "" || !utils.AuthCodeRegEx.MatchString(authCode) {
log.Infof("[PPTM] invalid arguments: %+v, %+v", id, authCode)
w.WriteHeader(http.StatusBadRequest)
return
}
tPlayer, err := utils.GetPlayer(db, id, conf.Steam.APIKey, rL)
if err != nil {
log.Infof("[PPT] player not found: %+v", err)
w.WriteHeader(http.StatusNotFound)
return
}
_, err = utils.IsAuthCodeValid(tPlayer, db.Lock, conf.Steam.APIKey, "", authCode, rL)
if err != nil {
switch e := err.(type) {
case utils.AuthcodeUnauthorizedError:
log.Infof("[DPT] authCode provided for player %s is invalid: %v", id, e)
w.WriteHeader(http.StatusUnauthorized)
return
default:
log.Infof("[DPT] Temporary Steam-API problem: %v", e)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
}
db.Lock.Lock()
err = tPlayer.Update().ClearAuthCode().ClearSharecodeUpdated().Exec(context.Background())
db.Lock.Unlock()
if err != nil {
log.Warningf("[PPT] update player failed: %+v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
func postPlayerTrack(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", conf.Httpd.CORSAllowDomains)
err := r.ParseForm()
if err != nil {
log.Infof("[PPT] Unable to parse form data: %v", err)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@@ -270,30 +335,41 @@ func postPlayerTrackMe(w http.ResponseWriter, r *http.Request) {
shareCode := r.Form.Get("sharecode") shareCode := r.Form.Get("sharecode")
if id == "" || authCode == "" || !utils.AuthCodeRegEx.MatchString(authCode) { if id == "" || authCode == "" || !utils.AuthCodeRegEx.MatchString(authCode) {
log.Infof("[PPTM] invalid arguments: %+v, %+v, %+v", id, authCode, shareCode) log.Infof("[PPT] invalid arguments: %+v, %+v, %+v", id, authCode, shareCode)
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
tPlayer, err := utils.GetPlayer(db, id, conf.Steam.APIKey, rL) tPlayer, err := utils.GetPlayer(db, id, conf.Steam.APIKey, rL)
if err != nil { if err != nil {
log.Infof("[PPTM] player not found: %+v", err) log.Infof("[PPT] player not found: %+v", err)
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
_, err = utils.IsAuthCodeValid(tPlayer, db.Lock, conf.Steam.APIKey, shareCode, authCode, rL) _, err = utils.IsAuthCodeValid(tPlayer, db.Lock, conf.Steam.APIKey, shareCode, authCode, rL)
if err != nil { if err != nil {
log.Infof("[PPTM] authCode provided for player %s is invalid: %v", id, err) switch e := err.(type) {
w.WriteHeader(http.StatusUnauthorized) case utils.AuthcodeUnauthorizedError:
return log.Infof("[PPT] authCode provided for player %s is invalid: %v", id, e)
w.WriteHeader(http.StatusUnauthorized)
return
case utils.SharecodeNoMatchError:
log.Infof("[PPT] shareCode provided for player %s is invalid: %v", id, e)
w.WriteHeader(http.StatusPreconditionFailed)
return
default:
log.Infof("[PPT] Temporary Steam-API problem: %v", e)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
} }
db.Lock.Lock() db.Lock.Lock()
err = tPlayer.Update().SetAuthCode(authCode).Exec(context.Background()) err = tPlayer.Update().SetAuthCode(authCode).Exec(context.Background())
db.Lock.Unlock() db.Lock.Unlock()
if err != nil { if err != nil {
log.Warningf("[PPTM] update player failed: %+v", err) log.Warningf("[PPT] update player failed: %+v", err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@@ -301,7 +377,7 @@ func postPlayerTrackMe(w http.ResponseWriter, r *http.Request) {
if shareCode != "" && utils.ShareCodeRegEx.MatchString(shareCode) { if shareCode != "" && utils.ShareCodeRegEx.MatchString(shareCode) {
err := demoLoader.LoadDemo(&csgo.Demo{ShareCode: shareCode}) err := demoLoader.LoadDemo(&csgo.Demo{ShareCode: shareCode})
if err != nil { if err != nil {
log.Warningf("[PPTM] unable to queue match: %v", err) log.Warningf("[PPT] unable to queue match: %v", err)
w.WriteHeader(http.StatusServiceUnavailable) w.WriteHeader(http.StatusServiceUnavailable)
return return
} }
@@ -611,7 +687,8 @@ func main() {
// Define routes // Define routes
router = mux.NewRouter().StrictSlash(true) router = mux.NewRouter().StrictSlash(true)
router.HandleFunc("/player/{id}", getPlayer).Methods(http.MethodGet, http.MethodOptions) router.HandleFunc("/player/{id}", getPlayer).Methods(http.MethodGet, http.MethodOptions)
router.HandleFunc("/player/trackme", postPlayerTrackMe).Methods(http.MethodPost, http.MethodOptions) router.HandleFunc("/player/{id}/track", postPlayerTrack).Methods(http.MethodPost, http.MethodOptions)
router.HandleFunc("/player/{id}/track", deletePlayerTrack).Methods(http.MethodOptions, http.MethodDelete)
router.HandleFunc("/match/parse/{sharecode}", getMatchParse).Methods(http.MethodGet, http.MethodOptions) router.HandleFunc("/match/parse/{sharecode}", getMatchParse).Methods(http.MethodGet, http.MethodOptions)
router.HandleFunc("/match/{id:[0-9]{19}}", getMatch).Methods(http.MethodGet, http.MethodOptions) router.HandleFunc("/match/{id:[0-9]{19}}", getMatch).Methods(http.MethodGet, http.MethodOptions)
router.HandleFunc("/match/{id:[0-9]{19}}/weapons", getMatchWeapons).Methods(http.MethodGet, http.MethodOptions) router.HandleFunc("/match/{id:[0-9]{19}}/weapons", getMatchWeapons).Methods(http.MethodGet, http.MethodOptions)

View File

@@ -8,6 +8,7 @@ import (
"csgowtfd/ent/stats" "csgowtfd/ent/stats"
"encoding/json" "encoding/json"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"errors"
"fmt" "fmt"
"github.com/an0nfunc/go-steamapi" "github.com/an0nfunc/go-steamapi"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -187,6 +188,18 @@ type MatchResponse struct {
Stats interface{} `json:"stats,omitempty"` Stats interface{} `json:"stats,omitempty"`
} }
type (
AuthcodeUnauthorizedError struct {
error
}
AuthcodeRateLimitError struct {
error
}
SharecodeNoMatchError struct {
error
}
)
const ( const (
shareCodeURLEntry = "https://api.steampowered.com/ICSGOPlayers_730/GetNextMatchSharingCode/v1?key=%s&steamid=%d&steamidkey=%s&knowncode=%s" shareCodeURLEntry = "https://api.steampowered.com/ICSGOPlayers_730/GetNextMatchSharingCode/v1?key=%s&steamid=%d&steamidkey=%s&knowncode=%s"
) )
@@ -328,10 +341,19 @@ func getNextShareCode(lastCode string, apiKey string, authCode string, steamId u
return "", err return "", err
} }
if r.StatusCode == 202 { switch r.StatusCode {
case http.StatusAccepted:
return "n/a", nil return "n/a", nil
} else if r.StatusCode != 200 { case http.StatusTooManyRequests, http.StatusServiceUnavailable:
return "", fmt.Errorf("bad response from steam api (HTTP %d)", r.StatusCode) return "", AuthcodeRateLimitError{errors.New("api temp. ratelimited")}
case http.StatusPreconditionFailed:
return "", SharecodeNoMatchError{errors.New("sharecode not from player history")}
case http.StatusForbidden:
return "", AuthcodeUnauthorizedError{errors.New("authcode unauthorized")}
case http.StatusOK:
break
default:
return "", errors.New("temporary steamapi error")
} }
defer func(Body io.ReadCloser) { defer func(Body io.ReadCloser) {