ForcePilot/backend/package/yuxi/channel/extensions/minecraft/keepalive.py
Kris b3b6c95094 feat(channel): 添加 Minecraft 渠道扩展
新增 Minecraft 渠道扩展,支持在 Yuxi 平台中集成 Minecraft 游戏服务器渠道。

包含以下功能模块:
- client: Minecraft 客户端封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- auth: 认证管理
- accounts: 账户管理
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- protocol: Minecraft 协议处理
- rcon: RCON 远程控制
- keepalive: 连接保活
- version_adapter: 版本适配
- setup: 初始化设置
- types: 类型定义
2026-05-21 11:26:52 +08:00

74 lines
2.5 KiB
Python

import asyncio
import logging
import random
from yuxi.channel.extensions.minecraft.protocol import write_bool, write_double
logger = logging.getLogger(__name__)
PLAYER_POSITION_INTERVAL = 60.0
KEEP_ALIVE_TIMEOUT = 30.0
class KeepAliveManager:
def __init__(self, client):
self.client = client
self._position_task: asyncio.Task | None = None
self._timeout_task: asyncio.Task | None = None
self._last_keep_alive = 0.0
self._running = False
async def start(self) -> None:
self._running = True
self._last_keep_alive = asyncio.get_event_loop().time()
self._position_task = asyncio.create_task(self._position_loop())
self._timeout_task = asyncio.create_task(self._timeout_monitor())
logger.info("KeepAliveManager started")
async def stop(self) -> None:
self._running = False
if self._position_task:
self._position_task.cancel()
self._position_task = None
if self._timeout_task:
self._timeout_task.cancel()
self._timeout_task = None
logger.info("KeepAliveManager stopped")
async def _position_loop(self) -> None:
x, y, z = 0.0, 64.0, 0.0
while self._running:
try:
await asyncio.sleep(PLAYER_POSITION_INTERVAL + random.uniform(-5, 5))
data = write_double(x) + write_double(y) + write_double(z) + write_bool(True)
await self.client.send_packet(0x1A, data)
logger.debug("Player position sent: (%.1f, %.1f, %.1f)", x, y, z)
except asyncio.CancelledError:
break
except Exception:
logger.exception("Error sending player position")
def record_keep_alive(self) -> None:
self._last_keep_alive = asyncio.get_event_loop().time()
@property
def is_alive(self) -> bool:
elapsed = asyncio.get_event_loop().time() - self._last_keep_alive
return elapsed < KEEP_ALIVE_TIMEOUT
async def _timeout_monitor(self) -> None:
while self._running:
try:
await asyncio.sleep(KEEP_ALIVE_TIMEOUT)
if not self.is_alive:
logger.warning("Keep-Alive timeout detected, connection may be dead")
if self.client and self.client.writer:
self.client.writer.close()
except asyncio.CancelledError:
break
except Exception:
logger.exception("Error in keep-alive timeout monitor")