add: getting player inventory
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
from fastapi import APIRouter
|
||||
from app.services.server.command import CommandService
|
||||
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
|
||||
import uuid
|
||||
|
||||
@ -28,6 +28,26 @@ async def add_server_command(command_data: ServerCommand):
|
||||
async def get_server_commands(server_ip: str):
|
||||
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):
|
||||
"""Обновляет время последней активности сервера"""
|
||||
from app.db.database import db
|
||||
|
@ -7,3 +7,7 @@ class ServerCommand(BaseModel):
|
||||
require_online_player: Optional[bool] = False
|
||||
target_message: Optional[str] = None # Сообщение для цели
|
||||
global_message: Optional[str] = None # Сообщение для остальных
|
||||
|
||||
class InventoryRequest(BaseModel):
|
||||
server_ip: str
|
||||
player_name: str
|
||||
|
@ -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()}},
|
||||
|
Reference in New Issue
Block a user