smac
Version:
Scriptcraft SMA Server controller
369 lines (368 loc) • 14.3 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = __importDefault(require("chalk"));
const fs = __importStar(require("fs-extra"));
const ghetto_monad_1 = require("ghetto-monad");
const path = __importStar(require("path"));
const docker = __importStar(require("./docker"));
const docker_1 = require("./docker");
const paths_1 = require("./paths");
const worlds_1 = require("./worlds");
class Server {
constructor() {
this.binder = new docker_1.Binder();
}
getServerTargetFromPackageJson() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing) {
return new ghetto_monad_1.Nothing();
}
else {
return new ghetto_monad_1.Result(conf.value.serverName);
}
});
}
getNodeModulesBinding() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing) {
return new ghetto_monad_1.Nothing();
}
else {
console.log(`Bind node_modules: ${conf.value.node_modules}`);
return new ghetto_monad_1.Result(conf.value.node_modules);
}
});
}
getTestMode() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing) {
return false;
}
else {
const testMode = conf.value.testMode === true;
return testMode;
}
});
}
getName() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing) {
return undefined;
}
else {
return conf.value.serverName;
}
});
}
// @TODO Bind node_modules directly
createNodeModuleBindings() {
const modules = fs.readdirSync('node_modules');
if (!modules) {
console.log(chalk_1.default.yellow('WARNING: node_modules directory not found, and it was specified in the bindings. Do you need to run ') +
chalk_1.default.magenta('npm i') +
chalk_1.default.yellow('?'));
console.log('Skipping node_modules binding');
return '';
}
return this.binder.makeMount(paths_1.localPath(`node_modules`), `scriptcraft-plugins/node_modules`);
// const nsPackage = m => {
// const isNamespacedPackage = m && m.indexOf('@') === 0
// if (isNamespacedPackage) {
// const pkgs = fs.readdirSync(`node_modules/${m}`)
// return pkgs
// .map(p =>
// this.binder.makeMount(
// localPath(`node_modules/${m}/${p}`),
// `scriptcraft-plugins/${m}/${p}`
// )
// )
// .join(' ')
// }
// return this.binder.makeMount(
// localPath(`node_modules/${m}`),
// `scriptcraft-plugins/${m}`
// )
// }
// if (modules.length > 0) {
// return modules.map(nsPackage).join(' ')
// }
// return ''
}
getBindings(name) {
return __awaiter(this, void 0, void 0, function* () {
const worlds = yield this.getWorldMounts();
const bindings = (yield this.getCustomBindings())
.map(({ src, dst }) => this.binder.makeMount(paths_1.localPath(src), dst))
.join(' ');
const mountNodeModules = yield this.getNodeModulesBinding();
const nodeModules = !mountNodeModules.isNothing && mountNodeModules.value
? this.createNodeModuleBindings()
: ``;
console.log('Found bindings in config:');
console.log(bindings);
return `${worlds} ${bindings} ${nodeModules}`;
});
}
getWorldMounts() {
return __awaiter(this, void 0, void 0, function* () {
// Check for worlds in the local worlds folder
const localMounts = this.getLocalWorldMounts();
// Parse worldDefinitions and make mounts
const smaMounts = yield this.getSmaWorldMounts();
// Make them unique - prefer local
const allMounts = {};
localMounts.map(({ src, dst }) => {
allMounts[dst] = { src, dst };
});
for (const smaMount of smaMounts) {
// Do we need to scan these dirs?
console.log(`Found: ${smaMount.src}`);
const existingMount = allMounts[smaMount.dst];
if (existingMount) {
if (smaMount.src !== existingMount.src) {
console.log(chalk_1.default.redBright(`Duplicate worlds found at ${smaMount.src} and ${existingMount.src}`));
console.log(chalk_1.default.yellowBright(`Using world from ${existingMount.src}`));
}
}
else {
allMounts[smaMount.dst] = smaMount;
}
}
if (Object.keys(allMounts).length > 0) {
console.log(`Loading the following worlds:`);
}
return Object.keys(allMounts)
.map(m => {
console.log(allMounts[m]);
const r = this.binder.makeMount(allMounts[m].src, allMounts[m].dst);
return r;
})
.join(' ');
});
}
getLocalWorldMounts() {
const mountData = (name, path) => ({
src: `${path}/${name}`,
dst: `worlds/${name}`,
});
const localPath = paths_1.localWorldsPath();
console.log('Scanning local directory:', localPath);
if (fs.existsSync(localPath)) {
const dirs = fs.readdirSync(localPath);
return dirs.map(name => {
console.log('Found:', path.join(localPath, name));
const m = mountData(name, localPath);
return m;
});
}
return [];
}
getSmaWorldMounts() {
return __awaiter(this, void 0, void 0, function* () {
const mountData = (name, path) => ({
src: `${path}/${name}`,
dst: `worlds/${name}`,
});
console.log(`Checking world definitions in ${this.filename}`);
const worldDefs = yield this.getWorldDefinitions();
if (worldDefs.isNothing) {
console.log('None found.');
return [];
}
const worlds = worldDefs.value.map(d => new worlds_1.World(d));
let smaMounts = [];
for (const world of worlds) {
const path = yield world.getPath();
if (!path.isNothing && !path.isError) {
if (fs.existsSync(path.value)) {
const dirs = fs.readdirSync(path.value);
dirs.map(name => {
smaMounts = [...smaMounts, mountData(name, path.value)];
});
return smaMounts;
}
}
}
if (smaMounts.length != worlds.length) {
console.log(chalk_1.default.red('WARNING: Some worlds specified in the Worlds definition are not available.'));
}
return smaMounts;
});
}
getDockerTag() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.dockerTag) {
return Server.defaultDockerTag;
}
else {
return conf.value.dockerTag;
}
});
}
getServerType() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.serverType) {
return Server.defaultServerType;
}
else {
return conf.value.serverType;
}
});
}
getDockerImage() {
return __awaiter(this, void 0, void 0, function* () {
const serverType = yield this.getServerType();
if (serverType === 'bukkit') {
return docker.images.bukkit;
}
if (serverType === 'nukkit') {
return docker.images.nukkit;
}
return docker.images.bukkit;
});
}
getContainerPort() {
return __awaiter(this, void 0, void 0, function* () {
const serverType = yield this.getServerType();
return Server.defaultPort[serverType];
});
}
getExposedPort() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.port) {
return this.getContainerPort();
}
else {
return conf.value.port;
}
});
}
getMemoryConfig() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.memory) {
return Server.defaultMemory;
}
else {
return conf.value.memory;
}
});
}
getRestConfig() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
const defaultConfig = {
port: Server.restPort,
password: Server.restPassword,
};
if (conf.isNothing || !conf.value.restEndpoint) {
return defaultConfig;
}
else {
return Object.assign({}, defaultConfig, conf.value.restEndpoint);
}
});
}
getEnvironment() {
return __awaiter(this, void 0, void 0, function* () {
const memory = yield this.getMemoryConfig();
const restConfig = yield this.getRestConfig();
const env = [];
env.push(`-e SERVERMEM=${memory}`);
env.push(`-e MINECRAFT_REST_CONSOLE_PORT=${restConfig.port}`);
env.push(`-e MINECRAFT_REST_CONSOLE_API_KEY=${restConfig.password}`);
return env.join(' ');
});
}
getCustomBindings() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.bind) {
return [];
}
else {
return conf.value.bind;
}
});
}
checkForConfigFile(filename) {
const cwd = process.cwd();
const pkgPath = path.join(cwd, filename);
if (!fs.existsSync(pkgPath)) {
return undefined;
}
else {
return pkgPath;
}
}
getServerConfig() {
return __awaiter(this, void 0, void 0, function* () {
if (this.serverConfig) {
return this.serverConfig;
}
const pkgPath = this.filename
? this.checkForConfigFile(this.filename)
: this.checkForConfigFile('smac.json') ||
this.checkForConfigFile('package.json');
if (!pkgPath) {
this.serverConfig = Promise.resolve(new ghetto_monad_1.Nothing());
return new ghetto_monad_1.Nothing();
}
const md = yield Promise.resolve().then(() => __importStar(require(pkgPath)));
if (!md.smaServerConfig) {
this.serverConfig = Promise.resolve(new ghetto_monad_1.Nothing());
return new ghetto_monad_1.Nothing();
}
console.log(`Loading settings from ${pkgPath}`);
this.serverConfig = Promise.resolve(new ghetto_monad_1.Result(md.smaServerConfig));
return new ghetto_monad_1.Result(md.smaServerConfig);
});
}
getWorldDefinitions() {
return __awaiter(this, void 0, void 0, function* () {
const conf = yield this.getServerConfig();
if (conf.isNothing || !conf.value.worlds) {
return new ghetto_monad_1.Nothing();
}
else {
return new ghetto_monad_1.Result(conf.value.worlds);
}
});
}
}
Server.defaultServerType = 'bukkit';
Server.defaultPort = {
bukkit: '25565',
nukkit: '19132',
};
Server.defaultDockerTag = 'latest';
Server.defaultMemory = 2048;
Server.restPort = 8086;
Server.restPassword = 'INSECURE';
Server.defaultDockerImage = 'magikcraft/scriptcraft';
exports.server = new Server();