Refator eco code. Split into modules
This commit is contained in:
91
core/economy/house.py
Normal file
91
core/economy/house.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""House account: the bot's own balance, fed by fines and lost bets."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .. import pb_client
|
||||
from ..pb_client import DatabaseError
|
||||
from .store import _log, _now, get_user, _commit
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# House account (bot user)
|
||||
# ---------------------------------------------------------------------------
|
||||
HOUSE_ID: int | None = None
|
||||
_house_pb_id: str | None = None
|
||||
|
||||
|
||||
def set_house(user_id: int) -> None:
|
||||
"""Register the bot's Discord user ID as the house account."""
|
||||
global HOUSE_ID, _house_pb_id
|
||||
if HOUSE_ID != user_id:
|
||||
_house_pb_id = None
|
||||
HOUSE_ID = user_id
|
||||
|
||||
|
||||
async def _house_record_id() -> str | None:
|
||||
"""PocketBase record id of the house account (cached; creates the record on first use)."""
|
||||
global _house_pb_id
|
||||
if HOUSE_ID is None:
|
||||
return None
|
||||
if _house_pb_id is None:
|
||||
house = await get_user(HOUSE_ID)
|
||||
_house_pb_id = house.get("_pb_id") # type: ignore[typeddict-item]
|
||||
return _house_pb_id
|
||||
|
||||
|
||||
async def _credit_house(amount: int) -> None:
|
||||
"""Add `amount` coins to the house via an atomic PocketBase increment.
|
||||
|
||||
Deliberately lock-free: callers hold per-user locks, so this must never
|
||||
acquire one itself (see the locking rules above)."""
|
||||
if amount <= 0:
|
||||
return
|
||||
record_id = await _house_record_id()
|
||||
if record_id is None:
|
||||
return
|
||||
await pb_client.update_record(record_id, {"balance+": amount})
|
||||
|
||||
|
||||
async def get_heist_global_cd() -> float:
|
||||
"""Return unix timestamp until which no new heist can start. Persisted on house record."""
|
||||
if HOUSE_ID is None:
|
||||
return 0.0
|
||||
house = await get_user(HOUSE_ID)
|
||||
return float(house.get("heist_global_cd_until") or 0)
|
||||
|
||||
|
||||
async def set_heist_global_cd(until: float) -> None:
|
||||
"""Persist heist global cooldown expiry to the house account in PocketBase."""
|
||||
record_id = await _house_record_id()
|
||||
if record_id is None:
|
||||
return
|
||||
await pb_client.update_record(record_id, {"heist_global_cd_until": until})
|
||||
|
||||
|
||||
async def _refund_house_safe(amount: int, context: str, related_uid: int) -> None:
|
||||
"""Best-effort refund of `amount` to the house. Logs critical if it fails."""
|
||||
if HOUSE_ID is None or amount <= 0:
|
||||
return
|
||||
try:
|
||||
await _credit_house(amount)
|
||||
except DatabaseError as exc:
|
||||
_log.critical(
|
||||
"House compensation failed (%s, related uid %s, amount %s): %s",
|
||||
context, related_uid, amount, exc,
|
||||
)
|
||||
|
||||
|
||||
async def _refund_user_safe(_unused_house_id, amount: int, context: str, uid: int) -> None:
|
||||
"""Best-effort atomic debit of `amount` from the house (compensates a failed
|
||||
user fine). Logs critical if it fails."""
|
||||
if HOUSE_ID is None or amount <= 0:
|
||||
return
|
||||
try:
|
||||
record_id = await _house_record_id()
|
||||
if record_id:
|
||||
await pb_client.update_record(record_id, {"balance-": amount})
|
||||
except DatabaseError as exc:
|
||||
_log.critical(
|
||||
"House debit compensation failed (%s, related uid %s, amount %s): %s",
|
||||
context, uid, amount, exc,
|
||||
)
|
||||
Reference in New Issue
Block a user