The exaroton API allows automated access to some basic functionalities of your game servers, such as starting or stopping the server. You can read the API documentation here: https://developers.exaroton.com
This is the official Node.js implementation of this API.
npm install exaroton
To use the API and this client you have to get your API key, which you can generate in your exaroton account settings: https://exaroton.com/account
const {Client} = require('exaroton');
const client = new Client(token);
Remember to keep your token secret and don't add it to any private or public code repositories.
let account = await client.getAccount();
console.log("My account is " + account.name + " and I have " + account.credits + " credits.");
The account object contains the fields and information as listed in the documentation.
let servers = await client.getServers();
for(let server of servers) {
console.log(server.name + ": " + server.id);
}
Each server object contains the fields and information as listed in the documentation.
let server = client.server(id);
await server.get();
console.log(server.name + ": " + server.id);
console.log(server.status);
if (server.hasStatus(server.STATUS.ONLINE)) {
console.log("Server is online.");
} else if (server.hasStatus([server.STATUS.PREPARING, server.STATUS.LOADING, server.STATUS.STARTING])) {
console.log("Server is online soon.");
} else {
console.log("Server is offline.");
}
The server status is an integer
as described in the documentation. You can use
the ServerStatus object, which you can require on its own const {ServerStatus} = require('exaroton')
or via the
shorthand server.STATUS
property.
try {
await server.start();
await server.stop();
await server.restart();
} catch (e) {
console.error(e.message);
}
It's important to catch errors, because incorrect calls, e.g. a server.stop()
when the server is offline will result in an error.
try {
await server.executeCommand("say Hello world!");
} catch (e) {
console.error(e.message);
}
try {
let logs = await server.getLogs();
console.log(logs);
} catch (e) {
console.error(e.message);
}
This is cached and will not return the latest updates immediately. It's also not possible to get the server logs while the server is loading, stopping or saving.
try {
let url = await server.shareLogs();
console.log(url);
} catch (e) {
console.error(e.message);
}
This is cached and will not return the latest updates immediately. It's also not possible to share the server logs while the server is loading, stopping or saving.
try {
let ram = await server.getRAM();
console.log("This server has " + ram + " GB RAM.");
} catch (e) {
console.error(e.message);
}
The amount of RAM is returned in full GiB.
try {
await server.setRAM(8);
} catch (e) {
console.error(e.message);
}
The RAM is set in full GiB and has to be between 2 and 16.
try {
let motd = await server.getMOTD();
console.log(motd);
} catch (e) {
console.error(e.message);
}
try {
await server.setMOTD("Hello world!");
} catch (e) {
console.error(e.message);
}
A player list is a list of players such as the whitelist, ops or bans. Player list entries are usually usernames, but might be something else, e.g. IPs in the banned-ips list. All player list operations are storage operations that might take a while, so try to reduce the amount of requests and combine actions when possible (e.g. adding/deleting multiple entries at once). Player lists are also cached any might not immediately return new results when changed through other methods e.g. in-game.
You can list all available player lists...
try {
let lists = await server.getPlayerLists();
console.log(lists);
} catch (e) {
console.error(e.message);
}
... or if you already know the name (e.g. "whitelist") you can directly create a player list object:
try {
let list = server.getPlayerList("whitelist");
console.log(list);
} catch (e) {
console.error(e.message);
}
try {
let list = server.getPlayerList("whitelist");
let entries = await list.getEntries();
console.log(entries);
} catch (e) {
console.error(e.message);
}
We handle all the heavy work of adding player list entries for you, e.g. automatically adding UUIDs depending on the online mode or executing the necessary commands while the server is running.
try {
let list = server.getPlayerList("whitelist");
await list.addEntry("Steve"); // add just one entry
await list.addEntries(["Steve", "Alex"]); // add multiple entries at once
console.log(await list.getEntries());
} catch (e) {
console.error(e.message);
}
try {
let list = server.getPlayerList("whitelist");
await list.deleteEntry("Steve"); // delete just one entry
await list.deleteEntries(["Steve", "Alex"]); // delete multiple entries at once
console.log(await list.getEntries());
} catch (e) {
console.error(e.message);
}
You can request information about files, download and upload files.
This just creates the file object but doesn't request any information or content
let file = server.getFile("server.properties");
If a file doesn't exist you will get a 404 error.
try {
await file.getInfo();
console.log(file);
} catch (e) {
console.error(e.message);
}
try {
// get the children of the directory
let children = await file.getChildren();
console.log(children);
// iterate over the children
// each child is a file object
for (let child of children) {
console.log(child);
}
} catch (e) {
console.error(e.message);
}
try {
// get the content of the file in a variable
// large files will cause high memory usage
let content = await file.getContent();
console.log(content);
// or download the file to a local file
await file.download("test.txt");
// or download the file to a stream
let stream = await file.downloadToStream(createWriteStream("test.txt"));
} catch (e) {
console.error(e.message);
}
try {
// change the content of the file
await file.setContent("Hello world!");
// or upload a local file
await file.upload("test.txt");
// or upload from a stream
await file.uploadFromStream(createReadStream("test.txt"));
} catch (e) {
console.error(e.message);
}
try {
await file.delete();
} catch (e) {
console.error(e.message);
}
try {
await file.createAsDirectory();
} catch (e) {
console.error(e.message);
}
Config files are files that contain server configuration and are shown as forms rather than plain text files in the exaroton panel.
You can get a config file object by using the getConfig()
method on a file object.
Whether a file is a config file can be checked using the isConfigFile
property.
let file = server.getFile("server.properties");
let config = file.getConfig();
let options = await config.getOptions();
for(let [key, option] of options) {
console.log(key, option.getValue());
}
let options = await config.getOptions();
options.get("max-players").setValue(26);
options.get("pvp").setValue(false);
await config.save();
Options of type select
or multiselect
have a list of possible values.
let options = await config.getOptions();
console.log(options.get("difficulty").getOptions());
Credit pools allow sharing the costs of a server between multiple users.
let pools = await client.getPools();
console.log(pools);
let server = client.pool(id);
await pool.get();
console.log(pool.name + ": " + pool.credits);
let members = await pool.getMembers();
console.log(members);
let servers = await pool.getServers();
console.log(servers);
The websocket API allows a constant connection to our websocket service to receive events in real time without polling (e.g. trying to get the server status every few seconds).
You can simply connect to the websocket API for a server by running the subscribe()
function.
server.subscribe();
By default, you are always subscribed to server status update events, you can react to server status changes by adding a listener:
server.subscribe();
server.on("status", function(server) {
console.log(server.status);
});
This event is not only triggered when the status itself changes but also when other events happen, e.g. a player joins the server.
There are several optional streams that you can subscribe to, e.g. the console.
server.subscribe("console");
The console stream emits an event for every new console line.
server.subscribe("console");
server.on("console:line", function(data) {
console.log(data.line);
});
The data.line
property is already cleaned up for easier use in this client library, you can use data.rawLine
if you want the raw
data with all formatting codes etc.
The console stream also allows you to send commands directly over the websocket. This is faster because the connection is already established and no further authorization etc. is necessary. This library already checks if you are subscribed to the console stream and sends the command through that stream instead, so you can just use it the same way as before:
try {
await server.executeCommand("say Hello world!");
} catch (e) {
console.error(e.message);
}
On Minecraft Java edition servers with version 1.16 and higher it is possible to get the tick times, and the TPS (ticks per second) of your server. This information is also available as an optional stream.
server.subscribe("tick");
server.on("tick:tick", function(data) {
console.log("Tick time: " + data.averageTickTime + "ms");
console.log("TPS: " + data.tps);
});
There are two different optional streams to get RAM usage, the general stats
stream and the Java specific heap
stream.
It is recommended to use the heap
stream if you are running a server software that is based on Java. It is not recommended using both.
You can subscribe to multiple streams at once by passing an array to the subscribe function.
server.subscribe(["stats", "heap"]);
server.on("stats:stats", function(data) {
console.log(data.memory.usage);
});
server.on("heap:heap", function(data) {
console.log(data.usage);
});
You can unsubscribe from one, multiple or all streams using the server.unsubscribe()
function.
server.unsubscribe("console");
server.unsubscribe(["tick", "heap"]);
server.unsubscribe(); // this disconnects the websocket connection