From 67763071598637ff9faf28cfae5369a693b91985 Mon Sep 17 00:00:00 2001 From: Gregory Ballantine Date: Fri, 7 Oct 2022 16:43:04 -0400 Subject: [PATCH] Added ability to start a server --- app/MinecraftServer.js | 42 +++++++++++++++++++++++++++++++++--------- index.js | 4 +++- package-lock.json | 36 ++++++++++++++++++++++++++++++++++++ package.json | 1 + routes/server.js | 27 ++++++++++++++++++++++++++- views/index.pug | 2 +- 6 files changed, 100 insertions(+), 12 deletions(-) diff --git a/app/MinecraftServer.js b/app/MinecraftServer.js index 40e0a56..00a2704 100644 --- a/app/MinecraftServer.js +++ b/app/MinecraftServer.js @@ -1,3 +1,4 @@ +const { exec } = require("child_process"); const fs = require('fs'); class Server { @@ -11,21 +12,44 @@ class Server { if (fs.existsSync(versionFilePath)) { this.version = fs.readFileSync(versionFilePath, {encoding:'utf8', flag:'r'}); } - - // set server state - if (fs.existsSync(this.pidFilePath)) { - this.state = true; - } else { - this.state = false; - } } start() { - console.log('Starting server...'); + console.log(`Starting server ${this.name}...`); + + // create shell command and execute it + let cmd = `${this.rootDir}/start.sh`; + exec(cmd, (err, stdout, stderr) => { + if (err) { + console.log(`Error while starting server: ${error.message}`); + } + + console.log(`Server ${this.name} has been started.`); + }); } stop() { - console.log('Stopping server...'); + console.log(`Stopping server ${this.name}...`); + } + + getStatus() { + if (fs.existsSync(this.pidFilePath)) { + let pid = fs.readFileSync(this.pidFilePath, {encoding: 'utf8', flag: 'r'}); + try { + return process.kill(pid, 0); + } catch (err) { + // ESRCH error means the process doesn't exist, so should return false + if (err.code !== 'ESRCH') { + console.error(err); + return err.code === 'EPERM'; + } else { + // delete pid.txt so we don't have to worry about checking it again + fs.unlinkSync(this.pidFilePath); + } + } + } + + return false } getPid() { diff --git a/index.js b/index.js index 474a81b..feebcda 100644 --- a/index.js +++ b/index.js @@ -18,11 +18,13 @@ var serverRoutes = require('./routes/server'); app.get('/', homeRoutes.getIndex); app.get('/server/create', serverRoutes.getCreate); app.post('/server/create', serverRoutes.postCreate); +app.get('/server/:serverName/start', serverRoutes.getStart); +app.get('/server/:serverName/stop', serverRoutes.getStop); // set Express to serve static files (ideally this is only used in development) app.use(express.static('./static/')); // start Express.js app app.listen(port, () => { - console.log(`Example app listening on port ${port}`); + console.log(`MCST has started and is listening on port ${port}.`); }); diff --git a/package-lock.json b/package-lock.json index 3c4cd09..3695b25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "BSD-2-Clause", "dependencies": { + "config": "^3.3.8", "express": "^4.18.1", "pug": "^3.0.2" } @@ -153,6 +154,17 @@ "is-regex": "^1.0.3" } }, + "node_modules/config": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.8.tgz", + "integrity": "sha512-rFzF6VESOdp7wAXFlB9IOZI4ouL05g3A03v2eRcTHj2JBQaTNJ40zhAUl5wRbWHqLZ+uqp/7OE0BWWtAVgrong==", + "dependencies": { + "json5": "^2.2.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/constantinople": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", @@ -462,6 +474,17 @@ "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", @@ -1051,6 +1074,14 @@ "is-regex": "^1.0.3" } }, + "config": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.8.tgz", + "integrity": "sha512-rFzF6VESOdp7wAXFlB9IOZI4ouL05g3A03v2eRcTHj2JBQaTNJ40zhAUl5wRbWHqLZ+uqp/7OE0BWWtAVgrong==", + "requires": { + "json5": "^2.2.1" + } + }, "constantinople": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", @@ -1290,6 +1321,11 @@ "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, "jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", diff --git a/package.json b/package.json index 02b68c7..320c264 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "author": "Gregory Ballantine ", "license": "BSD-2-Clause", "dependencies": { + "config": "^3.3.8", "express": "^4.18.1", "pug": "^3.0.2" } diff --git a/routes/server.js b/routes/server.js index 7eae740..fc16bf4 100644 --- a/routes/server.js +++ b/routes/server.js @@ -2,6 +2,7 @@ const config = require('config'); const fs = require('fs'); const https = require('https'); const path = require('path'); +const minecraft = require('../app/MinecraftServer'); exports.getCreate = function(req, res) { // render view @@ -30,7 +31,7 @@ exports.postCreate = function(req, res) { // create the start.sh shell script scriptFilePath = path.join(serverDir, 'start.sh'); - scriptContent = "#!/bin/sh\n\ncd " + serverDir + "\njava -Xmx2048M -Xms2048M -jar server_" + req.body.serverVersion + ".jar nogui"; + scriptContent = "#!/bin/sh\n\ncd " + serverDir + "\njava -Xmx2048M -Xms2048M -jar server_" + req.body.serverVersion + ".jar nogui &\n\necho \"$!\" > ./pid.txt"; fs.writeFileSync(scriptFilePath, scriptContent); fs.chmodSync(scriptFilePath, 0o755); @@ -43,3 +44,27 @@ exports.postCreate = function(req, res) { // redirect the user back to the home page res.redirect('/'); }; + +exports.getStart = function(req, res) { + let serverName = req.params.serverName; + let rootDir = config.get('server_directory'); + let server = new minecraft.Server(path.join(rootDir, serverName)); + + // start the server + server.start(); + + // redirect the user back to the home page + res.redirect('/'); +}; + +exports.getStop = function(req, res) { + let serverName = req.params.serverName; + let rootDir = config.get('server_directory'); + let server = new minecraft.Server(path.join(rootDir, serverName)); + + // stop the server + server.stop(); + + // redirect the user back to the home page + res.redirect('/'); +}; diff --git a/views/index.pug b/views/index.pug index 124ccfc..16f6ba4 100644 --- a/views/index.pug +++ b/views/index.pug @@ -24,7 +24,7 @@ block content tr.serverItem td.serverName= m.name td.serverVersion= m.version - td.serverState= m.state + td.serverState= m.getStatus() td a(href='/server/' + m.name + '/start') Start a(href='/server/' + m.name + '/stop') Stop