Skip to content

Commit

Permalink
Merge pull request #146 from martius-lab/fkloss/download_games
Browse files Browse the repository at this point in the history
Add buttons to download game data in games table
  • Loading branch information
luator authored Jan 14, 2025
2 parents b04d096 + 754f559 commit 2816e7a
Show file tree
Hide file tree
Showing 17 changed files with 284 additions and 93 deletions.
1 change: 1 addition & 0 deletions comprl-hockey-game/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
match_quality_threshold = 0.8
percentage_min_players_waiting = 0.1
percental_time_bonus = 0.1
registration_key = "secret"
13 changes: 6 additions & 7 deletions comprl-web-reflex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ python3 ./create_database_tables.py path/to/comprl/database.db

## Run

Some configuration values have to be specified via environment variables:
The path to the comprl config file needs to be specified via an environment
variable:
```
# Path to the database
export COMPRL_DB_PATH="/path/to/comprl/database.db"
# Key that has to be specified to be able to register
export COMPRL_REGISTRATION_KEY="12345"
export COMPRL_CONFIG_PATH="/path/to/comprl/config.toml"
reflex run
```
Expand All @@ -62,10 +61,10 @@ sudo apptainer run -ec --overlay /tmp/overlay \
```

In the example above, `/path/to/your/comprl-database` is expected to be a
directory on the host system, that contains the comprl database. It is
expected to be called "comprl.db". You can set a different name by adding the
directory on the host system, that contains the comprl config file. It is
expected to be called "config.toml". You can set a different name by adding the
following argument: ```
--env COMPRL_DB_PATH=/comprl-config/my_database.db
--env COMPRL_CONFIG_PATH=/comprl-config/my_config.toml
```
Note from the [Reflex container example, which was used as a base for
Expand Down
21 changes: 11 additions & 10 deletions comprl-web-reflex/comprl-web-reflex.def
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ from: python:3.12
# set up reflex
cd /comprl/comprl-web-reflex

# database path and registration key must be set (and db file must exist),
# otherwise `reflex export` will fail. However, the database doesn't need
# to be populated and the key can be overwritten at runtime
export COMPRL_DB_PATH="/comprl-config/comprl.db"
touch $COMPRL_DB_PATH
export COMPRL_REGISTRATION_KEY="BUILDTIME"
# A valid configuration must be provided, otherwise `reflex export` will
# fail... However, the database doesn't need to be populated and everything
# can be overwritten at runtime
export COMPRL_CONFIG_PATH="/comprl-config/config.toml"
echo '[CompetitionServer]' > $COMPRL_CONFIG_PATH
echo 'registration_key = "BUILDTIME"' >> $COMPRL_CONFIG_PATH
echo 'database_path = "/tmp/foobar.db"' >> $COMPRL_CONFIG_PATH
touch /tmp/foobar.db

# Deploy templates and prepare app
reflex init
Expand All @@ -46,11 +48,10 @@ from: python:3.12

%environment
export REDIS_URL=redis://localhost
export COMPRL_DB_PATH="/comprl-config/comprl.db"
export COMPRL_REGISTRATION_KEY="rl-lecture"
export COMPRL_CONFIG_PATH="/comprl-config/config.toml"

%runscript
%startscript
. /venv/bin/activate
cd /comprl/comprl-web-reflex
redis-server --daemonize yes
cd /comprl/comprl-web-reflex
reflex run --env prod "$@"
31 changes: 21 additions & 10 deletions comprl-web-reflex/comprl_web/comprl_web.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
"""Main app module to demo local authentication."""

import pathlib
import os

import reflex as rx

from .components import standard_layout
from . import reflex_local_auth
from . import config, reflex_local_auth
from .pages import user_dashboard, leaderboard, games
from .reflex_local_auth.local_auth import LocalAuthState


def _validate_configuration() -> None:
def _load_comprl_configuration() -> None:
"""Make sure the configuration is valid."""
if not rx.config.get_config().comprl_registration_key:
raise ValueError("Configuration: comprl_registration_key is not set.")
# FIXME very dirty hack to skip the configuration loading for `reflex export`
if "REFLEX_ENV_MODE" not in os.environ:
return

if not pathlib.Path(rx.config.get_config().comprl_db_path).is_file():
raise ValueError("Configuration: comprl_db_path does not exist.")
config_file = rx.config.get_config().comprl_config_path
if not config_file:
raise ValueError("Configuration: comprl_config_path is not set.")

config.load_config(config_file, [])

conf = config.get_config()
if not conf.registration_key:
raise ValueError("Configuration: registration_key is not set.")

if not conf.database_path.is_file():
raise ValueError("Configuration: database does not exist.")


@rx.page()
Expand All @@ -32,7 +43,7 @@ def index() -> rx.Component:
rx.text(f"Hello {LocalAuthState.authenticated_user.username}"),
reflex_local_auth.pages.login_page(),
),
rx.text(f"Key: {rx.config.get_config().comprl_registration_key}"),
rx.text(f"Key: {config.get_config().registration_key}"),
)
return standard_layout(index_page)

Expand All @@ -49,8 +60,8 @@ def registration() -> rx.Component:
return standard_layout(reflex_local_auth.pages.register_page())


_validate_configuration()

# FIXME can this be done differently, so it is not executed for `reflex export`?
_load_comprl_configuration()
app = rx.App(theme=rx.theme(has_background=True, accent_color="teal"))
app.add_page(
user_dashboard.dashboard,
Expand Down
3 changes: 3 additions & 0 deletions comprl-web-reflex/comprl_web/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from comprl.server.config import load_config, get_config

__all__ = ["load_config", "get_config"]
86 changes: 74 additions & 12 deletions comprl-web-reflex/comprl_web/pages/games.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,85 @@
import reflex as rx

from ..components import standard_layout
from ..protected_state import ProtectedState
from ..protected_state import UserGamesState, GameInfo
from .. import reflex_local_auth


@rx.page(on_load=ProtectedState.on_load)
@reflex_local_auth.require_login
def game_overview() -> rx.Component:
return standard_layout(
def show_game(game: GameInfo) -> rx.Component:
"""Show a game in a table row."""
return rx.table.row(
rx.table.cell(game.player1),
rx.table.cell(game.player2),
rx.table.cell(game.result),
rx.table.cell(game.time),
rx.table.cell(game.id),
rx.table.cell(
rx.button(
"Download game data",
on_click=lambda: UserGamesState.download_game(game.id),
)
),
)


def user_game_table() -> rx.Component:
"""Render the user game table."""
return rx.vstack(
rx.form(
rx.hstack(
rx.text("Search for game ID:"),
rx.input(
name="search_id",
placeholder="Game ID",
width="38ex",
),
rx.button("Search"),
),
on_submit=UserGamesState.search_game,
),
rx.cond(
ProtectedState.user_games,
rx.data_table(
data=ProtectedState.user_games,
columns=ProtectedState.user_games_header,
search=True,
pagination=True,
UserGamesState.search_id,
rx.hstack(
rx.text(f"Search results for game ID: {UserGamesState.search_id}"),
rx.button("Clear search", on_click=UserGamesState.clear_search),
),
),
rx.table.root(
rx.table.header(
rx.table.row(
rx.foreach(
UserGamesState.user_games_header, rx.table.column_header_cell
)
),
),
rx.text("No games played yet."),
rx.table.body(rx.foreach(UserGamesState.user_games, show_game)),
on_mount=UserGamesState.load_user_games,
width="100%",
),
rx.hstack(
rx.button(
"First",
on_click=UserGamesState.first_page,
),
rx.button(
"Prev",
on_click=UserGamesState.prev_page,
),
rx.text(
f"Page {UserGamesState.page_number} / {UserGamesState.total_pages}"
),
rx.button(
"Next",
on_click=UserGamesState.next_page,
),
),
)


@rx.page(on_load=UserGamesState.on_load)
@reflex_local_auth.require_login
def game_overview() -> rx.Component:
return standard_layout(
user_game_table(),
heading="Games",
)
6 changes: 3 additions & 3 deletions comprl-web-reflex/comprl_web/pages/leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import reflex as rx

from ..components import standard_layout
from ..protected_state import ProtectedState
from ..protected_state import UserDashboardState
from .. import reflex_local_auth


@rx.page(on_load=ProtectedState.on_load)
@rx.page(on_load=UserDashboardState.on_load)
@reflex_local_auth.require_login
def leaderboard() -> rx.Component:
return standard_layout(
rx.data_table(
data=ProtectedState.ranked_users,
data=UserDashboardState.ranked_users,
columns=["Ranking", "Username", "µ / Σ"],
search=True,
sort=False,
Expand Down
22 changes: 14 additions & 8 deletions comprl-web-reflex/comprl_web/pages/user_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
import reflex as rx

from ..components import standard_layout
from ..protected_state import ProtectedState
from ..protected_state import UserDashboardState
from .. import reflex_local_auth
from ..reflex_local_auth.local_auth import LocalAuthState


@rx.page(on_load=ProtectedState.on_load)
@rx.page(on_load=UserDashboardState.on_load)
@reflex_local_auth.require_login
def dashboard() -> rx.Component:
win_rate = round(
ProtectedState.game_statistics.num_games_won
/ ProtectedState.game_statistics.num_games_played
UserDashboardState.game_statistics.num_games_won
/ UserDashboardState.game_statistics.num_games_played
* 100
)

Expand All @@ -30,23 +30,29 @@ def dashboard() -> rx.Component:
),
rx.data_list.item(
rx.data_list.label("Ranking"),
rx.data_list.value(f"{ProtectedState.ranking_position}. place"),
rx.data_list.value(f"{UserDashboardState.ranking_position}. place"),
),
rx.data_list.item(
rx.data_list.label("Games Played"),
rx.data_list.value(ProtectedState.game_statistics.num_games_played),
rx.data_list.value(
UserDashboardState.game_statistics.num_games_played
),
),
rx.data_list.item(
rx.data_list.label("Games Won"),
rx.data_list.value(ProtectedState.game_statistics.num_games_won),
rx.data_list.value(
UserDashboardState.game_statistics.num_games_won
),
),
rx.data_list.item(
rx.data_list.label("Win rate"),
rx.data_list.value(f"{win_rate} %"),
),
rx.data_list.item(
rx.data_list.label("Disconnects"),
rx.data_list.value(ProtectedState.game_statistics.num_disconnects),
rx.data_list.value(
UserDashboardState.game_statistics.num_disconnects
),
),
),
),
Expand Down
Loading

0 comments on commit 2816e7a

Please sign in to comment.