From c349fe475baae2cfe6cf8e5416fc657d9edbbece Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Fri, 17 Apr 2026 09:33:19 +0200 Subject: [PATCH] Fix memory leaked caused by RefreshService --- VERSION | 2 +- src/EzggLanManager.py | 20 ++++++++++++------- src/ezgg_lan_manager/__init__.py | 4 ++-- .../components/UserInfoBox.py | 7 ++++--- src/ezgg_lan_manager/pages/CateringPage.py | 1 - .../services/RefreshService.py | 14 ++++++------- src/ezgg_lan_manager/types/UserSession.py | 6 +++--- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/VERSION b/VERSION index ce4f5af..4209dba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.7 \ No newline at end of file +0.3.8 \ No newline at end of file diff --git a/src/EzggLanManager.py b/src/EzggLanManager.py index 3436e43..11729f9 100644 --- a/src/EzggLanManager.py +++ b/src/EzggLanManager.py @@ -3,15 +3,13 @@ import logging import sys from pathlib import Path -from uuid import uuid4 from rio import App, Theme, Color, Font, ComponentPage, Session from from_root import from_root -from src.ezgg_lan_manager import pages, init_services, LocalDataService +from src.ezgg_lan_manager import pages, init_services, LocalDataService, RefreshService from src.ezgg_lan_manager.helpers.LoggedInGuard import logged_in_guard, not_logged_in_guard, team_guard from src.ezgg_lan_manager.services.LocalDataService import LocalData -from src.ezgg_lan_manager.types.UserSession import UserSession logger = logging.getLogger("EzggLanManager") @@ -38,6 +36,7 @@ if __name__ == "__main__": # Use this line to fake being any user without having to log in # session.attach(UserSession(id=uuid4(), user_id=30, is_team_member=True)) await session.set_title(lan_info.name) + session.attach(RefreshService()) if session[LocalData].stored_session_token: user_session = session[LocalDataService].verify_token(session[LocalData].stored_session_token) if user_session is not None: @@ -216,7 +215,14 @@ if __name__ == "__main__": } ) - sys.exit(app.run_as_web_server( - host="0.0.0.0", - port=8000, - )) + try: + app.run_as_web_server( + host="0.0.0.0", + port=8000, + ) + except (KeyboardInterrupt, SystemExit): + logger.info("EZGG LAN Manager was shut down.") + sys.exit(0) + except Exception as e: + logger.error(e) + sys.exit(1) diff --git a/src/ezgg_lan_manager/__init__.py b/src/ezgg_lan_manager/__init__.py index b81b07d..ad16fdc 100644 --- a/src/ezgg_lan_manager/__init__.py +++ b/src/ezgg_lan_manager/__init__.py @@ -20,7 +20,7 @@ from src.ezgg_lan_manager.services.UserService import UserService from src.ezgg_lan_manager.types import * # Inits services in the correct order -def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService, ReceiptPrintingService, TournamentService, TeamService, RefreshService]: +def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService, ReceiptPrintingService, TournamentService, TeamService]: logging.basicConfig(level=logging.DEBUG) configuration_service = ConfigurationService(from_root("config.toml")) db_service = DatabaseService(configuration_service.get_database_configuration()) @@ -37,4 +37,4 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe team_service = TeamService(db_service) refresh_service = RefreshService() - return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service, receipt_printing_service, tournament_service, team_service, refresh_service + return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service, receipt_printing_service, tournament_service, team_service diff --git a/src/ezgg_lan_manager/components/UserInfoBox.py b/src/ezgg_lan_manager/components/UserInfoBox.py index 3fa5689..5b170e6 100644 --- a/src/ezgg_lan_manager/components/UserInfoBox.py +++ b/src/ezgg_lan_manager/components/UserInfoBox.py @@ -68,9 +68,10 @@ class UserInfoBox(Component): @event.on_populate async def async_init(self) -> None: self.user = await self.session[UserService].get_user(self.user_id) - self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id) - self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id) - self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id) + if self.user is not None: + self.user_balance = await self.session[AccountingService].get_balance(self.user.user_id) + self.user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id) + self.user_seat = await self.session[SeatingService].get_user_seat(self.user.user_id) self.session[AccountingService].add_update_hook(self.update) async def update(self) -> None: diff --git a/src/ezgg_lan_manager/pages/CateringPage.py b/src/ezgg_lan_manager/pages/CateringPage.py index 74d40fc..fac82eb 100644 --- a/src/ezgg_lan_manager/pages/CateringPage.py +++ b/src/ezgg_lan_manager/pages/CateringPage.py @@ -18,7 +18,6 @@ class CateringPage(Component): @event.on_populate async def on_populate(self) -> None: - self.session[RefreshService].subscribe(self.on_populate) await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Catering") self.all_menu_items = await self.session[CateringService].get_menu() diff --git a/src/ezgg_lan_manager/services/RefreshService.py b/src/ezgg_lan_manager/services/RefreshService.py index baaef84..94d8fb4 100644 --- a/src/ezgg_lan_manager/services/RefreshService.py +++ b/src/ezgg_lan_manager/services/RefreshService.py @@ -1,17 +1,17 @@ -from typing import Callable +from typing import Callable, Optional class RefreshService: """ - rio.Components can subscribe to this service with their on_populate method. - Those methods get called whenever a overall refresh is needed. Usually when the user logs in or out. + The active rio.Components can subscribe to this service with their on_populate method. + This methods get called whenever a overall refresh is needed. Usually when the user logs in or out. """ def __init__(self) -> None: - self.subscribers: set[Callable] = set() + self.subscriber: Optional[Callable] = None def subscribe(self, refresh_cb: Callable) -> None: - self.subscribers.add(refresh_cb) + self.subscriber = refresh_cb async def trigger_refresh(self) -> None: - for refresh_cb in self.subscribers: - await refresh_cb() + if self.subscriber is not None: + await self.subscriber() diff --git a/src/ezgg_lan_manager/types/UserSession.py b/src/ezgg_lan_manager/types/UserSession.py index 52e4e4f..133c386 100644 --- a/src/ezgg_lan_manager/types/UserSession.py +++ b/src/ezgg_lan_manager/types/UserSession.py @@ -1,9 +1,9 @@ -from dataclasses import dataclass from uuid import UUID +from rio import Dataclass -@dataclass -class UserSession: + +class UserSession(Dataclass): id: UUID user_id: int is_team_member: bool -- 2.45.2