Skip to content

Commit d62ec70

Browse files
authored
Merge pull request #35 from EvickaStudio/dev
Dev: Add minor updates and patches
2 parents 5bc0880 + b995930 commit d62ec70

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

main.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
from src.core.service_locator import ServiceLocator
1010
from src.core.services import initialize_services
1111
from src.core.utils.retry import with_retry
12+
from src.infrastructure.http.request_manager import request_manager
1213
from src.infrastructure.logging.setup import setup_logging
14+
from src.services.moodle.api import MoodleAPI
1315
from src.services.moodle.notification_handler import MoodleNotificationHandler
1416
from src.ui.cli.screen import animate_logo, logo_lines
1517

@@ -87,9 +89,27 @@ def calculate_sleep_time(consecutive_errors: int, base_interval: int) -> float:
8789
def run_main_loop(config, moodle_handler, notification_processor) -> None:
8890
"""Run the main application loop."""
8991
consecutive_errors = 0
92+
# Session refresh interval in hours
93+
session_refresh_interval = 24.0
94+
95+
# Get Moodle API instance from service locator
96+
locator = ServiceLocator()
97+
moodle_api = locator.get("moodle_api", MoodleAPI)
9098

9199
while True:
92100
try:
101+
# Check if session needs to be refreshed (older than 24 hours)
102+
if request_manager.session_age_hours >= session_refresh_interval:
103+
logging.info(
104+
f"Session is {request_manager.session_age_hours:.2f} hours old. Refreshing..."
105+
)
106+
if moodle_api.refresh_session():
107+
logging.info("Session successfully refreshed")
108+
else:
109+
logging.error(
110+
"Failed to refresh session. Continuing with existing session."
111+
)
112+
93113
success = fetch_and_process(moodle_handler, notification_processor)
94114
if success:
95115
consecutive_errors = 0

src/core/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version information for MoodleMate."""
22

3-
__version__ = "2.0.2"
3+
__version__ = "2.1.0"

src/infrastructure/http/request_manager.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import time
12
from typing import Optional
23

34
import requests
@@ -10,6 +11,7 @@ class RequestManager:
1011

1112
_instance: Optional["RequestManager"] = None
1213
_session: Optional[requests.Session] = None
14+
_session_created_at: float = 0
1315

1416
def __new__(cls) -> "RequestManager":
1517
if cls._instance is None:
@@ -19,13 +21,18 @@ def __new__(cls) -> "RequestManager":
1921

2022
def _setup_session(self) -> None:
2123
"""Setup the global session with default headers."""
24+
# Close existing session if it exists
25+
if self._session is not None:
26+
self._session.close()
27+
2228
self._session = requests.Session()
2329
self._session.headers.update(
2430
{
2531
"User-Agent": f"MoodleMate/{__version__} (+https://github.com/EvickaStudio/Moodle-Mate)",
2632
"Content-Type": "application/x-www-form-urlencoded",
2733
}
2834
)
35+
self._session_created_at = time.time()
2936

3037
@property
3138
def session(self) -> requests.Session:
@@ -42,6 +49,17 @@ def update_headers(self, headers: dict) -> None:
4249
assert self._session is not None
4350
self._session.headers.update(headers)
4451

52+
def reset_session(self) -> None:
53+
"""Reset the session completely, creating a new one."""
54+
self._setup_session()
55+
56+
@property
57+
def session_age_hours(self) -> float:
58+
"""Return the age of the current session in hours."""
59+
if self._session_created_at == 0:
60+
return 0
61+
return (time.time() - self._session_created_at) / 3600
62+
4563

4664
# Global instance
4765
request_manager = RequestManager()

src/services/moodle/api.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ def _init_api(self, url: Optional[str] = None):
3131
"Content-Type": "application/x-www-form-urlencoded",
3232
}
3333
)
34-
self.token = None
35-
self.userid = None
34+
self.token: Optional[str] = None
35+
self.userid: Optional[int] = None
36+
self._username: Optional[str] = None
37+
self._password: Optional[str] = None
3638

3739
def login(self, username: str, password: str) -> bool:
3840
"""
3941
Logs in to the Moodle instance using the provided username and password.
42+
43+
Stores credentials securely for session refresh if successful.
4044
"""
4145
if not username:
4246
raise ValueError("Username is required")
@@ -55,6 +59,9 @@ def login(self, username: str, password: str) -> bool:
5559

5660
if "token" in response.json():
5761
self.token = response.json()["token"]
62+
# Store credentials for session refresh
63+
self._username = username
64+
self._password = password
5865
logger.info("Login successful")
5966
return True
6067

@@ -65,6 +72,26 @@ def login(self, username: str, password: str) -> bool:
6572
logger.error("Request to Moodle failed: %s", e)
6673
return False
6774

75+
def refresh_session(self) -> bool:
76+
"""
77+
Refreshes the session by creating a new session and re-authenticating.
78+
"""
79+
if not self._username or not self._password:
80+
logger.error("Cannot refresh session: No stored credentials")
81+
return False
82+
83+
logger.info("Refreshing Moodle session...")
84+
85+
# Reset the request manager's session
86+
request_manager.reset_session()
87+
88+
# Update our session reference
89+
self.session = request_manager.session
90+
91+
# Re-login with stored credentials
92+
self.token = None
93+
return self.login(self._username, self._password)
94+
6895
def get_site_info(self) -> Optional[dict]:
6996
"""
7097
Retrieves site information from the Moodle instance.

0 commit comments

Comments
 (0)