235 lines
11 KiB
Python
235 lines
11 KiB
Python
import uuid
|
||
from datetime import datetime
|
||
from fastapi import HTTPException
|
||
from typing import Dict
|
||
from app.db.database import db
|
||
import asyncio
|
||
|
||
# Создаем коллекции для хранения команд и инвентаря
|
||
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())
|
||
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.utcnow()
|
||
}
|
||
|
||
await pending_commands_collection.insert_one(command_doc)
|
||
print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
|
||
f"для сервера {command_data.server_ip}")
|
||
|
||
# Обновляем last_activity для сервера
|
||
await self._update_server_activity(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_cursor = pending_commands_collection.find({"server_ip": server_ip})
|
||
commands = await commands_cursor.to_list(1000)
|
||
|
||
result_commands = [
|
||
{
|
||
"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 in commands
|
||
]
|
||
|
||
# Удаляем полученные команды (чтобы не выполнять их повторно)
|
||
await pending_commands_collection.delete_many({"server_ip": server_ip})
|
||
|
||
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):
|
||
"""Обновляет время последней активности для сервера"""
|
||
await game_servers_collection.update_one(
|
||
{"ip": server_ip},
|
||
{"$set": {"last_activity": datetime.utcnow()}},
|
||
upsert=False # Не создаем новый сервер, только обновляем существующий
|
||
)
|