Fixed orphaned processes and added logging
This commit is contained in:
parent
17fc911290
commit
cd2eb8de9d
6 changed files with 177 additions and 46 deletions
|
|
@ -2,11 +2,13 @@ import shlex
|
|||
from collections import deque
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, Popen
|
||||
from threading import Lock
|
||||
from time import sleep
|
||||
from typing import Literal
|
||||
|
||||
from classes import ProcessStatus, ServerStatus
|
||||
from config import Config
|
||||
from logs import logger
|
||||
from mcrcon import MCRcon
|
||||
from mcstatus import JavaServer
|
||||
|
||||
|
|
@ -18,38 +20,65 @@ class ProcessController:
|
|||
self.last_status: Literal[ProcessStatus.STOPPED, ProcessStatus.CRASHED] = (
|
||||
ProcessStatus.STOPPED
|
||||
)
|
||||
self._lock = Lock()
|
||||
|
||||
def start(self) -> None:
|
||||
"Start the process."
|
||||
if self.status() == ProcessStatus.RUNNING:
|
||||
return
|
||||
logger.debug("ProcessController.start()")
|
||||
with self._lock:
|
||||
if self.status() == ProcessStatus.RUNNING:
|
||||
if self.process:
|
||||
logger.debug(
|
||||
"ProcessController.start() - Process was already running with PID: %s",
|
||||
self.process.pid,
|
||||
)
|
||||
return
|
||||
|
||||
self.process = Popen(
|
||||
self.start_command,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
)
|
||||
self.process = Popen(
|
||||
self.start_command,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
)
|
||||
logger.info(
|
||||
"ProcessController.start() - Started process with PID: %s",
|
||||
self.process.pid,
|
||||
)
|
||||
|
||||
def status(self) -> ProcessStatus:
|
||||
"Check the process' status."
|
||||
logger.debug("ProcessController.status()")
|
||||
|
||||
if not self.process:
|
||||
logger.debug("ProcessController.status() => %s", self.last_status)
|
||||
return self.last_status
|
||||
match self.process.poll():
|
||||
case None:
|
||||
logger.debug("ProcessController.status() => ProcessStatus.RUNNING")
|
||||
return ProcessStatus.RUNNING
|
||||
case 0:
|
||||
logger.debug("ProcessController.status() => ProcessStatus.STOPPED")
|
||||
self.last_status = ProcessStatus.STOPPED
|
||||
return ProcessStatus.STOPPED
|
||||
case _:
|
||||
logger.debug("ProcessController.status() => ProcessStatus.CRASHED")
|
||||
self.last_status = ProcessStatus.CRASHED
|
||||
return ProcessStatus.CRASHED
|
||||
|
||||
def kill(self) -> None:
|
||||
"Kill the process."
|
||||
if self.process:
|
||||
self.process.terminate()
|
||||
self.process = None
|
||||
self.last_status = ProcessStatus.STOPPED
|
||||
logger.debug("ProcessController.kill()")
|
||||
with self._lock:
|
||||
if self.process:
|
||||
pid = self.process.pid
|
||||
self.process.kill()
|
||||
code = self.process.wait()
|
||||
self.process = None
|
||||
logger.info(
|
||||
"ProcessController.kill() - Process with PID %s killed with return code: %s",
|
||||
pid,
|
||||
code,
|
||||
)
|
||||
self.last_status = ProcessStatus.STOPPED
|
||||
|
||||
|
||||
class ServerController:
|
||||
|
|
@ -65,9 +94,11 @@ class ServerController:
|
|||
)
|
||||
|
||||
def status(self) -> ServerStatus:
|
||||
logger.debug("ServerController.status()")
|
||||
try:
|
||||
status = self.server.status()
|
||||
except Exception:
|
||||
logger.debug("ServerController.status() - Server is offline")
|
||||
return {"online": False}
|
||||
|
||||
players = []
|
||||
|
|
@ -75,6 +106,7 @@ class ServerController:
|
|||
for player in status.players.sample:
|
||||
players.append(player.name)
|
||||
|
||||
logger.debug("ServerController.status() - Server is online")
|
||||
return {
|
||||
"online": True,
|
||||
"icon": status.icon,
|
||||
|
|
@ -87,12 +119,18 @@ class ServerController:
|
|||
}
|
||||
|
||||
def command(self, command: str) -> str:
|
||||
logger.debug('ServerController.command(command="%s")', command)
|
||||
try:
|
||||
self.rcon.connect()
|
||||
output = self.rcon.command(command)
|
||||
self.rcon.disconnect()
|
||||
logger.info('ServerController.command(command="%s") => %s', command, output)
|
||||
return output
|
||||
except Exception:
|
||||
logger.exception(
|
||||
'ServerController.command(command="%s") - Command execution failed',
|
||||
command,
|
||||
)
|
||||
return ""
|
||||
|
||||
|
||||
|
|
@ -101,19 +139,28 @@ class MaintainanceController:
|
|||
self.mnt_file = Path(Config.MAINTAINANCE_FILE)
|
||||
|
||||
def set(self, reason: str):
|
||||
logger.debug('MaintainanceController.set(reason="%s")', reason)
|
||||
self.mnt_file.write_text(reason)
|
||||
|
||||
def is_set(self) -> bool:
|
||||
logger.debug("MaintainanceController.is_set() => %s", self.mnt_file.is_file())
|
||||
return self.mnt_file.is_file()
|
||||
|
||||
def get(self) -> str:
|
||||
if self.is_set():
|
||||
logger.debug(
|
||||
"MaintainanceController.get() => %s", self.mnt_file.read_text()
|
||||
)
|
||||
return self.mnt_file.read_text()
|
||||
|
||||
logger.debug("MaintainanceController.get() => ")
|
||||
return ""
|
||||
|
||||
def unset(self):
|
||||
logger.debug("MaintainanceController.unset()")
|
||||
if self.is_set():
|
||||
self.mnt_file.unlink()
|
||||
logger.debug("MaintainanceController.unset() - Maintainance file was unset")
|
||||
|
||||
|
||||
class LogsController:
|
||||
|
|
@ -121,16 +168,21 @@ class LogsController:
|
|||
self.log_file = Path(Config.LOG_FILE)
|
||||
|
||||
def stream(self):
|
||||
logger.debug("LogsController.stream()")
|
||||
i = 0
|
||||
with self.log_file.open() as f:
|
||||
f.seek(0, 2)
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line:
|
||||
logger.debug("LogsController.stream() - Yielding line %s", i)
|
||||
i += 1
|
||||
yield line
|
||||
else:
|
||||
sleep(0.1)
|
||||
|
||||
def tail(self, back: int = 10):
|
||||
logger.debug("LogsController.tail(back=%s)", back)
|
||||
with self.log_file.open() as f:
|
||||
for line in deque(f, maxlen=back):
|
||||
yield line
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue