Skip to content

iMaxopoly/sports-event-timer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub license Go Report Card DeepScan grade Build Status

Sports Event Timing

Sports Event Timing

Sports Event Timing' demonstrates the simulation of a race among dummy participants, both server-sided and client-sided.

The simulation is a choice that can be run either solely on the client-side, concurrently using reactjs redux-sagas OR entirely on the server side where reactjs ensures to update the client-side accordingly.

App Demo

Race Preface

Every athlete carries a chip with a unique identifier. There are two set time points in the race, both of which also carrying unique chip identifiers, individually trigger a signal to the server side, indicating the athlete has reached said time point.

Client Side Simulation

In case of the client side simulation, the client fetches dummy race participants, and dummy time points. Concurrently, the sagas then simulate the athletes running on the track, where whenever any given athlete trips over a given time point, the following information is sent to the server:

  1. Athlete Chip Identifier
  2. Time taken for the athlete to reach that time point
  3. Time Point Chip Identifier

The server then acnkowledges the request using REST endpoints and then stores the information in the database.

Server Side Simulation

On the other hand, for the server side simulation, the server executes a goroutine-based race among athletes, stores their data in the database and makes that data available for client side fetching via REST endpoints. The server also uses similar mechanics to detect athlete chip identifiers and time point chip identifiers.

Prerequisites

1. Go development environment and;
2. NPM/Yarn;
3. GCC 64 bit for inbuilt sqlite3 database support; 
   preferrably: https://sourceforge.net/projects/mingw-w64/

Installing

On a Windows machine, project can be built using the build.bat file. Subsequently, it will create a dist folder that will contain the production ReactJS files as well as the backend binary. Please ensure 64 bit gcc(required for sqlite3) is available at command prompt.

1. Clone the project in the src folder of your GOPATH
2. Change directory into the project root
3. Ensure that the project directory is called 'sports-event-timing' 
   and follows the following folder structure: 'GOPATH/src/sports-event-timing/source/backend'
3. Run ./build.bat

Alternatively, production files can also be generated separately(backend and frontend). Again, please ensure 64 bit gcc(required for sqlite3) is available at command prompt. Steps as follows:

1. Clone the project in your GOPATH or download the repository as zip and extract it in your GOPATH.
2. Ensure that the project directory is called 'sports-event-timing' 
   and follows the following folder structure: 'GOPATH/src/sports-event-timing/source/backend'
3. Change directory into the %project root%/source/backend folder.
4. Run go build to get the built executable.
5. Change directory into the %project root%/source/frontend folder.
6. Run 'npm install' or just 'yarn'(project uses yarn) to install dependencies.
7. Run 'npm run build' or 'yarn build' to generate production files that will be placed inside %project root%/dist/ folder.
8. Make sure the server executable is in the same folder as all other distribution files i. e. same folder as index.html

Backend REST API Overview

The backend uses the package httprouter as its main mux to server REST Endpoints.

By default, the server port is 8082

Server Simulated Race EndPoints

endpoint method description
/server/race-simulation/start GET Starts of the Race Event
/server/race-simulation/stop GET Stops the Race Event
/server/race-simulation/fetch/live-standings GET Returns the list of athletes with their race-relevant attributes in a live race
/server/race-simulation/fetch/last-standings GET Returns the list of athletes with their race-relevant attributes from the last race whereby, a race is currently not live

Sample Calls

Start Race

Request:

curl 'http://localhost:8082/server/race-simulation/start'

Response:

