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

87 lines
2.8 KiB
D

module server_metadata;
import std.json;
import std.file;
import std.path;
import std.string : endsWith;
import std.array;
import std.algorithm;
import std.stdio;
import properd;
/**
* The set of information about each server that we can obtain by reading the
* server's directory and files in it (service file, properties, etc.).
*/
struct ServerMetaData {
/// The name of the server, as declared in servers.json.
const string name;
/// The display name of the server, as declared in servers.json.
const string displayName;
/// The description of the server, as declared in servers.json.
const string description;
/// The directory to find the server's files in.
const string directory;
/// The name of the server's SystemD service, as determined by searching the server's directory.
const string serviceName;
/// The port used for player connections.
const ushort port;
/// The password for connecting to the RCON service of the server.
const string rconPassword;
/// The port for connecting to the RCON service.
const ushort rconPort;
/// The maximum number of players for the server.
const int maxPlayers;
}
/**
* Reads server metadata from each server defined in "servers.json", by parsing
* its "server.properties" file, SystemD service file, and more.
* Returns: The list of server metadata structs.
*/
ServerMetaData[] readServerMetaData() {
import properd;
JSONValue arr = parseJSON(readText("servers.json"));
return arr.array.map!((s) {
string name = s.object["name"].str;
string displayName = s.object["displayName"].str;
string description = s.object["description"].str;
string directory = s.object["directory"].str;
string systemDServiceName = findSystemDServiceName(directory);
string propsFile = buildPath(directory, "server.properties");
if (!exists(propsFile)) throw new Exception("Missing server properties file: " ~ propsFile);
try {
auto props = readProperties(propsFile);
ushort port = props.as!(ushort)("server-port");
string rconPassword = props["rcon.password"];
ushort rconPort = props.as!(ushort)("rcon.port");
int maxPlayers = props.as!(int)("max-players");
return ServerMetaData(
name,
displayName,
description,
directory,
systemDServiceName,
port,
rconPassword,
rconPort,
maxPlayers
);
} catch (PropertyException e) {
stderr.writefln!"Error parsing properties from %s: %s"(propsFile, e.msg);
throw e;
}
}).array;
}
private string findSystemDServiceName(string serverDir) {
foreach (DirEntry entry; dirEntries(serverDir, SpanMode.shallow, false)) {
if (entry.name.endsWith(".service")) {
return baseName(stripExtension(entry.name));
}
}
throw new Exception("No SystemD service file found in " ~ serverDir);
}