mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-16 20:47:55 +00:00
Implement leaderboard service and POC HTTP handlers with Swagger documentation
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/x0gp/server/internal/races"
|
||||
"github.com/x0gp/server/internal/transport"
|
||||
)
|
||||
|
||||
// leaderboardHandler godoc
|
||||
// @Summary Leaderboard
|
||||
// @Description Returns paginated leaderboard list. Supports overall leaderboard or track-specific leaderboard for the current year.
|
||||
// @Tags leaderboard
|
||||
// @Produce json
|
||||
// @Param track_id query string false "Track ID. If empty, returns overall leaderboard."
|
||||
// @Param year query int false "Year. Defaults to current year."
|
||||
// @Param limit query int false "Limit (1..200, default 50)"
|
||||
// @Param offset query int false "Offset (default 0)"
|
||||
// @Param X-Driver-Id header string false "Current driver ID. Defaults to driver-seed-001 (mock Alice)."
|
||||
// @Success 200 {object} transport.LeaderboardResponse "Leaderboard page and current driver position"
|
||||
// @Failure 400 {object} map[string]interface{} "Invalid input"
|
||||
// @Failure 500 {object} map[string]interface{} "Internal server error"
|
||||
// @Router /api/leaderboard [get]
|
||||
func leaderboardHandler(svc *races.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
trackID := r.URL.Query().Get("track_id")
|
||||
|
||||
yearVal := r.URL.Query().Get("year")
|
||||
var year int
|
||||
if yearVal != "" {
|
||||
var err error
|
||||
year, err = strconv.Atoi(yearVal)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid_input", "invalid year")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
limit := 50
|
||||
limitVal := r.URL.Query().Get("limit")
|
||||
if limitVal != "" {
|
||||
var err error
|
||||
limit, err = strconv.Atoi(limitVal)
|
||||
if err != nil || limit <= 0 {
|
||||
writeError(w, http.StatusBadRequest, "invalid_input", "invalid limit")
|
||||
return
|
||||
}
|
||||
if limit > 200 {
|
||||
limit = 200
|
||||
}
|
||||
}
|
||||
|
||||
offset := 0
|
||||
offsetVal := r.URL.Query().Get("offset")
|
||||
if offsetVal != "" {
|
||||
var err error
|
||||
offset, err = strconv.Atoi(offsetVal)
|
||||
if err != nil || offset < 0 {
|
||||
writeError(w, http.StatusBadRequest, "invalid_input", "invalid offset")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
driverID := r.Header.Get("X-Driver-Id")
|
||||
if driverID == "" {
|
||||
driverID = "driver-seed-001" // mock current driver
|
||||
}
|
||||
|
||||
res, err := svc.GetLeaderboard(r.Context(), trackID, year, limit, offset, driverID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "internal", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
items := make([]transport.LeaderboardEntry, 0, len(res.Items))
|
||||
for _, item := range res.Items {
|
||||
items = append(items, leaderboardEntryToWire(item))
|
||||
}
|
||||
|
||||
var curDriver *transport.LeaderboardEntry
|
||||
if res.CurrentDriver != nil {
|
||||
wire := leaderboardEntryToWire(*res.CurrentDriver)
|
||||
curDriver = &wire
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, transport.LeaderboardResponse{
|
||||
Items: items,
|
||||
Total: res.Total,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
CurrentDriver: curDriver,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func leaderboardEntryToWire(e races.LeaderboardEntry) transport.LeaderboardEntry {
|
||||
var bestPos *int
|
||||
if e.BestPos != nil {
|
||||
pos := *e.BestPos
|
||||
bestPos = &pos
|
||||
}
|
||||
var bestTime *int64
|
||||
if e.BestTimeMs != nil {
|
||||
val := *e.BestTimeMs
|
||||
bestTime = &val
|
||||
}
|
||||
return transport.LeaderboardEntry{
|
||||
DriverID: e.DriverID,
|
||||
Nickname: e.Nickname,
|
||||
Name: e.Name,
|
||||
AvatarURL: e.AvatarURL,
|
||||
ClanID: e.ClanID,
|
||||
ClanTag: e.ClanTag,
|
||||
Points: e.Points,
|
||||
BestPos: bestPos,
|
||||
BestTimeMs: bestTime,
|
||||
Rank: e.Rank,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user