package web import ( "context" "errors" "math" "net/http" "sort" "strconv" "sync" "time" "github.com/AmanTahiliani/box-box/internal/models" ) const ( defaultReplayIntervalMS = 5000 maxReplayFrames = 3000 replayFetchConcurrency = 4 ) type replayDataClient interface { GetDriversForSession(sessionKey int) ([]models.Driver, error) GetLocation(sessionKey, driverNumber int) ([]models.Location, error) } type replayFramesResponse struct { SessionKey int `json:"session_key"` Interval int `json:"interval_ms"` StartTime string `json:"start_time"` Frames []replayFrame `json:"frames"` } type replayFrame struct { T int64 `json:"t"` Cars map[string]replayCar `json:"cars"` } type replayCar struct { X float64 `json:"x"` Y float64 `json:"y"` } func (s *Server) handleReplayFrames(w http.ResponseWriter, r *http.Request) { sessionKey, err := strconv.Atoi(r.URL.Query().Get("session_key")) if err != nil || sessionKey == 0 { http.Error(w, "session_key required", http.StatusBadRequest) return } intervalMS := defaultReplayIntervalMS rawInterval := r.URL.Query().Get("interval_ms") if rawInterval != "" { parsed, err := strconv.Atoi(rawInterval) if err != nil { http.Error(w, "invalid interval_ms", http.StatusBadRequest) return } if parsed > intervalMS { intervalMS = parsed } } client := s.client.Scoped() resp, incomplete, err := assembleReplayFrames(r.Context(), client, sessionKey, intervalMS) if err != nil { writeError(w, err, http.StatusInternalServerError, client.LastResponseWasStale()) return } markOpenF1Availability(w, client, replayResponseFreshness(resp, incomplete)) writeJSON(w, resp) } func replayResponseFreshness(resp replayFramesResponse, incomplete bool) string { if !incomplete { return "fresh" } if len(resp.Frames) == 0 { return "limited" } return "partial" } func assembleReplayFrames(ctx context.Context, client replayDataClient, sessionKey, intervalMS int) (replayFramesResponse, bool, error) { if intervalMS < defaultReplayIntervalMS { intervalMS = defaultReplayIntervalMS } resp := replayFramesResponse{ SessionKey: sessionKey, Interval: intervalMS, Frames: []replayFrame{}, } drivers, err := client.GetDriversForSession(sessionKey) if err != nil { return resp, false, err } driverNumbers := uniqueDriverNumbers(drivers) if len(driverNumbers) == 0 { return resp, true, nil } series, err := fetchReplayLocationSeries(ctx, client, sessionKey, driverNumbers) if err != nil && len(series) == 0 { return resp, false, err } start, ok := earliestReplayLocationTime(series) if !ok { return resp, true, nil } resp.StartTime = start.Format(time.RFC3339Nano) resp.Frames = snapReplayFrames(series, start, intervalMS) return resp, err != nil || len(series) < len(driverNumbers) || len(resp.Frames) == 0, nil } func uniqueDriverNumbers(drivers []models.Driver) []int { seen := make(map[int]bool, len(drivers)) numbers := make([]int, 0, len(drivers)) for _, driver := range drivers { if driver.DriverNumber <= 0 || seen[driver.DriverNumber] { continue } seen[driver.DriverNumber] = true numbers = append(numbers, driver.DriverNumber) } sort.Ints(numbers) return numbers } func fetchReplayLocationSeries(ctx context.Context, client replayDataClient, sessionKey int, driverNumbers []int) (map[int][]models.Location, error) { type result struct { driver int locs []models.Location err error } sem := make(chan struct{}, replayFetchConcurrency) results := make(chan result, len(driverNumbers)) var wg sync.WaitGroup for _, driverNumber := range driverNumbers { driverNumber := driverNumber wg.Add(1) go func() { defer wg.Done() select { case sem <- struct{}{}: defer func() { <-sem }() case <-ctx.Done(): results <- result{driver: driverNumber, err: ctx.Err()} return } locs, err := client.GetLocation(sessionKey, driverNumber) results <- result{driver: driverNumber, locs: locs, err: err} }() } wg.Wait() close(results) series := make(map[int][]models.Location, len(driverNumbers)) var joined error for result := range results { if result.err != nil { joined = errors.Join(joined, result.err) continue } if len(result.locs) > 0 { series[result.driver] = result.locs } } return series, joined } func earliestReplayLocationTime(series map[int][]models.Location) (time.Time, bool) { var start time.Time for _, locs := range series { for _, loc := range locs { t, err := time.Parse(time.RFC3339Nano, loc.Date) if err != nil { continue } if start.IsZero() || t.Before(start) { start = t } } } if start.IsZero() { return time.Time{}, false } return start, true } func snapReplayFrames(series map[int][]models.Location, start time.Time, intervalMS int) []replayFrame { type accumulator struct { t int64 cars map[string]replayCar nearest map[string]int64 } interval := int64(intervalMS) framesByIndex := make(map[int]*accumulator) for driverNumber, locs := range series { driverKey := strconv.Itoa(driverNumber) for _, loc := range locs { if !isFiniteFloat(loc.X) || !isFiniteFloat(loc.Y) { continue } t, err := time.Parse(time.RFC3339Nano, loc.Date) if err != nil { continue } offset := t.Sub(start).Milliseconds() if offset < 0 { continue } index := int((offset + interval/2) / interval) if index < 0 || index >= maxReplayFrames { continue } frameT := int64(index) * interval distance := absInt64(offset - frameT) acc, ok := framesByIndex[index] if !ok { acc = &accumulator{ t: frameT, cars: make(map[string]replayCar), nearest: make(map[string]int64), } framesByIndex[index] = acc } if prev, ok := acc.nearest[driverKey]; ok && prev <= distance { continue } acc.nearest[driverKey] = distance acc.cars[driverKey] = replayCar{X: loc.X, Y: loc.Y} } } indexes := make([]int, 0, len(framesByIndex)) for index, acc := range framesByIndex { if len(acc.cars) > 0 { indexes = append(indexes, index) } } sort.Ints(indexes) frames := make([]replayFrame, 0, len(indexes)) for _, index := range indexes { acc := framesByIndex[index] frames = append(frames, replayFrame{T: acc.t, Cars: acc.cars}) } return frames } func absInt64(v int64) int64 { if v < 0 { return -v } return v } func isFiniteFloat(v float64) bool { return !math.IsNaN(v) && !math.IsInf(v, 0) }