add: getting player inventory
This commit is contained in:
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()}},
|
||||||
|
Reference in New Issue
Block a user