{"responseMessage":"starting race","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk15uu8auq2p50gu1i0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk15uu8auq2p50gu1ig","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk15uu8auq2p50gu1j0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk15uu8auq2p50gu1jg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk15uu8auq2p50gu1k0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1}]}

Stop Race

Request:

curl 'http://localhost:8082/server/race-simulation/stop'

Response:

{"responseMessage":"stopping race"}

Get live Athlete values in a live Race

Request:

curl 'http://localhost:8082/server/race-simulation/fetch/live-standings'

Response:

{"responseMessage":"race is in process, showing live data","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk15uu8auq2p50gu1i0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk15uu8auq2p50gu1ig","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk15uu8auq2p50gu1j0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk15uu8auq2p50gu1jg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk15uu8auq2p50gu1k0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1}]}

Get Athlete values in a from the last Race

Request:

curl 'http://localhost:8082/server/race-simulation/fetch/last-standings'

Response:

{"responseMessage":"race is currently not in process, showing last race data","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk15uu8auq2p50gu1i0","location":209,"timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk15uu8auq2p50gu1ig","location":203,"timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk15uu8auq2p50gu1j0","location":226,"timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk15uu8auq2p50gu1jg","location":201,"timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk15uu8auq2p50gu1k0","location":201,"timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1}]}

Client Simulated Race EndPoints

endpoint method description
/client/race-simulation/start GET Starts of the Race Event
/client/race-simulation/stop GET Stops the Race Event
/client/race-simulation/fetch/current-standings GET Returns the list of athletes with their race-relevant attributes in a live race
/client/race-simulation/push/current-standings POST Accepts athlete attributes which it then stores in the database in a live race

Sample Calls

Start Race

Request:

curl 'http://localhost:8082/client/race-simulation/start'

Response:

{"responseMessage":"starting race","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk0q968auq2p50gu1b0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk0q968auq2p50gu1bg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk0q968auq2p50gu1c0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk0q968auq2p50gu1cg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk0q968auq2p50gu1d0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1}],"timePoints":[{"name":"Corridor Timepoint","location":800,"identifier":"bbk0q968auq2p50gu1dg"},{"name":"Finish Line Timepoint","location":1000,"identifier":"bbk0q968auq2p50gu1e0"}]}

Stop Race

Request:

curl 'http://localhost:8082/client/race-simulation/stop'

Response:

{"responseMessage":"stopping race"}

Fetch Current Athletes in the Race

Request:

curl 'http://localhost:8082/client/race-simulation/fetch/current-standings'

Response:

{"responseMessage":"race is in process, showing live data","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk15hu8auq2p50gu1eg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk15hu8auq2p50gu1f0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk15hu8auq2p50gu1fg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk15hu8auq2p50gu1g0","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk15hu8auq2p50gu1gg","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1}]}

Push updated Athletes values from Client to Server

Request:

curl 'http://localhost:8082/client/race-simulation/push/current-standings' --data-binary '{"requestCommand":"commit feed","athletes":[{"timeElapsed":33614,"identifier":"bbk0ntm8auq2p50gu17g","timePointIdentifier":"bbk0ntm8auq2p50gu1a0"}]}'

Response:

{"responseMessage":"race is in process, data was committed, showing committed data","athletes":[{"startNumber":1,"fullName":"Manish Singh","identifier":"bbk0ntm8auq2p50gu17g","inFinishCorridor":true,"timeTakenToReachFinishCorridor":33614,"timeTakenToFinish":-1},{"startNumber":2,"fullName":"Madhushree Singh","identifier":"bbk0ntm8auq2p50gu180","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":3,"fullName":"Siim Kaspar Uustalu","identifier":"bbk0ntm8auq2p50gu18g","timeTakenToReachFinishCorridor":-1,"timeTakenToFinish":-1},{"startNumber":4,"fullName":"Eliisabeth Käbin","identifier":"bbk0ntm8auq2p50gu190","inFinishCorridor":true,"timeTakenToReachFinishCorridor":33485,"timeTakenToFinish":-1},{"startNumber":5,"fullName":"Ahti Liin","identifier":"bbk0ntm8auq2p50gu19g","inFinishCorridor":true,"timeTakenToReachFinishCorridor":33647,"timeTakenToFinish":-1}]}

  • Notes:

Ideally, the response message should be in the format of 'success' or 'fail' and should use status codes more effectively to better adhere to REST EndPoint standards. The backend uses defensive analysis to ascertain the condition of the race event before responding to the client. The client side, might however, lack coping mechanisms to accurately reflect the backend's status responses. This is true at the time of writing.

1, May, 2018


FrontEnd Overview

The frontend is based on ReactJS, using Redux for state-management and Redux Saga as a side-effects middleware.

Bootstrap is used as the CSS framework of choice and SCSS is used to modify the theme.

Click here to see the component diagram of the application structure.

  • Notes:

CSS modules in combination with SCSS files that allow for global CSS/SCSS dependencies(or from node_modules) to stay intact would have been a much proficient set up, not found in this project. Usage of FlipMove external dependency seems to be bad with performance, however, ideal for this project, compared to my slide animation attempt using react-transition-group, but definitely something to retry.

1, May, 2018

Database Overview

The current database used is sqlite 3. For the database, GORM is used as an ORM to allow quick replacement of database software without requiring to re-write code.

These are the following tables created:

athlete_db_models

contains columns: 
full_name                               string
start_number                            int
chip_identifier                         string
in_finish_corridor                      boolean
has_finished                            boolean
location                                int
time_taken_to_reach_finish_corridor     int
time_taken_to_finish                    int

timepoint_db_models

contains columns: 
name                                    string
location                                int
chip_identifier                         string

The database file itself(called 'RaceEventDB.db') is located in the 'dist' folder if using production build.

To-do

  • Thorough Unit-Testing.
  • Replace mutexes in backend with pure channel-based solution.
  • Stories on frontend.

Built With

  • httprouter - The backend router used
  • react - The frontend javascript library used
  • redux - State Management
  • redux-saga - To handle side-effects and other asynchronous tasks
  • sqlite3 - Relational drop-in database for quick demo

Author

License

This project is licensed under The Unlicence License - see the LICENSE file for details

About

Race event simulation in ReactJS and Golang using react-redux and react-saga.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published