Fixed orphaned processes and added logging

This commit is contained in:
Malasaur 2025-12-16 23:57:35 +01:00
parent 17fc911290
commit cd2eb8de9d
No known key found for this signature in database
6 changed files with 177 additions and 46 deletions

97
main.py
View file

@ -1,11 +1,11 @@
from asyncio import create_task
from typing import Annotated, Optional
import uvicorn
from classes import ProcessStatus
from controllers import Controllers
from fastapi import FastAPI, Header
from fastapi import BackgroundTasks, FastAPI, Header
from fastapi.responses import StreamingResponse
from logs import logger
from models import Models
from responses import Responses
from util import check_password, stop_server
@ -14,14 +14,17 @@ app = FastAPI()
@app.get("/start")
async def start() -> Responses.StartResponse:
async def start(tasks: BackgroundTasks) -> Responses.StartResponse:
"""Starts the Server's process if it is not already running.
Returns:
status: "started" or "running".
message: The Server's response.
"""
logger.debug("/start")
if Controllers.process.status() == ProcessStatus.RUNNING:
logger.debug("/start - The Server was already running")
return {
"status": "running",
"message": "The Server was already running.",
@ -29,11 +32,13 @@ async def start() -> Responses.StartResponse:
if Controllers.maintainance.is_set():
Controllers.maintainance.unset()
logger.debug("/start - Unset maintainance")
Controllers.process.start()
tasks.add_task(Controllers.process.start)
logger.info("/start - Starting server")
return {
"status": "started",
"message": "The Server was started.",
"status": "starting",
"message": "The Server is starting.",
}
@ -52,22 +57,30 @@ async def status() -> Responses.StatusResponse:
list: the list of online players' usernames as strings.
"""
logger.debug("/status")
process_status = Controllers.process.status()
if process_status != ProcessStatus.RUNNING:
# Crashed
if process_status == ProcessStatus.CRASHED:
logger.debug("/status - The Server has crashed")
return {
"status": "crashed",
"message": "The Server has crashed.",
}
# Maintainance
if Controllers.maintainance.is_set():
reason = Controllers.maintainance.get()
logger.debug(
'/status - The Server is offline due to maintainance ("%s")', reason
)
return {
"status": "maintainance",
"message": "The Server is offline due to maintainance.",
"reason": Controllers.maintainance.get(),
"reason": reason,
}
# Offline
logger.debug("/status - The Server is offline")
return {
"status": "offline",
"message": "The Server is offline.",
@ -77,12 +90,14 @@ async def status() -> Responses.StatusResponse:
# Starting
if not server_status["online"]:
logger.debug("/status - The Server is starting")
return {
"status": "starting",
"message": "The Server is starting.",
}
# Online
logger.debug("/status - The Server is online")
return {
"status": "online",
"message": "The Server is online.",
@ -101,7 +116,9 @@ async def status() -> Responses.StatusResponse:
@app.get("/stop")
async def stop(
data: Models.StopModel, authorization: Annotated[str, Header()]
data: Models.StopModel,
authorization: Annotated[str, Header()],
tasks: BackgroundTasks,
) -> Responses.StopResponse:
"""Stops the Server.
It waits for `countdown` seconds, then runs `/stop` on the Server, and kills it after `timeout` seconds if it's still alive.
@ -117,8 +134,12 @@ async def stop(
message: The Server's response.
"""
logger.debug("/stop")
check_password(authorization)
create_task(stop_server("STOPPING", data.countdown, data.reason, data.timeout))
tasks.add_task(stop_server, "STOPPING", data.countdown, data.reason, data.timeout)
logger.info("/stop - The Server is stopping")
return {
"status": "stopping",
"message": "The Server is stopping.",
@ -127,7 +148,9 @@ async def stop(
@app.get("/restart")
async def restart(
data: Models.RestartModel, authorization: Annotated[str, Header()]
data: Models.RestartModel,
authorization: Annotated[str, Header()],
tasks: BackgroundTasks,
) -> Responses.RestartResponse:
"""Restarts the Server.
It waits for `countdown` seconds, then runs `/stop` on the Server, and kills it after `timeout` seconds if it's still alive.
@ -145,15 +168,20 @@ async def restart(
"""
check_password(authorization)
create_task(
stop_server(
"RESTARTING",
data.countdown,
data.reason,
data.timeout,
Controllers.process.start,
)
logger.debug("/restart")
tasks.add_task(
stop_server,
"RESTARTING",
data.countdown,
data.reason,
data.timeout,
Controllers.process.start,
)
logger.info("/restart - The Server is restarting")
return {
"status": "restarting",
"message": "The Server is restarting.",
@ -162,7 +190,9 @@ async def restart(
@app.get("/maintainance")
async def maintainance(
data: Models.MaintainanceModel, authorization: Annotated[str, Header()]
data: Models.MaintainanceModel,
authorization: Annotated[str, Header()],
tasks: BackgroundTasks,
) -> Responses.MaintainanceResponse:
"""Stops the Server and sets it to maintainance status.
It waits for `countdown` seconds, then runs `/stop` on the Server, and kills it after `timeout` seconds if it's still alive.
@ -179,15 +209,21 @@ async def maintainance(
"""
check_password(authorization)
create_task(
stop_server(
"STOPPING FOR MAINTAINANCE",
data.countdown,
data.reason,
data.timeout,
Controllers.maintainance.set(data.reason),
)
logger.debug("/maintainance")
tasks.add_task(
stop_server,
"STOPPING FOR MAINTAINANCE",
data.countdown,
data.reason,
data.timeout,
Controllers.maintainance.set,
data.reason,
)
logger.info("/maintainance - The Server is stopping for maintainance")
return {
"status": "stopping",
"message": "The Server is stopping for maintainance.",
@ -210,11 +246,14 @@ async def command(
output: The command's output.
"""
logger.debug('/command {command: "%s"}', data.command)
check_password(authorization)
output = Controllers.server.command(data.command)
return {
"status": "executed",
"message": "The command was executed.",
"output": Controllers.server.command(data.command),
"output": output,
}
@ -227,6 +266,7 @@ async def logs_stream(authorization: Annotated[str, Header()]) -> StreamingRespo
Returns: text/event-stream
"""
logger.debug("/logs/stream")
check_password(authorization)
return StreamingResponse(Controllers.logs.stream(), media_type="text/event-stream")
@ -244,6 +284,7 @@ async def logs_tail(
Returns: text/event-stream
"""
logger.debug("/logs/tail")
check_password(authorization)
return StreamingResponse(Controllers.logs.tail(data.back if data else 10))