add balance

This commit is contained in:
Yuriy Yuriev
2026-05-14 21:04:28 +07:00
parent bdf3fef7ec
commit fe9ada0558
7 changed files with 734 additions and 170 deletions
+7 -12
View File
@@ -116,21 +116,16 @@ class BackgroundTaskManager:
Returns:
Number of tasks cancelled
"""
cancelled = 0
async with self._lock:
for task in list(self._tasks.values()):
if not task.done():
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
cancelled += 1
running = [t for t in self._tasks.values() if not t.done()]
for task in running:
task.cancel()
if running:
await asyncio.gather(*running, return_exceptions=True)
self._tasks.clear()
self._task_info.clear()
cancelled = len(running)
logger.info(f"All tasks cancelled: {cancelled}")
return cancelled
+55 -2
View File
@@ -44,6 +44,7 @@ class TaskStorage:
"successful_visits": params.successful_visits,
"links_found": params.links_found,
"chat_id": params.chat_id,
"user_id": params.user_id,
"started_at": params.started_at.isoformat() if params.started_at else None,
}
@@ -69,6 +70,7 @@ class TaskStorage:
successful_visits=data.get("successful_visits", 0),
links_found=data.get("links_found", 0),
chat_id=data.get("chat_id"),
user_id=data.get("user_id"),
)
if data.get("started_at"):
try:
@@ -84,8 +86,12 @@ class TaskStorage:
def _load_sync(self) -> dict:
if not self.file_path.exists():
return {}
with open(self.file_path, "r", encoding="utf-8") as f:
return json.load(f)
try:
with open(self.file_path, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"Failed to load tasks: {e}")
return {}
async def save_tasks(self, tasks: Dict[str, TaskParams]) -> None:
async with self._lock:
@@ -165,3 +171,50 @@ class ChatStorage:
if key in data and channel in data[key]:
data[key].remove(channel)
await asyncio.to_thread(self._save_sync, data)
class BalanceStorage:
"""Баланс переходов пользователей."""
def __init__(self, file_path: str = "data/balances.json"):
self.file_path = Path(file_path)
self.file_path.parent.mkdir(parents=True, exist_ok=True)
self._lock = asyncio.Lock()
def _load_sync(self) -> dict:
if not self.file_path.exists():
return {}
try:
with open(self.file_path, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"Failed to load balances: {e}")
return {}
def _save_sync(self, data: dict) -> None:
with open(self.file_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
async def get_balance(self, user_id: int) -> int:
async with self._lock:
data = await asyncio.to_thread(self._load_sync)
return data.get(str(user_id), 0)
async def add_balance(self, user_id: int, amount: int) -> int:
async with self._lock:
data = await asyncio.to_thread(self._load_sync)
data[str(user_id)] = data.get(str(user_id), 0) + amount
await asyncio.to_thread(self._save_sync, data)
return data[str(user_id)]
async def deduct(self, user_id: int, amount: int = 1) -> int:
async with self._lock:
data = await asyncio.to_thread(self._load_sync)
new_bal = max(0, data.get(str(user_id), 0) - amount)
data[str(user_id)] = new_bal
await asyncio.to_thread(self._save_sync, data)
return new_bal
async def get_all(self) -> dict:
async with self._lock:
return await asyncio.to_thread(self._load_sync)
+16 -8
View File
@@ -48,7 +48,8 @@ class TaskParams:
successful_visits: int = 0
links_found: int = 0
chat_id: Optional[int] = None
user_id: Optional[int] = None # Telegram user_id, если задача создана пользователем
completed: bool = False # Задача завершена
stopped: bool = False # Задача остановлена пользователем
@@ -241,15 +242,22 @@ class TaskManager:
async def get_stats(self) -> dict:
"""Общая статистика."""
twitch_tasks = await self.get_twitch_tasks()
visit_tasks = await self.get_visit_tasks()
twitch = visit = paused = active = 0
for p in self._tasks.values():
if p.task_type == "twitch_irc":
twitch += 1
elif p.task_type == "visit":
visit += 1
if p.paused:
paused += 1
else:
active += 1
return {
"total": len(self._tasks),
"twitch": len(twitch_tasks),
"visit": len(visit_tasks),
"paused": sum(1 for p in self._tasks.values() if p.paused),
"active": sum(1 for p in self._tasks.values() if not p.paused),
"twitch": twitch,
"visit": visit,
"paused": paused,
"active": active,
}
def _get_task_info(self, task_id: str, params: TaskParams) -> str: