This repository has been archived on 2025-02-16. You can view files and clone it, but cannot push or open issues or pull requests.
Spiffo/cogs/console.py
Corban-Lee Jones 5e216862a6
All checks were successful
Build and Push Docker Image / build (push) Successful in 12s
fix spam + add player disconnect message
2024-12-06 12:34:18 +00:00

121 lines
4.3 KiB
Python

"""
Reads and handles updates in the server console file.
"""
import re
import logging
from pathlib import Path
import aiofiles
from discord.ext import commands, tasks
CONSOLE_FILE_PATH = Path(__file__).parent.parent / "data" / "server-console.txt"
log = logging.getLogger(__name__)
class ConsoleCog(commands.Cog):
"""
Reads and handles the server-console.txt file.
"""
_last_line_number = 0
def __init__(self, bot: commands.Bot):
self.bot = bot
self.monitor_console.start()
@tasks.loop(seconds=1)
async def monitor_console(self):
"""
Check the latest version of the console log file.
"""
if not CONSOLE_FILE_PATH.exists():
self.monitor_console.cancel()
raise FileNotFoundError("Server console file doesn't exist, task cancelled.")
async with aiofiles.open(CONSOLE_FILE_PATH, "r", encoding="utf-8") as file:
# If we are at 0, restarting the bot would cause rapid fire of all log lines,
# instead lets grab the latest line, to prevent spam.
if self._last_line_number == 0:
await file.seek(0, 2)
self._last_line_number = await file.tell()
return
await file.seek(self._last_line_number)
lines = await file.readlines()
if not lines:
log.debug("no new lines to read")
return
for line in lines:
await self.process_console_line(line.strip())
self._last_line_number = await file.tell()
async def process_console_line(self, line: str):
if "CheckModsNeedUpdate" in line:
await self.handle_mod_needs_update(line)
elif "ConnectionManager: [fully-connected]" in line:
await self.handle_player_joined(line)
elif "ConnectionManager: [disconnect]" in line:
await self.handle_player_left(line)
async def handle_mod_needs_update(self, line: str):
log.debug("mod update instruction: %s", line)
async def handle_player_joined(self, line: str):
# example for connect:
# ConnectionManager: [fully-connected] "" connection: guid=1733487070761473 ip=192.168.1.23 steam-id=76561198202697217 access=admin username="corbz" connection-type="UDPRakNet"
re_pattern = r"guid=(\d+) ip=([\d\.]+) steam-id=(\d+) access=(\w+) username=\"([^\"]+)\" connection-type=\"([^\"]+)\""
re_match = re.search(re_pattern, line)
if not re_match:
log.warning("failed to parse player data: %s", line)
return
data = {
"guid": re_match.group(1),
"ip": re_match.group(2),
"steam_id": re_match.group(3),
"access": re_match.group(4),
"username": re_match.group(5),
"connection_type": re_match.group(6),
}
channel = self.bot.get_channel(self.bot.in_game_channel_id)
channel = await self.bot.fetch_channel(self.bot.in_game_channel_id) if not channel else channel
await channel.send(content=f"Player Joined: **{data['username']}**")
async def handle_player_left(self, line: str):
# Example for disconnect:
# ConnectionManager: [disconnect] "receive-disconnect" connection: guid=1733487070761473 ip=192.168.1.23 steam-id=76561198202697217 access=admin username="corbz" connection-type="Disconnected"
re_pattern = r"guid=(\d+) ip=([\d\.]+) steam-id=(\d+) access=(\w+) username=\"([^\"]+)\" connection-type=\"([^\"]+)\""
re_match = re.search(re_pattern, line)
if not re_match:
log.warning("failed to parse player data: %s", line)
return
data = {
"guid": re_match.group(1),
"ip": re_match.group(2),
"steam_id": re_match.group(3),
"access": re_match.group(4),
"username": re_match.group(5),
"connection_type": re_match.group(6),
}
channel = self.bot.get_channel(self.bot.in_game_channel_id)
channel = await self.bot.fetch_channel(self.bot.in_game_channel_id) if not channel else channel
await channel.send(content=f"Player Left: **{data['username']}**")
async def setup(bot: commands.Bot):
cog = ConsoleCog(bot)
await bot.add_cog(cog)
log.info("Added %s cog", cog.__class__.__name__)