Skip to content

Commit

Permalink
Added documentation to server config + main (#148)
Browse files Browse the repository at this point in the history
* Added documentation for server config and the main server file

* Made requested documentation updates
  • Loading branch information
JeanAEckelberg authored Feb 17, 2024
1 parent 5b1d24a commit 47740f9
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 9 deletions.
2 changes: 1 addition & 1 deletion server/crud/crud_team.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def create(team: TeamBase, db: Session) -> Team:


# read most recent team
def read(db: Session, id: int, eager: bool = False) -> Team | None:
def read(db: Session, id: str, eager: bool = False) -> Team | None:
"""
This method will create an entry in the ``Team`` table based on the team.py file. Refer to the
``models`` package for more information about team.py.
Expand Down
103 changes: 100 additions & 3 deletions server/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""
This file is the main entry point for the server, creating endpoints for the clients.
It should be noted that the runners do not require endpoints as they run on the server and utilize the crud files to
interact with the DB.
"""

from typing import Callable
from functools import wraps

Expand All @@ -8,6 +14,8 @@
from server.models.base import Base
from server.database import SessionLocal, engine
from server.crud import crud_submission, crud_team_type, crud_university, crud_team, crud_tournament, crud_run

# These models need to be imported to build the database correctly. DO NOT REMOVE THEM
from server.models.run import Run
from server.models.submission_run_info import SubmissionRunInfo
from server.models.team import Team
Expand All @@ -32,23 +40,39 @@
from server.schemas.university.university_base import UniversityBase
from server.schemas.university.university_schema import UniversitySchema

# Creates the DB
Base().metadata.create_all(bind=engine)

# run in byte_engine folder: uvicorn server.main:app --reload
app = FastAPI()


def get_db():
"""
Get a database session for orm and query execution
:return:
"""
db = SessionLocal()
try:
yield db
finally:
db.close()


def run_with_return_to_client(func: Callable):
def run_with_return_to_client(func: Callable) -> Callable:
"""
A decorator for returning errors to the client instead of leaving errors on serverside only
:param func:
:return:
"""
@wraps(func)
def wrapper(*args, **kwargs):
"""
Wraps the function
:param args:
:param kwargs:
:return:
"""
try:
return func(*args, **kwargs)
except Exception as e:
Expand All @@ -61,20 +85,36 @@ def wrapper(*args, **kwargs):

@app.get('/')
def root():
"""
Root endpoint.
:return:
"""
return {"message": "Hello World"}


# post submission
@app.post('/submission/', response_model=SubmissionBase)
@run_with_return_to_client
def post_submission(submission: SubmissionWTeam, db: Session = Depends(get_db)):
"""
Submission post endpoint.
:param submission: Submission with Team schema (dict) is what is expected in the request body.
:param db: DB session.
:return:
"""
return crud_submission.create(submission, db)


# post team endpoint
@app.post('/team/', response_model=TeamIdSchema)
@run_with_return_to_client
def post_team(team: TeamBase, db: Session = Depends(get_db)):
"""
Team post endpoint.
:param team: Team base schema (dict) is what is expected in the request body.
:param db: DB session.
:return:
"""
# Throw error when team name already exists
try:
return crud_team.create(team, db)
Expand All @@ -83,16 +123,29 @@ def post_team(team: TeamBase, db: Session = Depends(get_db)):
'team name. Please choose a different name.')


@app.get('/team_info/', response_model=TeamIdSchema)
@app.get('/team_info', response_model=TeamIdSchema)
@run_with_return_to_client
def get_team_info(uuid: str, db: Session = Depends(get_db)):
"""
This endpoint is currently unused, this endpoint could be used to get the team information.
:param uuid: UUID of the team, also known as vID.
:param db: DB session.
:return:
"""
return crud_team.read(db, uuid, True)


