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

@ -1,7 +1,7 @@
from fastapi import APIRouter from fastapi import APIRouter
from app.services.server.command import CommandService from app.services.server.command import CommandService
from app.services.server.event import EventService from app.services.server.event import EventService
from app.models.server.command import ServerCommand from app.models.server.command import ServerCommand, InventoryRequest
from datetime import datetime from datetime import datetime
import uuid import uuid
@ -28,6 +28,26 @@ async def add_server_command(command_data: ServerCommand):
async def get_server_commands(server_ip: str): async def get_server_commands(server_ip: str):
return await CommandService().get_commands(server_ip) return await CommandService().get_commands(server_ip)
@router.post("/inventory")
async def request_player_inventory(inventory_request: InventoryRequest):
"""Создаёт запрос на получение инвентаря игрока"""
return await CommandService().request_inventory(inventory_request)
@router.get("/inventory/requests")
async def get_inventory_requests(server_ip: str):
"""Получает список запросов инвентаря для сервера"""
return await CommandService().get_inventory_requests(server_ip)
@router.post("/inventory/submit")
async def submit_inventory(inventory_data: dict):
"""Принимает данные инвентаря от сервера"""
return await CommandService().submit_inventory(inventory_data)
@router.get("/inventory/{request_id}")
async def get_inventory_result(request_id: str):
"""Получает результаты запроса инвентаря"""
return await CommandService().get_inventory_result(request_id)
async def update_server_activity(server_ip): async def update_server_activity(server_ip):
"""Обновляет время последней активности сервера""" """Обновляет время последней активности сервера"""
from app.db.database import db from app.db.database import db

View File

@ -7,3 +7,7 @@ class ServerCommand(BaseModel):
require_online_player: Optional[bool] = False require_online_player: Optional[bool] = False
target_message: Optional[str] = None # Сообщение для цели target_message: Optional[str] = None # Сообщение для цели
global_message: Optional[str] = None # Сообщение для остальных global_message: Optional[str] = None # Сообщение для остальных
class InventoryRequest(BaseModel):
server_ip: str
player_name: str

View File

@ -2,22 +2,29 @@ import uuid
from datetime import datetime from datetime import datetime
from fastapi import HTTPException from fastapi import HTTPException
from typing import Dict 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: class CommandService:
async def add_command(self, command_data): async def add_command(self, command_data):
try: try:
command_id = str(uuid.uuid4()) command_id = str(uuid.uuid4())
pending_commands[command_id] = { command_doc = {
"id": command_id,
"command": command_data.command, "command": command_data.command,
"server_ip": command_data.server_ip, "server_ip": command_data.server_ip,
"require_online_player": command_data.require_online_player, "require_online_player": command_data.require_online_player,
"target_message": command_data.target_message if hasattr(command_data, 'target_message') else None, "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, "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} " print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
f"для сервера {command_data.server_ip}") f"для сервера {command_data.server_ip}")
@ -31,32 +38,194 @@ class CommandService:
async def get_commands(self, server_ip: str): async def get_commands(self, server_ip: str):
try: 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"], "command": cmd["command"],
"require_online_player": cmd["require_online_player"], "require_online_player": cmd["require_online_player"],
"target_message": cmd.get("target_message"), "target_message": cmd.get("target_message"),
"global_message": cmd.get("global_message") "global_message": cmd.get("global_message")
} }
for cmd_id, cmd in pending_commands.items() for cmd in commands
if cmd["server_ip"] == server_ip
] ]
# Удаляем полученные команды (чтобы не выполнять их повторно) # Удаляем полученные команды (чтобы не выполнять их повторно)
for cmd_id in list(pending_commands.keys()): await pending_commands_collection.delete_many({"server_ip": server_ip})
if pending_commands[cmd_id]["server_ip"] == server_ip:
del pending_commands[cmd_id]
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: except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) raise HTTPException(status_code=400, detail=str(e))
async def _update_server_activity(self, server_ip): 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( await game_servers_collection.update_one(
{"ip": server_ip}, {"ip": server_ip},
{"$set": {"last_activity": datetime.utcnow()}}, {"$set": {"last_activity": datetime.utcnow()}},