feat: new endpoints for users and updated models
This commit is contained in:
102
app/services/coins.py
Normal file
102
app/services/coins.py
Normal file
@ -0,0 +1,102 @@
|
||||
from datetime import datetime
|
||||
from app.db.database import users_collection, sessions_collection
|
||||
|
||||
class CoinsService:
|
||||
async def update_player_coins(self, player_id: str, player_name: str, online_time: int, server_ip: str):
|
||||
"""Обновляет монеты игрока на основе времени онлайн"""
|
||||
|
||||
# Находим пользователя
|
||||
user = await self._find_user_by_uuid(player_id)
|
||||
if not user:
|
||||
return # Пользователь не найден
|
||||
|
||||
# Находим последнее обновление монет
|
||||
last_update = await sessions_collection.find_one({
|
||||
"player_id": player_id,
|
||||
"server_ip": server_ip,
|
||||
"update_type": "coins_update"
|
||||
}, sort=[("timestamp", -1)])
|
||||
|
||||
now = datetime.now()
|
||||
current_coins = user.get("coins", 0)
|
||||
current_total_time = user.get("total_time_played", 0)
|
||||
|
||||
if last_update:
|
||||
# Время с последнего начисления
|
||||
last_timestamp = last_update["timestamp"]
|
||||
seconds_since_update = int((now - last_timestamp).total_seconds())
|
||||
|
||||
# Начисляем монеты только за полные минуты
|
||||
minutes_to_reward = seconds_since_update // 60
|
||||
|
||||
# Если прошло меньше минуты, пропускаем
|
||||
if minutes_to_reward < 1:
|
||||
return
|
||||
else:
|
||||
# Первое обновление (ограничиваем для безопасности)
|
||||
minutes_to_reward = min(online_time // 60, 5)
|
||||
|
||||
if minutes_to_reward > 0:
|
||||
# Обновляем монеты и время
|
||||
new_coins = current_coins + minutes_to_reward
|
||||
new_total_time = current_total_time + (minutes_to_reward * 60)
|
||||
|
||||
# Сохраняем в БД
|
||||
await users_collection.update_one(
|
||||
{"_id": user["_id"]},
|
||||
{"$set": {
|
||||
"coins": new_coins,
|
||||
"total_time_played": new_total_time
|
||||
}}
|
||||
)
|
||||
|
||||
# Сохраняем запись о начислении
|
||||
await sessions_collection.insert_one({
|
||||
"player_id": player_id,
|
||||
"player_name": player_name,
|
||||
"server_ip": server_ip,
|
||||
"update_type": "coins_update",
|
||||
"timestamp": now,
|
||||
"minutes_added": minutes_to_reward,
|
||||
"coins_added": minutes_to_reward
|
||||
})
|
||||
|
||||
print(f"[{now}] Игроку {user.get('username')} начислено {minutes_to_reward} монет. "
|
||||
f"Всего монет: {new_coins}")
|
||||
|
||||
async def _find_user_by_uuid(self, player_id: str):
|
||||
"""Находит пользователя по UUID с поддержкой разных форматов"""
|
||||
|
||||
# Пробуем найти как есть
|
||||
user = await users_collection.find_one({"uuid": player_id})
|
||||
if user:
|
||||
return user
|
||||
|
||||
# Пробуем разные форматы UUID
|
||||
if '-' in player_id:
|
||||
user = await users_collection.find_one({"uuid": player_id.replace('-', '')})
|
||||
else:
|
||||
formatted_uuid = f"{player_id[:8]}-{player_id[8:12]}-{player_id[12:16]}-{player_id[16:20]}-{player_id[20:]}"
|
||||
user = await users_collection.find_one({"uuid": formatted_uuid})
|
||||
|
||||
return user
|
||||
|
||||
async def get_player_coins(self, username: str):
|
||||
"""Возвращает информацию о монетах и времени игрока"""
|
||||
|
||||
user = await users_collection.find_one({"username": username})
|
||||
if not user:
|
||||
return None
|
||||
|
||||
total_time = user.get("total_time_played", 0)
|
||||
hours, remainder = divmod(total_time, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
|
||||
return {
|
||||
"username": username,
|
||||
"coins": user.get("coins", 0),
|
||||
"total_time_played": {
|
||||
"seconds": total_time,
|
||||
"formatted": f"{hours}ч {minutes}м {seconds}с"
|
||||
}
|
||||
}
|
41
app/services/server/command.py
Normal file
41
app/services/server/command.py
Normal file
@ -0,0 +1,41 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from fastapi import HTTPException
|
||||
from typing import Dict
|
||||
|
||||
# Глобальное хранилище команд (в реальном проекте используйте БД)
|
||||
pending_commands: Dict[str, Dict] = {}
|
||||
|
||||
class CommandService:
|
||||
async def add_command(self, command_data):
|
||||
try:
|
||||
command_id = str(uuid.uuid4())
|
||||
pending_commands[command_id] = {
|
||||
"command": command_data.command,
|
||||
"server_ip": command_data.server_ip,
|
||||
"require_online_player": command_data.require_online_player,
|
||||
"created_at": datetime.now().isoformat()
|
||||
}
|
||||
print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
|
||||
f"для сервера {command_data.server_ip}")
|
||||
return {"status": "success", "command_id": command_id}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
async def get_commands(self, server_ip: str):
|
||||
try:
|
||||
# Получаем команды для указанного сервера
|
||||
commands = [
|
||||
{"id": cmd_id, "command": cmd["command"], "require_online_player": cmd["require_online_player"]}
|
||||
for cmd_id, cmd in pending_commands.items()
|
||||
if cmd["server_ip"] == server_ip
|
||||
]
|
||||
|
||||
# Удаляем полученные команды (чтобы не выполнять их повторно)
|
||||
for cmd_id in list(pending_commands.keys()):
|
||||
if pending_commands[cmd_id]["server_ip"] == server_ip:
|
||||
del pending_commands[cmd_id]
|
||||
|
||||
return {"status": "success", "commands": commands}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
70
app/services/server/event.py
Normal file
70
app/services/server/event.py
Normal file
@ -0,0 +1,70 @@
|
||||
from fastapi import HTTPException
|
||||
from datetime import datetime
|
||||
import json
|
||||
from app.services.coins import CoinsService
|
||||
from app.models.server.event import PlayerEvent, OnlinePlayersUpdate
|
||||
|
||||
class EventService:
|
||||
def __init__(self):
|
||||
self.coins_service = CoinsService()
|
||||
|
||||
async def process_event(self, event_data: dict):
|
||||
try:
|
||||
event_type = event_data.get("event_type")
|
||||
server_ip = event_data.get("server_ip", "unknown")
|
||||
|
||||
if event_type == "player_join":
|
||||
player_name = event_data["player_name"]
|
||||
player_id = event_data["player_id"]
|
||||
print(f"[{datetime.now()}] Игрок вошел: {player_name} (ID: {player_id}) "
|
||||
f"IP сервера: {server_ip}")
|
||||
|
||||
elif event_type == "player_quit":
|
||||
player_name = event_data["player_name"]
|
||||
player_id = event_data["player_id"]
|
||||
print(f"[{datetime.now()}] Игрок вышел: {player_name} (ID: {player_id}) "
|
||||
f"IP сервера: {server_ip}")
|
||||
|
||||
elif event_type == "player_session":
|
||||
player_name = event_data["player_name"]
|
||||
player_id = event_data["player_id"]
|
||||
duration = event_data["duration"]
|
||||
|
||||
# Обновляем монеты через выделенный сервис
|
||||
await self.coins_service.update_player_coins(player_id, player_name, duration, server_ip)
|
||||
|
||||
print(f"[{datetime.now()}] Игрок {player_name} провел на сервере: {duration} секунд "
|
||||
f"IP сервера: {server_ip}")
|
||||
|
||||
elif event_type == "online_players_update":
|
||||
players = event_data["players"]
|
||||
print(f"\n[{datetime.now()}] Текущие онлайн-игроки ({len(players)}): "
|
||||
f"IP сервера: {server_ip}")
|
||||
|
||||
# Обрабатываем каждого игрока
|
||||
for player in players:
|
||||
player_id = player["player_id"]
|
||||
player_name = player["player_name"]
|
||||
online_time = player["online_time"]
|
||||
|
||||
# Обновляем монеты через выделенный сервис
|
||||
await self.coins_service.update_player_coins(
|
||||
player_id, player_name, online_time, server_ip
|
||||
)
|
||||
|
||||
hours, remainder = divmod(online_time, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
print(f" - {player_name} (ID: {player_id}) "
|
||||
f"Онлайн: {hours}ч {minutes}м {seconds}с")
|
||||
print()
|
||||
|
||||
else:
|
||||
print(f"[{datetime.now()}] Неизвестное событие: {json.dumps(event_data, indent=2)}")
|
||||
raise HTTPException(status_code=400, detail="Invalid event type")
|
||||
|
||||
return {"status": "success", "message": "Event processed"}
|
||||
|
||||
except Exception as e:
|
||||
print(f"[{datetime.now()}] Ошибка обработки события: {str(e)}")
|
||||
print(f"Полученные данные: {json.dumps(event_data, indent=2)}")
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
Reference in New Issue
Block a user