# gets the INDIVIDUAL submission data of a specific team
@app.get('/submission', response_model=SubmissionSchema)
@run_with_return_to_client
def get_submission(submission_id: int, team_uuid: str, db: Session = Depends(get_db)):
"""
Gets the submission information for an id provided.
:param submission_id: An int representing the submission id.
:param team_uuid: A string representing the team Universally Unique Identifier.
:param db: DB session.
:return:
"""
# Retrieves a list of submissions where the submission id and uuids match
submission_list: list[Submission] | None = crud_submission.read_all_W_filter(
db, submission_id=submission_id, team_uuid=team_uuid)
Expand All @@ -107,6 +160,13 @@ def get_submission(submission_id: int, team_uuid: str, db: Session = Depends(get
@app.get('/runs', response_model=list[RunSchema])
@run_with_return_to_client
def get_runs(tournament_id: int, team_uuid: str | None = None, db: Session = Depends(get_db)):
"""
Gets the runs for a given tournament and given team, if provided.
:param tournament_id: An int representing the tournament id.
:param team_uuid: A string representing the team Universally Unique Identifier.
:param db: DB session.
:return:
"""
run_list: list[Run] | None = crud_run.read_all_W_filter(
db, tournament_id=tournament_id)

Expand All @@ -127,34 +187,60 @@ def get_runs(tournament_id: int, team_uuid: str | None = None, db: Session = Dep
@app.get('/submissions', response_model=list[SubmissionSchema])
@run_with_return_to_client
def get_submissions(team_uuid: str, db: Session = Depends(get_db)):
"""
Gets the submissions for a given team.
:param team_uuid: A string representing the team Universally Unique Identifier.
:param db: DB session.
:return:
"""
return crud_submission.read_all_by_team_id(db, team_uuid)


# get team types
@app.get('/team_types/', response_model=list[TeamTypeBase])
@run_with_return_to_client
def get_team_types(db: Session = Depends(get_db)):
"""
Gets the team types in the DB.
:param db: DB session.
:return:
"""
return crud_team_type.read_all(db)


# get universities
@app.get('/universities/', response_model=list[UniversityBase])
@run_with_return_to_client
def get_universities(db: Session = Depends(get_db)):
"""
Gets the universities in the DB.
:param db: DB session.
:return:
"""
return crud_university.read_all(db)


# get runs
@app.get('/runs/', response_model=list[RunBase])
@run_with_return_to_client
def get_runs(db: Session = Depends(get_db)):
"""
Gets the runs in the DB. This is currently unused and would be a resource intensive call if it was used.
:param db: DB session.
:return:
"""
return crud_run.read_all(db)


# get tournaments
@app.get('/tournaments/', response_model=list[TournamentBase])
@run_with_return_to_client
def get_tournaments(db: Session = Depends(get_db)):
"""
Gets the tournaments from the DB.
:param db: DB session.
:return:
"""
temp: list[Tournament] = crud_tournament.read_all(db)

if len(temp) == 0:
Expand All @@ -167,6 +253,12 @@ def get_tournaments(db: Session = Depends(get_db)):
@app.get('/tournament', response_model=TournamentSchema)
@run_with_return_to_client
def get_tournament(tournament_id: int, db: Session = Depends(get_db)):
"""
Gets a single tournament from the DB by id.
:param tournament_id: An int representing the id of a tournament.
:param db: DB session.
:return:
"""
temp: Tournament = crud_tournament.read(db, tournament_id, eager=True)

if temp is None:
Expand All @@ -178,11 +270,16 @@ def get_tournament(tournament_id: int, db: Session = Depends(get_db)):
@app.get('/latest_tournament/', response_model=TournamentSchema)
@run_with_return_to_client
def get_latest_tournament(db: Session = Depends(get_db)):
"""
An endpoint to retrieve the latest tournament.
:param db: DB session.
:return:
"""
temp: Tournament = crud_tournament.get_latest_tournament(db)

if temp is None:
raise Exception('No tournaments found.')

return temp

# main should NOT be able to delete data (we do not want the public to be able to delete), so deletion endpoints
# main should NOT be able to delete data (we do not want the public to be able to delete), so no deletion endpoints
58 changes: 56 additions & 2 deletions server/server_config.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,77 @@


class Config:
"""
Config
------
The Server Config class is responsible for setting up the runners for the server.
-----
Number Of Games Against Same Team
+++++++++++++++++++++++++++++++++
The Number Of Games Against Same Team is an int representing how many runs should be repeated. It is worth
noting that this should be 1 if the development team has ensured that randomness is seeded, ensuring that
two games with the same seed play out the same way. Competitor randomness is their own liability and not
the development team's responsibility.
-----
Sleep Time Between Runs
+++++++++++++++++++++++
The Sleep Time Between Runs is an int representing the number of seconds between each run of the client runner.
Each time the client runner is run, it will generate an entire tournament. The run time of the client runner is
not factored into this time.
-----
End DateTime
++++++++++++
The End DateTime is an ISO formatted string representing the end of the competition. This will need to be
changed for every competition. Ex. 'YYYY-mm-dd HH:MM', like '2030-01-01 00:00'
-----
Sleep Time Between Vis
++++++++++++++++++++++
The Sleep Time Between Vis is an int representing the number of seconds between each run of the visualizer.
Each time the visualizer is run, it will visualize the best runs for each team of the tournament. The run time
of the visualizer is not factored into this time. If the visualizer isn't running on the server, increase this
parameter as a potential solution.
-----
"""
__NUMBER_OF_GAMES_AGAINST_SAME_TEAM: int = 1
__SLEEP_TIME_SECONDS_BETWEEN_RUNS: int = 150
__END_DATETIME: str = "2030-01-01 00:00" # Adjust this for every competition!!!!!
__SLEEP_TIME_SECONDS_BETWEEN_VIS: int = 10

@property
def NUMBER_OF_GAMES_AGAINST_SAME_TEAM(self) -> int:
"""
The Number Of Games Against Same Team is an int representing how many runs should be repeated. It is worth
noting that this should be 1 if the development team has ensured that randomness is seeded, ensuring that
two games with the same seed play out the same way. Competitor randomness is their own liability and not
the development team's responsibility.
:return: int
"""
return self.__NUMBER_OF_GAMES_AGAINST_SAME_TEAM

@property
def SLEEP_TIME_SECONDS_BETWEEN_RUNS(self) -> int:
"""
The Sleep Time Between Runs is an int representing the number of seconds between each run of the client runner.
Each time the client runner is run, it will generate an entire tournament. The run time of the client runner is
not factored into this time.
:return: int
"""
return self.__SLEEP_TIME_SECONDS_BETWEEN_RUNS

@property
def END_DATETIME(self) -> str:
"""
The End DateTime is an ISO formatted string representing the end of the competition. This will need to be
changed for every competition.
:return: str
"""
return self.__END_DATETIME

@property
def SLEEP_TIME_SECONDS_BETWEEN_VIS(self) -> int:
"""
The Sleep Time Between Vis is an int representing the number of seconds between each run of the visualizer.
Each time the visualizer is run, it will visualize the best runs for each team of the tournament. The run time
of the visualizer is not factored into this time. If the visualizer isn't running on the server, increase this
parameter as a potential solution.
:return: int
"""
return self.__SLEEP_TIME_SECONDS_BETWEEN_VIS
17 changes: 14 additions & 3 deletions visualizer/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,34 @@ class Config:
def NUMBER_OF_FRAMES_PER_TURN(self) -> int:
"""
If you have an animation, this will be the number of frames the animation goes through for each turn.
:return: int
"""
return self.__NUMBER_OF_FRAMES_PER_TURN

@property
def TILE_SIZE(self) -> int:
"""
This will be the size of the tile-its going to be squares
This will be the size of the tile; it is a square.
:return: int
"""
return self.__TILE_SIZE

@property
def SCALE(self) -> int:
"""
Scale is for the tile size being scaled larger.
For example: With a 16x16 tile, it can be scaled by 4 to be a 64x64 tile on the visualizer
For example: With a 16x16 tile, it can be scaled by 4 to be a 64x64 tile on the visualizer.
:return: int
"""
return self.__SCALE

@property
def SCREEN_SIZE(self) -> Vector:
"""
The screen size is the overall screen size
The screen size is the overall screen size.
The x and y values of the Vector object returned represent the horizontal and vertical lengths
of the screen respectively.
:return: Vector
"""
return self.__SCREEN_SIZE

Expand All @@ -106,33 +112,38 @@ def SCREEN_SIZE(self) -> Vector:
def FRAME_RATE(self) -> int:
"""
Frame Rate is the overall frames per second.
:return: int
"""
return self.__FRAME_RATE

@property
def BACKGROUND_COLOR(self) -> (int, int, int):
"""
This is where you can set the default background color.
:return: tuple of 3 ints representing the red, blue, and green values.
"""
return self.__BACKGROUND_COLOR

@property
def GAME_BOARD_MARGIN_LEFT(self) -> int:
"""
This is where you can set the left margin for the main game board.
:return: int
"""
return self.__GAME_BOARD_MARGIN_LEFT

@property
def GAME_BOARD_MARGIN_TOP(self) -> int:
"""
This is where you can set the top margin for the main game board.
:return: int
"""
return self.__GAME_BOARD_MARGIN_TOP

@property
def VISUALIZE_HELD_ITEMS(self) -> bool:
"""
This is where you can set if you want held items to be displayed in the visualizer.
:return: bool
"""
return self.__VISUALIZE_HELD_ITEMS

0 comments on commit 47740f9

Please sign in to comment.