added weapon-stats endpoint
This commit is contained in:
@@ -317,6 +317,10 @@ func (p *DemoParser) parseWorker() {
|
||||
}
|
||||
|
||||
for _, tMatchPlayer := range tStats {
|
||||
if tMatchPlayer.Color == "" {
|
||||
tMatchPlayer.Color = stats.ColorGrey
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
nMatchPLayer, err := tMatchPlayer.Update().
|
||||
SetDmgTeam(tMatchPlayer.DmgTeam).
|
||||
|
236
main.go
236
main.go
@@ -57,6 +57,18 @@ type PlayerResponse struct {
|
||||
Matches []*MatchResponse `json:"matches,omitempty"`
|
||||
}
|
||||
|
||||
type EqResponse struct {
|
||||
Victim uint64 `json:"victim"`
|
||||
Type int `json:"type"`
|
||||
HitGroup int `json:"hit_group"`
|
||||
Dmg uint `json:"dmg"`
|
||||
}
|
||||
|
||||
type WeaponResponse struct {
|
||||
Player *PlayerResponse `json:"player"`
|
||||
Eq []*EqResponse `json:"eq,omitempty"`
|
||||
}
|
||||
|
||||
type MatchResponse struct {
|
||||
MatchId uint64 `json:"match_id,string"`
|
||||
ShareCode string `json:"share_code,omitempty"`
|
||||
@@ -70,63 +82,6 @@ type MatchResponse struct {
|
||||
Stats interface{} `json:"stats,omitempty"`
|
||||
}
|
||||
|
||||
type StatsResponse struct {
|
||||
TeamID int `json:"team_id"`
|
||||
Kills int `json:"kills"`
|
||||
Deaths int `json:"deaths"`
|
||||
Assists int `json:"assists"`
|
||||
Headshot int `json:"headshot"`
|
||||
MVP uint `json:"mvp"`
|
||||
Score int `json:"score"`
|
||||
Player interface{} `json:"player,omitempty"`
|
||||
Rank struct {
|
||||
Old int `json:"old,omitempty"`
|
||||
New int `json:"new,omitempty"`
|
||||
} `json:"rank,omitempty"`
|
||||
MultiKills struct {
|
||||
Duo uint `json:"duo,omitempty"`
|
||||
Triple uint `json:"triple,omitempty"`
|
||||
Quad uint `json:"quad,omitempty"`
|
||||
Pent uint `json:"pent,omitempty"`
|
||||
} `json:"multi_kills,omitempty"`
|
||||
Dmg struct {
|
||||
Enemy uint `json:"enemy,omitempty"`
|
||||
Team uint `json:"team,omitempty"`
|
||||
UD struct {
|
||||
HE uint `json:"he,omitempty"`
|
||||
Flames uint `json:"flames,omitempty"`
|
||||
Flash uint `json:"flash,omitempty"`
|
||||
Decoy uint `json:"decoy,omitempty"`
|
||||
Smoke uint `json:"smoke,omitempty"`
|
||||
} `json:"ud,omitempty"`
|
||||
HitGroup struct {
|
||||
Head uint `json:"head,omitempty"`
|
||||
Chest uint `json:"chest,omitempty"`
|
||||
Stomach uint `json:"stomach,omitempty"`
|
||||
LeftArm uint `json:"left_arm,omitempty"`
|
||||
RightArm uint `json:"right_arm,omitempty"`
|
||||
LeftLeg uint `json:"left_leg,omitempty"`
|
||||
RightLeg uint `json:"right_leg,omitempty"`
|
||||
Gear uint `json:"gear,omitempty"`
|
||||
} `json:"hit_group,omitempty"`
|
||||
} `json:"dmg,omitempty"`
|
||||
Flash struct {
|
||||
Duration struct {
|
||||
Self float32 `json:"self,omitempty"`
|
||||
Team float32 `json:"team,omitempty"`
|
||||
Enemy float32 `json:"enemy,omitempty"`
|
||||
} `json:"duration,omitempty"`
|
||||
Total struct {
|
||||
Team uint `json:"team,omitempty"`
|
||||
Enemy uint `json:"enemy,omitempty"`
|
||||
Self uint `json:"self,omitempty"`
|
||||
} `json:"total,omitempty"`
|
||||
} `json:"flash,omitempty"`
|
||||
Crosshair string `json:"crosshair,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
KAST int `json:"kast,omitempty"`
|
||||
}
|
||||
|
||||
func housekeeping() {
|
||||
for {
|
||||
if !firstHK {
|
||||
@@ -301,7 +256,7 @@ func getPlayer(w http.ResponseWriter, r *http.Request) {
|
||||
continue
|
||||
}
|
||||
|
||||
sResponse := &StatsResponse{
|
||||
sResponse := &utils.StatsResponse{
|
||||
TeamID: tStats.TeamID,
|
||||
Kills: tStats.Kills,
|
||||
Deaths: tStats.Deaths,
|
||||
@@ -311,16 +266,22 @@ func getPlayer(w http.ResponseWriter, r *http.Request) {
|
||||
Score: tStats.Score,
|
||||
}
|
||||
|
||||
sResponse.MultiKills.Duo = tStats.Mk2
|
||||
sResponse.MultiKills.Triple = tStats.Mk3
|
||||
sResponse.MultiKills.Quad = tStats.Mk4
|
||||
sResponse.MultiKills.Pent = tStats.Mk5
|
||||
sResponse.MultiKills = &utils.MultiKills{
|
||||
Duo: tStats.Mk2,
|
||||
Triple: tStats.Mk3,
|
||||
Quad: tStats.Mk4,
|
||||
Pent: tStats.Mk5,
|
||||
}
|
||||
|
||||
sResponse.Rank.Old = tStats.RankOld
|
||||
sResponse.Rank.New = tStats.RankNew
|
||||
sResponse.Rank = &utils.Rank{
|
||||
Old: tStats.RankOld,
|
||||
New: tStats.RankNew,
|
||||
}
|
||||
|
||||
sResponse.Dmg.Enemy = tStats.DmgEnemy
|
||||
sResponse.Dmg.Team = tStats.DmgTeam
|
||||
sResponse.Dmg = &utils.Damage{
|
||||
Enemy: tStats.DmgEnemy,
|
||||
Team: tStats.DmgTeam,
|
||||
}
|
||||
|
||||
mResponse.Stats = sResponse
|
||||
response.Matches = append(response.Matches, mResponse)
|
||||
@@ -409,6 +370,64 @@ func getMatchParse(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func getMatchWeapons(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", conf.Httpd.CORSAllowDomains)
|
||||
id := mux.Vars(r)["id"]
|
||||
|
||||
if id == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
matchId, err := strconv.ParseUint(id, 10, 64)
|
||||
if err != nil {
|
||||
log.Warningf("[GM] Error parsing matchID %s: %v", id, err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
mResponse := make([]*WeaponResponse, 0)
|
||||
|
||||
db.Lock.RLock()
|
||||
tStats, err := db.Client.Stats.Query().Where(stats.HasMatchesWith(match.ID(matchId))).All(context.Background())
|
||||
db.Lock.RUnlock()
|
||||
if err != nil {
|
||||
log.Warningf("[GMW] match %d not found: %+v", matchId, err)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
for _, stat := range tStats {
|
||||
db.Lock.RLock()
|
||||
mWs, err := stat.QueryWeaponStats().All(context.Background())
|
||||
db.Lock.RUnlock()
|
||||
if err != nil {
|
||||
log.Warningf("[GMW] Unbale to get WeaponStats for player %d: %v", stat.PlayerStats, err)
|
||||
continue
|
||||
}
|
||||
|
||||
mWr := &WeaponResponse{
|
||||
Player: &PlayerResponse{SteamID64: stat.PlayerStats},
|
||||
}
|
||||
|
||||
for _, wr := range mWs {
|
||||
mWr.Eq = append(mWr.Eq, &EqResponse{
|
||||
Victim: wr.Victim,
|
||||
Type: wr.EqType,
|
||||
HitGroup: wr.HitGroup,
|
||||
Dmg: wr.Dmg,
|
||||
})
|
||||
}
|
||||
mResponse = append(mResponse, mWr)
|
||||
}
|
||||
|
||||
err = utils.SendJSON(mResponse, w)
|
||||
if err != nil {
|
||||
log.Errorf("[GM] JSON: %+v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func getMatch(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", conf.Httpd.CORSAllowDomains)
|
||||
id := mux.Vars(r)["id"]
|
||||
@@ -444,7 +463,7 @@ func getMatch(w http.ResponseWriter, r *http.Request) {
|
||||
MatchResult: tMatch.MatchResult,
|
||||
MaxRounds: tMatch.MaxRounds,
|
||||
Parsed: tMatch.DemoParsed,
|
||||
Stats: []*StatsResponse{},
|
||||
Stats: []*utils.StatsResponse{},
|
||||
}
|
||||
|
||||
db.Lock.RLock()
|
||||
@@ -456,10 +475,10 @@ func getMatch(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
tmpStats := make([]*StatsResponse, 0)
|
||||
tmpStats := make([]*utils.StatsResponse, 0)
|
||||
|
||||
for _, iStats := range tStats {
|
||||
sResponse := &StatsResponse{
|
||||
sResponse := &utils.StatsResponse{
|
||||
Player: PlayerResponse{
|
||||
SteamID64: iStats.Edges.Players.ID,
|
||||
Name: iStats.Edges.Players.Name,
|
||||
@@ -475,38 +494,54 @@ func getMatch(w http.ResponseWriter, r *http.Request) {
|
||||
Headshot: iStats.Headshot,
|
||||
MVP: iStats.Mvp,
|
||||
Score: iStats.Score,
|
||||
}
|
||||
|
||||
sResponse.Color = iStats.Color.String()
|
||||
sResponse.Crosshair = iStats.Crosshair
|
||||
sResponse.KAST = iStats.Kast
|
||||
sResponse.Dmg.Team = iStats.DmgTeam
|
||||
sResponse.Dmg.Enemy = iStats.DmgEnemy
|
||||
sResponse.Dmg.UD.HE = iStats.UdHe
|
||||
sResponse.Dmg.UD.Smoke = iStats.UdSmoke
|
||||
sResponse.Dmg.UD.Flash = iStats.UdFlash
|
||||
sResponse.Dmg.UD.Decoy = iStats.UdDecoy
|
||||
sResponse.Dmg.UD.Flames = iStats.UdFlames
|
||||
sResponse.Dmg.HitGroup.Gear = iStats.HitGroupGear
|
||||
sResponse.Dmg.HitGroup.LeftLeg = iStats.HitGroupLeftLeg
|
||||
sResponse.Dmg.HitGroup.RightLeg = iStats.HitGroupRightLeg
|
||||
sResponse.Dmg.HitGroup.RightArm = iStats.HitGroupRightArm
|
||||
sResponse.Dmg.HitGroup.LeftArm = iStats.HitGroupLeftArm
|
||||
sResponse.Dmg.HitGroup.Stomach = iStats.HitGroupStomach
|
||||
sResponse.Dmg.HitGroup.Chest = iStats.HitGroupChest
|
||||
sResponse.Dmg.HitGroup.Head = iStats.HitGroupHead
|
||||
sResponse.Rank.Old = iStats.RankOld
|
||||
sResponse.Rank.New = iStats.RankNew
|
||||
sResponse.Flash.Total.Enemy = iStats.FlashTotalEnemy
|
||||
sResponse.Flash.Total.Team = iStats.FlashTotalTeam
|
||||
sResponse.Flash.Total.Self = iStats.FlashTotalSelf
|
||||
sResponse.Flash.Duration.Enemy = iStats.FlashDurationEnemy
|
||||
sResponse.Flash.Duration.Team = iStats.FlashDurationTeam
|
||||
sResponse.Flash.Duration.Self = iStats.FlashDurationSelf
|
||||
sResponse.MultiKills.Duo = iStats.Mk2
|
||||
sResponse.MultiKills.Triple = iStats.Mk3
|
||||
sResponse.MultiKills.Quad = iStats.Mk4
|
||||
sResponse.MultiKills.Pent = iStats.Mk5
|
||||
Dmg: &utils.Damage{
|
||||
Team: iStats.DmgTeam,
|
||||
Enemy: iStats.DmgEnemy,
|
||||
UD: &utils.UD{
|
||||
HE: iStats.UdHe,
|
||||
Smoke: iStats.UdSmoke,
|
||||
Flash: iStats.UdFlash,
|
||||
Decoy: iStats.UdDecoy,
|
||||
Flames: iStats.UdFlames,
|
||||
},
|
||||
HitGroup: &utils.HitGroup{
|
||||
Gear: iStats.HitGroupGear,
|
||||
LeftLeg: iStats.HitGroupLeftLeg,
|
||||
RightLeg: iStats.HitGroupRightLeg,
|
||||
RightArm: iStats.HitGroupRightArm,
|
||||
LeftArm: iStats.HitGroupLeftArm,
|
||||
Stomach: iStats.HitGroupStomach,
|
||||
Chest: iStats.HitGroupChest,
|
||||
Head: iStats.HitGroupHead,
|
||||
},
|
||||
},
|
||||
Color: iStats.Color.String(),
|
||||
Crosshair: iStats.Crosshair,
|
||||
KAST: iStats.Kast,
|
||||
Rank: &utils.Rank{
|
||||
Old: iStats.RankOld,
|
||||
New: iStats.RankNew,
|
||||
},
|
||||
Flash: &utils.Flash{
|
||||
Total: &utils.SelfTeamEnemy{
|
||||
Enemy: iStats.FlashTotalEnemy,
|
||||
Team: iStats.FlashTotalTeam,
|
||||
Self: iStats.FlashTotalSelf,
|
||||
},
|
||||
Duration: &utils.SelfTeamEnemy{
|
||||
Enemy: iStats.FlashDurationEnemy,
|
||||
Team: iStats.FlashDurationTeam,
|
||||
Self: iStats.FlashDurationSelf,
|
||||
},
|
||||
},
|
||||
MultiKills: &utils.MultiKills{
|
||||
Duo: iStats.Mk2,
|
||||
Triple: iStats.Mk3,
|
||||
Quad: iStats.Mk4,
|
||||
Pent: iStats.Mk5,
|
||||
},
|
||||
}
|
||||
|
||||
if !iStats.Edges.Players.VacDate.IsZero() {
|
||||
switch s := sResponse.Player.(type) {
|
||||
@@ -622,6 +657,7 @@ func main() {
|
||||
router.HandleFunc("/player/trackme", postPlayerTrackMe).Methods(http.MethodPost, 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}}/weapons", getMatchWeapons).Methods(http.MethodGet, http.MethodOptions)
|
||||
router.Use(mux.CORSMethodMiddleware(router))
|
||||
loggedRouter := handlers.LoggingHandler(os.Stdout, router)
|
||||
proxyRouter := handlers.ProxyHeaders(loggedRouter)
|
||||
|
@@ -83,6 +83,73 @@ type MatchStats struct {
|
||||
Loss int `json:"loss,omitempty"`
|
||||
}
|
||||
|
||||
type MultiKills struct {
|
||||
Duo uint `json:"duo,omitempty"`
|
||||
Triple uint `json:"triple,omitempty"`
|
||||
Quad uint `json:"quad,omitempty"`
|
||||
Pent uint `json:"pent,omitempty"`
|
||||
}
|
||||
|
||||
type Rank struct {
|
||||
Old int `json:"old,omitempty"`
|
||||
New int `json:"new,omitempty"`
|
||||
}
|
||||
|
||||
type HitGroup struct {
|
||||
Head uint `json:"head,omitempty"`
|
||||
Chest uint `json:"chest,omitempty"`
|
||||
Stomach uint `json:"stomach,omitempty"`
|
||||
LeftArm uint `json:"left_arm,omitempty"`
|
||||
RightArm uint `json:"right_arm,omitempty"`
|
||||
LeftLeg uint `json:"left_leg,omitempty"`
|
||||
RightLeg uint `json:"right_leg,omitempty"`
|
||||
Gear uint `json:"gear,omitempty"`
|
||||
}
|
||||
|
||||
type UD struct {
|
||||
HE uint `json:"he,omitempty"`
|
||||
Flames uint `json:"flames,omitempty"`
|
||||
Flash uint `json:"flash,omitempty"`
|
||||
Decoy uint `json:"decoy,omitempty"`
|
||||
Smoke uint `json:"smoke,omitempty"`
|
||||
}
|
||||
|
||||
type Damage struct {
|
||||
Enemy uint `json:"enemy,omitempty"`
|
||||
Team uint `json:"team,omitempty"`
|
||||
UD *UD `json:"ud,omitempty"`
|
||||
HitGroup *HitGroup `json:"hit_group,omitempty"`
|
||||
}
|
||||
|
||||
type SelfTeamEnemy struct {
|
||||
Self interface{} `json:"self,omitempty"`
|
||||
Team interface{} `json:"team,omitempty"`
|
||||
Enemy interface{} `json:"enemy,omitempty"`
|
||||
}
|
||||
|
||||
type Flash struct {
|
||||
Duration *SelfTeamEnemy `json:"duration,omitempty"`
|
||||
Total *SelfTeamEnemy `json:"total,omitempty"`
|
||||
}
|
||||
|
||||
type StatsResponse struct {
|
||||
TeamID int `json:"team_id"`
|
||||
Kills int `json:"kills"`
|
||||
Deaths int `json:"deaths"`
|
||||
Assists int `json:"assists"`
|
||||
Headshot int `json:"headshot"`
|
||||
MVP uint `json:"mvp"`
|
||||
Score int `json:"score"`
|
||||
Player interface{} `json:"player,omitempty"`
|
||||
Rank *Rank `json:"rank,omitempty"`
|
||||
MultiKills *MultiKills `json:"multi_kills,omitempty"`
|
||||
Dmg *Damage `json:"dmg,omitempty"`
|
||||
Flash *Flash `json:"flash,omitempty"`
|
||||
Crosshair string `json:"crosshair,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
KAST int `json:"kast,omitempty"`
|
||||
}
|
||||
|
||||
const (
|
||||
steamID64Entry = "https://steamcommunity.com/profiles/%d?xml=1"
|
||||
steamVanityURLEntry = "https://steamcommunity.com/id/%s?xml=1"
|
||||
|
Reference in New Issue
Block a user