mc-server-manager/agent/source/app.d

81 lines
2.4 KiB
D

import std.stdio;
import std.algorithm;
import std.array;
import std.json;
import std.datetime;
import requests;
import shared_utils.server_status;
import config;
import server_metadata;
import server_actions;
/**
* 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();
ServerMetaData[] servers = readServerMetaData();
ServerStatus[] statuses = servers.map!(determineStatus).array;
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);
}
}
void sendServerStatusToWeb(in ServerStatus[] statuses, in AgentConfig config) {
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
)
);
}
}
void startRequestedServers(ServerMetaData[] servers, AgentConfig config) {
auto content = getContent(config.webUrl ~ "/api/server-requests");
JSONValue jsonContent = parseJSON(cast(string) content.data);
string[] requestedServerNames = jsonContent.array()
.map!(node => node.str)
.array;
foreach (server; servers) {
if (canFind(requestedServerNames, server.name)) {
startServer(server, config);
}
}
}
void checkForEmptyServers(ServerMetaData[] servers, ServerStatus[] statuses, AgentConfig config) {
foreach (i, server; servers) {
ServerStatus status = statuses[i];
if (status.online && status.playersOnline > 0) {
removeIdleTrackerFileIfPresent(server);
} else if (status.online && status.playersOnline == 0) {
const Duration idleTime = getOrCreateIdleTrackerFileAndGetAge(server);
if (idleTime.total!"minutes" > config.serverInactivityTimeoutMinutes) {
stopServer(server, config);
}
}
}
}