add: getting player inventory

This commit is contained in:
2025-07-19 01:20:26 +05:00
parent 259e3c373b
commit 44e12723ad
3 changed files with 209 additions and 16 deletions

View File

@ -2,22 +2,29 @@ import uuid
from datetime import datetime
from fastapi import HTTPException
from typing import Dict
from app.db.database import db
# Глобальное хранилище команд (в реальном проекте используйте БД)
pending_commands: Dict[str, Dict] = {}
# Создаем коллекции для хранения команд и инвентаря
pending_commands_collection = db.pending_commands
inventory_requests_collection = db.inventory_requests
inventory_collection = db.inventory
game_servers_collection = db.game_servers
class CommandService:
async def add_command(self, command_data):
try:
command_id = str(uuid.uuid4())
pending_commands[command_id] = {
command_doc = {
"id": command_id,
"command": command_data.command,
"server_ip": command_data.server_ip,
"require_online_player": command_data.require_online_player,
"target_message": command_data.target_message if hasattr(command_data, 'target_message') else None,
"global_message": command_data.global_message if hasattr(command_data, 'global_message') else None,
"created_at": datetime.now().isoformat()
"created_at": datetime.utcnow()
}
await pending_commands_collection.insert_one(command_doc)
print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
f"для сервера {command_data.server_ip}")
@ -31,32 +38,194 @@ class CommandService:
async def get_commands(self, server_ip: str):
try:
# Получаем команды для указанного сервера
commands = [
commands_cursor = pending_commands_collection.find({"server_ip": server_ip})
commands = await commands_cursor.to_list(1000)
result_commands = [
{
"id": cmd_id,
"id": cmd["id"],
"command": cmd["command"],
"require_online_player": cmd["require_online_player"],
"target_message": cmd.get("target_message"),
"global_message": cmd.get("global_message")
}
for cmd_id, cmd in pending_commands.items()
if cmd["server_ip"] == server_ip
for cmd in commands
]
# Удаляем полученные команды (чтобы не выполнять их повторно)
for cmd_id in list(pending_commands.keys()):
if pending_commands[cmd_id]["server_ip"] == server_ip:
del pending_commands[cmd_id]
await pending_commands_collection.delete_many({"server_ip": server_ip})
return {"status": "success", "commands": commands}
return {"status": "success", "commands": result_commands}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
async def request_inventory(self, inventory_request):
"""Создаёт запрос на получение инвентаря игрока"""
try:
request_id = str(uuid.uuid4())
inventory_request_doc = {
"id": request_id,
"server_ip": inventory_request.server_ip,
"player_name": inventory_request.player_name,
"created_at": datetime.utcnow(),
"status": "pending"
}
await inventory_requests_collection.insert_one(inventory_request_doc)
print(f"[{datetime.now()}] Запрос инвентаря игрока {inventory_request.player_name} "
f"с сервера {inventory_request.server_ip}")
# Обновляем last_activity для сервера
await self._update_server_activity(inventory_request.server_ip)
return {"status": "pending", "request_id": request_id}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
async def get_inventory_requests(self, server_ip: str):
"""Получает запросы на инвентарь для указанного сервера"""
try:
requests_cursor = inventory_requests_collection.find(
{"server_ip": server_ip, "status": "pending"}
)
requests = await requests_cursor.to_list(1000)
result_requests = [
{
"id": req["id"],
"player_name": req["player_name"]
}
for req in requests
]
# Помечаем запросы как обработанные
for req in result_requests:
await inventory_requests_collection.update_one(
{"id": req["id"]},
{"$set": {"status": "processing"}}
)
return {"status": "success", "inventory_requests": result_requests}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
async def submit_inventory(self, inventory_data: dict):
"""Принимает данные инвентаря от сервера"""
try:
request_id = inventory_data.get("request_id")
request = await inventory_requests_collection.find_one({"id": request_id})
if not request:
raise HTTPException(status_code=404, detail="Запрос не найден")
player_name = request["player_name"]
server_ip = request["server_ip"]
# Обновляем или создаем запись инвентаря
await inventory_collection.update_one(
{
"player_name": player_name,
"server_ip": server_ip
},
{
"$set": {
"inventory_data": inventory_data.get("inventory", []),
"updated_at": datetime.utcnow()
}
},
upsert=True # Создает новую запись, если не найдена существующая
)
# Помечаем запрос как выполненный
await inventory_requests_collection.update_one(
{"id": request_id},
{"$set": {"status": "completed"}}
)
return {"status": "success"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
async def get_inventory_result(self, request_id: str):
"""Получает результаты запроса инвентаря"""
request = await inventory_requests_collection.find_one({"id": request_id})
if not request:
raise HTTPException(status_code=404, detail="Запрос не найден")
if request["status"] != "completed":
return {"status": request["status"]}
# Получаем инвентарь из коллекции inventory
inventory = await inventory_collection.find_one({
"player_name": request["player_name"],
"server_ip": request["server_ip"]
})
if not inventory:
raise HTTPException(status_code=404, detail="Инвентарь не найден")
return {
"status": "completed",
"result": {
"player_name": inventory["player_name"],
"server_ip": inventory["server_ip"],
"inventory_data": inventory["inventory_data"],
"updated_at": inventory["updated_at"]
}
}
async def get_player_inventory(self, player_name: str, server_ip: str, timeout: int = 10):
"""Запрашивает и ждет получения инвентаря игрока"""
try:
# Проверяем, есть ли уже актуальный инвентарь
existing_inventory = await inventory_collection.find_one({
"player_name": player_name,
"server_ip": server_ip
})
# Если инвентарь уже есть и он достаточно свежий (не старше 1 минуты)
if existing_inventory and "updated_at" in existing_inventory:
if (datetime.utcnow() - existing_inventory["updated_at"]).total_seconds() < 60:
return {
"status": "success",
"player_name": existing_inventory["player_name"],
"server_ip": existing_inventory["server_ip"],
"inventory": existing_inventory["inventory_data"],
"updated_at": existing_inventory["updated_at"]
}
# Запрашиваем новый инвентарь
request_id = str(uuid.uuid4())
inventory_request_doc = {
"id": request_id,
"server_ip": server_ip,
"player_name": player_name,
"created_at": datetime.utcnow(),
"status": "pending"
}
await inventory_requests_collection.insert_one(inventory_request_doc)
print(f"[{datetime.now()}] Запрос инвентаря игрока {player_name} "
f"с сервера {server_ip}")
# Обновляем last_activity для сервера
await self._update_server_activity(server_ip)
# Ждем ответа от сервера
start_time = datetime.utcnow()
while (datetime.utcnow() - start_time).total_seconds() < timeout:
result = await self.get_inventory_result(request_id)
if result["status"] == "completed":
return result
await asyncio.sleep(1) # Ждем 1 секунду перед следующей проверкой
raise HTTPException(status_code=504, detail="Timeout waiting for inventory")
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
async def _update_server_activity(self, server_ip):
"""Обновляет время последней активности для сервера"""
from app.db.database import db
game_servers_collection = db.game_servers
await game_servers_collection.update_one(
{"ip": server_ip},
{"$set": {"last_activity": datetime.utcnow()}},