Skip to content

Timekeeper, leaderboard & streaming overlays

David Smith edited this page Mar 20, 2024 · 1 revision

Timekeeper

Requirements

General

  • Shall be part of the DREM react application
  • Shall have the features that the current Gosquare solution has. TBD breakdown features

Access management

  • Shall be accessible for users belonging to admin and operator groups
  • Shall only be able to do timekeeping for events the user has access to.
  • Shall be possible to use the same DREM installation for time tracking of multiple concurrent events

Integrations

  • Shall work with the automated timing system, https://gitlab.aws.dev/dasmthc/deepracer-leaderboard-timer
  • Shall stream race information to the backend every second during a race
    • racer name, current lap time, fastest lap so far, remaining race time
  • Shall support storing race & lap information in the backend

Race types

  • Shall require an event in DREM before allowing the timekeeper to do timekeeping.

    Note: An event need to contain

    • no. tracks for the event
    • race configuration per track.
    • the car fleet selected for the event
  • Shall support time trial mode

Data & analytics

  • With the data stored in the backend at least the following metrics shall be possible to derive:
    • Per event
      • unique racers
      • total number of races and laps
      • fastest, average and mean lap time
      • number of racers who raced with their own models
    • Across all events
      • fastest, average and mean lap time per track type
      • total number or unique racers
      • total number or races and laps
      • histogram for number of events users has participated in

Proposed architecture

DREM-architecture__10___1___2___3_-Leader_board__Timekeeper

All parts websites are hosted as different origin in the same Cloudfront distribution. The DREM webb app use the default behaviour. All websites use the backend for getting event unique data.

Timekeeper architecture

On page load the timekeeper fetch all racers for the current event using the GetAllRacers query. When the timekeeper is ready to start the race the the timekeeper page starts to do a AddRacerInfo mutation every second with the following data:

  • racer name, current lap time, remaining race time, no. car resets for current lap

When a race is finished the timekeeper do an AddRace mutation with the race data, If the race contains a new fastest lap for the racer it will triggers a new OnNewLeaderboardEntry subscription which the leaderboard is subscribing on.

Leaderboard

Requirements

General

  • Shall not be part of the DREM react application
  • Shall have the same look and feel as the current Gosquare leaderboard have TBD breakdown
  • on page load all existing leaderboard entries shall be fetched from the backend
  • new leaderboard entries shall be pushed to all connected leaderboards which subscribe to the current event id

Access management

  • Shall not require any login to view the leaderboard for an event
  • Shall be possible to access the leaderboard for a specific event using only a URL

Overlay information

  • Shall be possible to see the remaining time for the current racer

Configurable items

  • Footer can be "Anything" default is "Follow the race: #AWSDeepRacer"
  • Custom logo can be added to the event will appear top right or replace the DeepRacer logo (discuss)
  • Ranking method
  • Links to leaderboard when RPi connected (think GoSquared event setup)

Proposed architecture

The leaderboard use an Appsync API key to access the required API methods. TODO how to manage API key rotate (max age is 365 days)

On leaderboard page load:

When the leaderboard is loaded the page uses the url query parameter to fetch the leaderboard entries for the selected event. It also establish a subscription for the OnNewRacerInfo and OnNewRacerInfo for the event Id used to fetch the leaderboard.

supported URL query parameters:

  • event=<eventId>, ex: 80f0f15c-a830-4cee-a751-4dfea59a69c6 TODO: how can we shorten the event ID and still ensure that it will be unique for all events
  • track=<trackId>, ex: 1,2... or all for a combined dashboard
  • lang=<langCode>, ex: en, se, de

On subscriptions:

When the leaderboard receives data on OnNewRacerInfo, the leaderboard updates the relevant parts of the site. TBD how to manage if there is no data or the stream break??

When the OnNewLeaderboardEntry subscription is triggered the leaderboard either replace or add the new entry based on if the racer already is present on the leaderboard.

Streaming overlays

MoSCoW Requirements

  • Must
    • M01: not require any login to view the overlays for an event
  • Should
    • S01: be possible to access the overlay for a specific event using only a URL
    • S02: allow for the chroma to be turned off / on via the URL (greenscreen) so the same overlay can be used in OBS or Elemental
    • S03: allow for any leaderboard configuration supported by the leaderboards (single track / all tracks) for an event
  • Could
    • C01:
  • Will not
    • W01:

TODO

Proposed architecture

DRAFT!!!

Design:

API design

  • Queries:
    • getLeaderBoard(eventId: ID!, trackId: ID): LeaderBoard
    • getAllRacers: \\\[User\\\]
  • Mutations:
    • addRace(eventId: ID!, username: String!, laps: \\\[LapInput\\\]!): Race
    • addLeaderboardEntry(eventId: ID!, trackId: ID!, username: String, eventId: String, time: Float): LeaderBoardEntry
    • addRaceInfo(eventId: ID!, trackId: ID!, username: String, currentLapTime: Float, remainingRaceTime: Float, resetsCurrentLap: Int): RaceInfo
  • Subscriptions:
    • onNewRaceInfo(eventId: ID): RaceInfo
    • onNewLeaderboardEntry(eventId: ID): LeaderBoardEntry
  • Types
    • User
      • username: String!
      • id: ID!
    • Race
      • id: ID
      • username: String
      • laps: \\\[Lap\\\]
    • Lap & LapInput
      • id: ID
      • raceId: ID
      • modelId: ID
      • carId: ID
      • time: Float
      • resets: Int
      • isValid: Boolean
      • autTimerConnected: Boolean
    • LeaderBoard
      • eventName: String, trackId: Int, entries: \\\[LeaderBoardEntry\\\]
      • TODO: do we need a raceType enum to be able to show different types of leaderboards depending on the winning criteria???
    • LeaderBoardEntry
      • username: String, countryCode: String, eventId: String, time: Float
      • TODO: do we need the eventId for anything but triggering the subscription??? if yes then we most likely also need to use a union for defining the different types
    • RaceInfo
      • username: String, currentLapTime: Float, remainingRaceTime: Float, resetsCurrentLap: Int

DDB Tables

LeaderboardEntriesTable

Query patterns:

  • timekeeper:
    • Get entry for racer x, (for verifying if newly added race is better than last record for the user)
  • event admin:
    • Get all races for event x
    • Get all laps for racer x in event y
    • Delete lap x for user y
    • Delete race x for user y
  • leaderboard:
    • Get all leaderboard entries for event x

Design:

The table stores two types of items and use a composite primary key and composite sort key

  • races/laps, one lap per row
    • pk = RACE#<eventId>
    • sk = <username>#<raceId>#<lapId>
  • leaderboard entries, one entry per racer that has raced
    • pk = RECORD#<eventId>
    • sk = <username>

All queries, updates and deletes can be done without any secondary indexes