2024-06-27 15:58:40 +00:00
|
|
|
import std.stdio;
|
|
|
|
import std.algorithm;
|
|
|
|
import std.array;
|
2024-08-03 18:15:41 +00:00
|
|
|
import std.json;
|
2024-06-27 15:58:40 +00:00
|
|
|
import std.datetime;
|
|
|
|
|
|
|
|
import requests;
|
|
|
|
|
|
|
|
import shared_utils.server_status;
|
|
|
|
|
2024-08-03 18:15:41 +00:00
|
|
|
import config;
|
|
|
|
import server_metadata;
|
|
|
|
import server_actions;
|
2024-06-27 15:58:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This program will run frequently (maybe every minute or more), and does the following:
|
|
|
|
* - Fetches a list of requested servers from the mc-server-manager API, and starts them.
|
|
|
|
* - Checks for any servers without any players online, and writes a blank file to track.
|
|
|
|
* - For servers with nobody online, and a timestamp file older than N minutes, the server is shut down.
|
|
|
|
*/
|
|
|
|
void main() {
|
|
|
|
AgentConfig config = readConfig();
|
2024-08-03 18:15:41 +00:00
|
|
|
ServerMetaData[] servers = readServerMetaData();
|
|
|
|
ServerStatus[] statuses = servers.map!(determineStatus).array;
|
2024-06-27 15:58:40 +00:00
|
|
|
try {
|
|
|
|
sendServerStatusToWeb(statuses, config);
|
|
|
|
} catch (Exception e) {
|
|
|
|
stderr.writeln(e.msg);
|
|
|
|
}
|
|
|
|
checkForEmptyServers(servers, statuses, config);
|
|
|
|
try {
|
|
|
|
startRequestedServers(servers, config);
|
|
|
|
} catch (Exception e) {
|
|
|
|
stderr.writeln(e.msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 18:15:41 +00:00
|
|
|
void sendServerStatusToWeb(in ServerStatus[] statuses, in AgentConfig config) {
|
2024-06-27 15:58:40 +00:00
|
|
|
JSONValue jsonPayload = serializeServerStatuses(statuses);
|
|
|
|
string payload = jsonPayload.toJSON();
|
|
|
|
Request rq = Request();
|
|
|
|
rq.addHeaders(["X-Agent-Key": config.agentKey]);
|
|
|
|
Response resp = rq.post(config.webUrl ~ "/api/servers", payload, "application/json");
|
|
|
|
if (resp.code >= 300) {
|
|
|
|
import std.format;
|
|
|
|
throw new Exception(
|
|
|
|
format!"Failed to post server statuses: Error code %d, Response body: %s"(
|
|
|
|
resp.code,
|
|
|
|
resp.responseBody
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 18:15:41 +00:00
|
|
|
void startRequestedServers(ServerMetaData[] servers, AgentConfig config) {
|
2024-06-27 15:58:40 +00:00
|
|
|
auto content = getContent(config.webUrl ~ "/api/server-requests");
|
|
|
|
JSONValue jsonContent = parseJSON(cast(string) content.data);
|
2024-08-03 18:15:41 +00:00
|
|
|
string[] requestedServerNames = jsonContent.array()
|
|
|
|
.map!(node => node.str)
|
|
|
|
.array;
|
2024-06-27 15:58:40 +00:00
|
|
|
foreach (server; servers) {
|
2024-08-03 18:15:41 +00:00
|
|
|
if (canFind(requestedServerNames, server.name)) {
|
|
|
|
startServer(server, config);
|
2024-06-27 15:58:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-03 18:15:41 +00:00
|
|
|
void checkForEmptyServers(ServerMetaData[] servers, ServerStatus[] statuses, AgentConfig config) {
|
2024-06-27 15:58:40 +00:00
|
|
|
foreach (i, server; servers) {
|
|
|
|
ServerStatus status = statuses[i];
|
2024-08-10 18:29:27 +00:00
|
|
|
if (!status.online || (status.online && status.playersOnline > 0)) {
|
2024-08-03 18:15:41 +00:00
|
|
|
removeIdleTrackerFileIfPresent(server);
|
2024-06-27 15:58:40 +00:00
|
|
|
} else if (status.online && status.playersOnline == 0) {
|
2024-08-03 18:15:41 +00:00
|
|
|
const Duration idleTime = getOrCreateIdleTrackerFileAndGetAge(server);
|
|
|
|
if (idleTime.total!"minutes" > config.serverInactivityTimeoutMinutes) {
|
2024-08-10 18:29:27 +00:00
|
|
|
writefln!"Server %s has been idle for %d minutes, shutting down."(server.name, idleTime.total!"minutes");
|
2024-08-03 18:15:41 +00:00
|
|
|
stopServer(server, config);
|
2024-06-27 15:58:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|