Files
bancho.py/app/bg_loops.py
2025-04-04 21:30:31 +09:00

90 lines
2.8 KiB
Python

from __future__ import annotations
import asyncio
import time
import app.packets
import app.settings
import app.state
from app.constants.privileges import Privileges
from app.logging import Ansi
from app.logging import log
OSU_CLIENT_MIN_PING_INTERVAL = 300000 // 1000 # defined by osu!
async def initialize_housekeeping_tasks() -> None:
"""Create tasks for each housekeeping tasks."""
log("Initializing housekeeping tasks.", Ansi.LCYAN)
loop = asyncio.get_running_loop()
app.state.sessions.housekeeping_tasks.update(
{
loop.create_task(task)
for task in (
_remove_expired_donation_privileges(interval=30 * 60),
_update_bot_status(interval=5 * 60),
_disconnect_ghosts(interval=OSU_CLIENT_MIN_PING_INTERVAL // 3),
)
},
)
async def _remove_expired_donation_privileges(interval: int) -> None:
"""Remove donation privileges from users with expired sessions."""
while True:
if app.settings.DEBUG:
log("Removing expired donation privileges.", Ansi.LMAGENTA)
expired_donors = await app.state.services.database.fetch_all(
"SELECT id FROM users "
"WHERE donor_end <= UNIX_TIMESTAMP() "
"AND priv & :donor_priv",
{"donor_priv": Privileges.DONATOR.value},
)
for expired_donor in expired_donors:
player = await app.state.sessions.players.from_cache_or_sql(
id=expired_donor["id"],
)
assert player is not None
# TODO: perhaps make a `revoke_donor` method?
await player.remove_privs(Privileges.DONATOR)
player.donor_end = 0
await app.state.services.database.execute(
"UPDATE users SET donor_end = 0 WHERE id = :id",
{"id": player.id},
)
if player.is_online:
player.enqueue(
app.packets.notification("Your supporter status has expired."),
)
log(f"{player}'s supporter status has expired.", Ansi.LMAGENTA)
await asyncio.sleep(interval)
async def _disconnect_ghosts(interval: int) -> None:
"""Actively disconnect users above the
disconnection time threshold on the osu! server."""
while True:
await asyncio.sleep(interval)
current_time = time.time()
for player in app.state.sessions.players:
if current_time - player.last_recv_time > OSU_CLIENT_MIN_PING_INTERVAL:
log(f"Auto-dced {player}.", Ansi.LMAGENTA)
player.logout()
async def _update_bot_status(interval: int) -> None:
"""Re roll the bot status, every `interval`."""
while True:
await asyncio.sleep(interval)
app.packets.bot_stats.cache_clear()