@ -0,0 +1,10 @@ | |||
node_modules/ | |||
world/ | |||
minecraft_server.jar | |||
users.json | |||
server.properties | |||
whitelist.json | |||
ops.json | |||
banned-ips.json | |||
banned-players.json | |||
logs/ |
@ -1,2 +1,10 @@ | |||
node_modules/ | |||
world/ | |||
minecraft_server.jar | |||
users.json | |||
server.properties | |||
whitelist.json | |||
ops.json | |||
banned-ips.json | |||
banned-players.json | |||
logs/ |
@ -0,0 +1,66 @@ | |||
'use strict'; | |||
var path = require('path'), | |||
byline = require('byline'); | |||
module.exports = exports = { | |||
status: status, | |||
start: start, | |||
stop: stop, | |||
command: command, | |||
addLogListener: addLogListener | |||
}; | |||
var minecraft = null; | |||
var logLineStream = null; | |||
var logListeners = []; | |||
function status() { | |||
return { running: !!minecraft }; | |||
} | |||
function start() { | |||
console.log('start minecraft server'); | |||
var opts = { cwd: path.join(__dirname, '..') }; | |||
if (process.env.CLOUDRON) opts.cwd = '/app/data'; | |||
minecraft = require('child_process').spawn('java', ['-Xmx1024M', '-Xms1024M', '-jar', path.join(__dirname, '../minecraft_server.jar'), 'nogui'], opts); | |||
logLineStream = byline(minecraft.stdout); | |||
logLineStream.on('data', function (line) { | |||
console.log(line.toString()); // also log to stdout | |||
logListeners.forEach(function (l) { | |||
l.emit('line', line.toString().split('[Server thread/INFO]:')[1]); | |||
}); | |||
}); | |||
minecraft.stderr.pipe(process.stderr); | |||
// minecraft.stdout.pipe(process.stdout); | |||
// process.stdin.pipe(minecraft.stdin); | |||
minecraft.on('close', function () { | |||
minecraft = null; | |||
}); | |||
} | |||
function stop(callback) { | |||
console.log('stop minecraft server'); | |||
if (!minecraft) return callback(); | |||
minecraft.kill(); | |||
minecraft.on('close', function () { | |||
minecraft = null; | |||
callback(); | |||
}); | |||
} | |||
function command(cmd, callback) { | |||
if (!minecraft) return; | |||
minecraft.stdin.write(cmd + '\n', callback); | |||
} | |||
function addLogListener(socket) { | |||
logListeners.push(socket); | |||
} |
@ -0,0 +1,156 @@ | |||
'use strict'; | |||
var assert = require('assert'), | |||
fs = require('fs'), | |||
path = require('path'), | |||
ldapjs = require('ldapjs'), | |||
basicAuth = require('basic-auth'), | |||
minecraft = require('./minecraft.js'), | |||
lastMile = require('connect-lastmile'), | |||
HttpError = lastMile.HttpError, | |||
HttpSuccess = lastMile.HttpSuccess; | |||
module.exports = exports = { | |||
healthcheck: healthcheck, | |||
status: status, | |||
auth: auth, | |||
profile: profile, | |||
settings: { | |||
get: settingsGet, | |||
set: settingsSet | |||
}, | |||
start: start, | |||
stop: stop, | |||
command: command | |||
}; | |||
const LDAP_URL = process.env.LDAP_URL; | |||
const LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN; | |||
const LOCAL_AUTH_FILE = path.resolve('users.json'); | |||
const baseDir = process.env.CLOUDRON ? '/app/data' : path.join(__dirname, '..') | |||
const configFilePath = path.join(baseDir, 'server.properties'); | |||
var users = {}; | |||
var AUTH_METHOD = (LDAP_URL && LDAP_USERS_BASE_DN) ? 'ldap' : 'local'; | |||
if (AUTH_METHOD === 'ldap') { | |||
console.log('Use ldap auth'); | |||
} else { | |||
console.log(`Use local auth file ${LOCAL_AUTH_FILE}`); | |||
try { | |||
users = JSON.parse(fs.readFileSync(LOCAL_AUTH_FILE, 'utf8')); | |||
} catch (e) { | |||
let template = [{ username: 'username', email: 'test@example.com', password: 'password' }]; | |||
console.log(`Unable to read local auth file. Create a JSON file at ${LOCAL_AUTH_FILE} with\n%s`, JSON.stringify(template, null, 4)); | |||
process.exit(1); | |||
} | |||
} | |||
function healthcheck(req, res, next) { | |||
next(new HttpSuccess(200, {})); | |||
} | |||
function status(req, res, next) { | |||
next(new HttpSuccess(200, { status: minecraft.status() })); | |||
} | |||
function auth(req, res, next) { | |||
var credentials = basicAuth(req); | |||
if (!credentials) return next(new HttpError(400, 'Basic auth required')); | |||
function attachUser(user) { | |||
req.user = user; | |||
return next(); | |||
} | |||
if (AUTH_METHOD === 'ldap') { | |||
var ldapClient = ldapjs.createClient({ url: process.env.LDAP_URL }); | |||
ldapClient.on('error', function (error) { | |||
console.error('LDAP error', error); | |||
}); | |||
ldapClient.bind(process.env.LDAP_BIND_DN, process.env.LDAP_BIND_PASSWORD, function (error) { | |||
if (error) return next(new HttpError(500, error)); | |||
var filter = `(|(uid=${credentials.name})(mail=${credentials.name})(username=${credentials.name})(sAMAccountName=${credentials.name}))`; | |||
ldapClient.search(process.env.LDAP_USERS_BASE_DN, { filter: filter }, function (error, result) { | |||
if (error) return next(new HttpError(500, error)); | |||
var items = []; | |||
result.on('searchEntry', function(entry) { items.push(entry.object); }); | |||
result.on('error', function (error) { next(new HttpError(500, error)); }); | |||
result.on('end', function (result) { | |||
if (result.status !== 0) return next(new HttpError(500, error)); | |||
if (items.length === 0) return next(new HttpError(401, 'Invalid credentials')); | |||
// pick the first found | |||
var user = items[0]; | |||
ldapClient.bind(user.dn, credentials.pass, function (error) { | |||
if (error) return next(new HttpError(401, 'Invalid credentials')); | |||
attachUser({ username: user.username, email: user.mail }); | |||
}); | |||
}); | |||
}); | |||
}); | |||
} else { | |||
let user = users.find(function (u) { return (u.username === credentials.name || u.email === credentials.name) && u.password === credentials.pass; }); | |||
if (!user) return next(new HttpError(401, 'Invalid credentials')); | |||
attachUser(user); | |||
} | |||
} | |||
function profile(req, res, next) { | |||
assert.strictEqual(typeof req.user, 'object'); | |||
next(new HttpSuccess(200, { user: req.user })); | |||
} | |||
function settingsGet(req, res, next) { | |||
assert.strictEqual(typeof req.user, 'object'); | |||
fs.readFile(configFilePath, function (error, result) { | |||
if (error) return res.status(500).send(error); | |||
next(new HttpSuccess(200, { settings: result.toString() })); | |||
}); | |||
} | |||
function settingsSet(req, res, next) { | |||
assert.strictEqual(typeof req.user, 'object'); | |||
fs.writeFile(configFilePath, req.body.settings, function (error) { | |||
if (error) return res.status(500).send(error); | |||
next(new HttpSuccess(202, {})); | |||
}); | |||
} | |||
function start(req, res, next) { | |||
minecraft.start(); | |||
next(new HttpSuccess(202, {})); | |||
} | |||
function stop(req, res, next) { | |||
minecraft.stop(function () { | |||
next(new HttpSuccess(202, {})); | |||
}); | |||
} | |||
function command(req, res, next) { | |||
minecraft.command(req.body.cmd, function (error) { | |||
if (error) return next(new HttpError(500, 'server not running')); | |||
next(new HttpSuccess(202, {})); | |||
}); | |||
} |
@ -0,0 +1,51 @@ | |||
'use strict'; | |||
var assert = require('assert'), | |||
connectTimeout = require('connect-timeout'), | |||
lastMile = require('connect-lastmile'), | |||
routes = require('./routes.js'), | |||
minecraft = require('./minecraft.js'), | |||
express = require('express'); | |||
module.exports = exports = { | |||
start: start | |||
}; | |||
function start(port, callback) { | |||
assert.strictEqual(typeof port, 'number'); | |||
assert.strictEqual(typeof callback, 'function'); | |||
var router = express.Router(); | |||
router.del = router.delete; | |||
var app = express(); | |||
var http = require('http').Server(app); | |||
var io = require('socket.io')(http); | |||
router.get ('/api/v1/healthcheck', routes.healthcheck); | |||
router.get ('/api/v1/status', routes.auth, routes.status); | |||
router.get ('/api/v1/profile', routes.auth, routes.profile); | |||
router.post('/api/v1/start', routes.auth, routes.start); | |||
router.post('/api/v1/stop', routes.auth, routes.stop); | |||
router.post('/api/v1/command', routes.auth, routes.command); | |||
router.get ('/api/v1/settings', routes.auth, routes.settings.get); | |||
router.post('/api/v1/settings', routes.auth, routes.settings.set); | |||
// for log lines | |||
io.on('connection', function (socket) { | |||
socket.on('cmd', function (cmd) { | |||
minecraft.cmd(cmd); | |||
}); | |||
minecraft.addLogListener(socket); | |||
}); | |||
app | |||
.use(connectTimeout(10000, { respond: true })) | |||
.use(express.json()) | |||
.use(express.urlencoded({ extended: true })) | |||
.use(router) | |||
.use(express.static('./frontend')) | |||
.use(lastMile()); | |||
http.listen(port, callback); | |||
} |
@ -0,0 +1,157 @@ | |||
@font-face { | |||
font-family: 'Minecraft'; | |||
src: url('/fonts/mcfont.eot'); | |||
src: url('/fonts/mcfont.woff') format('woff'), | |||
url('/fonts/mcfont.ttf') format('truetype'), | |||
url('/fonts/mcfont.svg#svgFontName') format('svg'); | |||
} | |||
html, body { | |||
height: 100%; | |||
font-family: Minecraft; | |||
text-shadow: 3px 3px #4C4C4C; | |||
color: white; | |||
margin: 0; | |||
color: rgb(187, 189, 194); | |||
background: transparent url('/img/body-bg.png') repeat; | |||
font-size: 16px; | |||
line-height: 40px; | |||
} | |||
header { | |||
color: white; | |||
padding: 10px; | |||
} | |||
a { | |||
color: #FFFFA0 !important; | |||
text-decoration: none; | |||
} | |||
.pull-right { | |||
float: right; | |||
} | |||
header > h1 { | |||
margin: 0; | |||
text-align: center; | |||
vertical-align: middle; | |||
font-weight: normal; | |||
} | |||
footer { | |||
width: 100%; | |||
text-align: center; | |||
} | |||
.container { | |||
width: 100%; | |||
max-width: 800px; | |||
margin: auto; | |||
} | |||
.inactive { | |||
color: red; | |||
} | |||
.active { | |||
color: greenyellow; | |||
} | |||
button { | |||
height: 40px; | |||
min-width: 200px; | |||
outline: 2px solid black; | |||
position: relative; | |||
margin: 0; | |||
display: inline-block; | |||
background-image: url('/img/button_center.png'); | |||
background-repeat: repeat; | |||
padding: 0; | |||
font-family: Minecraft; | |||
text-align: center; | |||
color: white; | |||
text-shadow: 3px 3px #4C4C4C; | |||
border-bottom: 4px solid #565656; | |||
border-right: 2px solid #565656; | |||
border-left: 2px solid #AAA; | |||
border-top: 2px solid #AAA; | |||
box-sizing: border-box; | |||
font-size: 16px; | |||
cursor: pointer; | |||
} | |||
button:hover { | |||
border-bottom: 4px solid #59639A; | |||
border-right: 2px solid #59639A; | |||
border-left: 2px solid #BDC6FF; | |||
border-top: 2px solid #BDC6FF; | |||
background-image: url('/img/button_active_center.png'); | |||
color: #FFFFA0; | |||
} | |||
input { | |||
background-color: black; | |||
border-color: #888787; | |||
border-style: solid; | |||
border-width: 2px; | |||
height: 40px; | |||
font-family: Minecraft; | |||
font-size: 16px; | |||
color: white; | |||
padding: 10px; | |||
} | |||
input:focus, textarea:focus { | |||
border-color: white; | |||
} | |||
textarea { | |||
background-color: black; | |||
border-color: #4C4C4C; | |||
border-style: solid; | |||
border-width: 2px; | |||
font-family: Minecraft; | |||
font-size: 16px; | |||
color: white; | |||
padding: 10px; | |||
width: 100%; | |||
min-height: 300px; | |||
} | |||
.logout { | |||
position: fixed; | |||
top: 10px; | |||
left: 10px; | |||
} | |||
.login input, .login button { | |||
width: 100%; | |||
} | |||
.logstream { | |||
width: 100%; | |||
height: 400px; | |||
overflow: auto; | |||
background-color: black; | |||
} | |||
.logstream > p { | |||
font-family: Minecraft; | |||
text-shadow: none; | |||
line-height: normal; | |||
font-size: 14px; | |||
color: white; | |||
margin: 0; | |||
} | |||
.command { | |||
width: 100%; | |||
font-size: 14px; | |||
} | |||
.command::before { | |||
content: '>' | |||
} |
@ -0,0 +1,251 @@ | |||
<?xml version="1.0" standalone="no"?> | |||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > | |||
<svg> | |||
<metadata> | |||
Created by FontForge 20110222 at Sun Jan 5 10:13:18 2014 | |||
By Orthosie Webhosting | |||
Copyright Pwnage_Block 2011 | |||
</metadata> | |||
<defs> | |||
<font id="Minecraft" horiz-adv-x="768" > | |||
<font-face | |||
font-family="Minecraft" | |||
font-weight="400" | |||
font-stretch="normal" | |||
units-per-em="1024" | |||
panose-1="0 0 4 0 0 0 0 0 0 0" | |||
ascent="896" | |||
descent="-128" | |||
x-height="640" | |||
cap-height="896" | |||
bbox="0 -128 1280 1152" | |||
underline-thickness="51" | |||
underline-position="126" | |||
unicode-range="U+0020-201D" | |||
/> | |||
<missing-glyph horiz-adv-x="374" | |||
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" /> | |||
<glyph glyph-name=".notdef" horiz-adv-x="374" | |||
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" /> | |||
<glyph glyph-name=".null" horiz-adv-x="0" | |||
/> | |||
<glyph glyph-name="nonmarkingreturn" horiz-adv-x="341" | |||
/> | |||
<glyph glyph-name="space" unicode=" " horiz-adv-x="256" | |||
/> | |||
<glyph glyph-name="exclam" unicode="!" horiz-adv-x="256" | |||
d="M0 0v128h128v-128h-128zM0 256v640h128v-640h-128z" /> | |||
<glyph glyph-name="quotedbl" unicode=""" horiz-adv-x="512" | |||
d="M0 640v256h128v-256h-128zM256 640v256h128v-256h-128z" /> | |||
<glyph glyph-name="numbersign" unicode="#" | |||
d="M384 384v128h-128v-128h128zM128 0v256h-128v128h128v128h-128v128h128v256h128v-256h128v256h128v-256h128v-128h-128v-128h128v-128h-128v-256h-128v256h-128v-256h-128z" /> | |||
<glyph glyph-name="dollar" unicode="$" | |||
d="M256 0v128h-256v128h512v-128h-128v-128h-128zM512 256v128h128v-128h-128zM128 384v128h384v-128h-384zM0 512v128h128v-128h-128zM128 640v128h128v128h128v-128h256v-128h-512z" /> | |||
<glyph glyph-name="percent" unicode="%" | |||
d="M0 0v128h128v-128h-128zM512 0v256h128v-256h-128zM128 128v256h128v-256h-128zM256 384v128h128v-128h-128zM384 512v256h128v-256h-128zM0 640v256h128v-256h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="ampersand" unicode="&" | |||
d="M128 0v128h256v-128h-256zM512 0v128h128v-128h-128zM0 128v256h128v-256h-128zM512 384v128h128v-128h-128zM384 128v128h-128v128h-128v128h128v128h128v-256h128v-256h-128zM128 640v128h128v-128h-128zM384 640v128h128v-128h-128zM256 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="quotesingle" unicode="'" horiz-adv-x="256" | |||
d="M0 640v256h128v-256h-128z" /> | |||
<glyph glyph-name="parenleft" unicode="(" horiz-adv-x="640" | |||
d="M256 0v128h256v-128h-256zM128 128v128h128v-128h-128zM0 256v384h128v-384h-128zM128 640v128h128v-128h-128zM256 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="parenright" unicode=")" horiz-adv-x="640" | |||
d="M0 0v128h256v-128h-256zM256 128v128h128v-128h-128zM384 256v384h128v-384h-128zM256 640v128h128v-128h-128zM0 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="asterisk" unicode="*" horiz-adv-x="640" | |||
d="M0 256v128h128v-128h-128zM384 256v128h128v-128h-128zM128 384v128h256v-128h-256zM0 512v128h128v-128h-128zM384 512v128h128v-128h-128z" /> | |||
<glyph glyph-name="plus" unicode="+" | |||
d="M256 0v256h-256v128h256v256h128v-256h256v-128h-256v-256h-128z" /> | |||
<glyph glyph-name="comma" unicode="," horiz-adv-x="256" | |||
d="M0 -128v384h128v-384h-128z" /> | |||
<glyph glyph-name="hyphen" unicode="-" | |||
d="M0 256v128h640v-128h-640z" /> | |||
<glyph glyph-name="period" unicode="." horiz-adv-x="256" | |||
d="M0 0v256h128v-256h-128z" /> | |||
<glyph glyph-name="slash" unicode="/" | |||
d="M0 0v128h128v-128h-128zM128 128v256h128v-256h-128zM256 384v128h128v-128h-128zM384 512v256h128v-256h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="zero" unicode="0" | |||
d="M128 0v128h384v-128h-384zM256 384v128h128v-128h-128zM0 128v640h128v-384h128v-128h-128v-128h-128zM512 128v384h-128v128h128v128h128v-640h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="one" unicode="1" | |||
d="M0 0v128h256v512h-128v128h128v128h128v-768h256v-128h-640z" /> | |||
<glyph glyph-name="two" unicode="2" | |||
d="M0 0v256h128v-128h512v-128h-640zM128 256v128h128v-128h-128zM256 384v128h256v-128h-256zM0 640v128h128v-128h-128zM512 512v256h128v-256h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="three" unicode="3" | |||
d="M128 0v128h384v-128h-384zM0 128v128h128v-128h-128zM512 128v256h128v-256h-128zM256 384v128h256v-128h-256zM0 640v128h128v-128h-128zM512 512v256h128v-256h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="four" unicode="4" | |||
d="M128 512v128h128v-128h-128zM256 640v128h128v-128h-128zM512 0v256h-512v256h128v-128h384v384h-128v128h256v-896h-128z" /> | |||
<glyph glyph-name="five" unicode="5" | |||
d="M128 0v128h384v-128h-384zM0 128v128h128v-128h-128zM512 128v384h128v-384h-128zM0 512v384h640v-128h-512v-128h384v-128h-512z" /> | |||
<glyph glyph-name="six" unicode="6" | |||
d="M128 0v128h384v-128h-384zM512 128v256h128v-256h-128zM0 128v512h128v-128h384v-128h-384v-256h-128zM128 640v128h128v-128h-128zM256 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="seven" unicode="7" | |||
d="M256 0v384h128v-384h-128zM384 384v128h128v-128h-128zM512 512v256h-384v-128h-128v256h640v-384h-128z" /> | |||
<glyph glyph-name="eight" unicode="8" | |||
d="M128 0v128h384v-128h-384zM0 128v256h128v-256h-128zM512 128v256h128v-256h-128zM128 384v128h384v-128h-384zM0 512v256h128v-256h-128zM512 512v256h128v-256h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="nine" unicode="9" | |||
d="M128 0v128h256v-128h-256zM384 128v128h128v-128h-128zM0 512v256h128v-256h-128zM512 256v128h-384v128h384v256h128v-512h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="colon" unicode=":" horiz-adv-x="256" | |||
d="M0 0v256h128v-256h-128zM0 512v256h128v-256h-128z" /> | |||
<glyph glyph-name="semicolon" unicode=";" horiz-adv-x="256" | |||
d="M0 -128v384h128v-384h-128zM0 512v256h128v-256h-128z" /> | |||
<glyph glyph-name="less" unicode="<" horiz-adv-x="640" | |||
d="M384 0v128h128v-128h-128zM256 128v128h128v-128h-128zM128 256v128h128v-128h-128zM0 384v128h128v-128h-128zM128 512v128h128v-128h-128zM256 640v128h128v-128h-128zM384 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="equal" unicode="=" | |||
d="M0 128v128h640v-128h-640zM0 512v128h640v-128h-640z" /> | |||
<glyph glyph-name="greater" unicode=">" horiz-adv-x="640" | |||
d="M0 0v128h128v-128h-128zM128 128v128h128v-128h-128zM256 256v128h128v-128h-128zM384 384v128h128v-128h-128zM256 512v128h128v-128h-128zM128 640v128h128v-128h-128zM0 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="question" unicode="?" | |||
d="M256 0v128h128v-128h-128zM256 256v128h128v-128h-128zM384 384v128h128v-128h-128zM0 640v128h128v-128h-128zM512 512v256h128v-256h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="at" unicode="@" horiz-adv-x="896" | |||
d="M128 0v128h640v-128h-640zM0 128v640h128v-640h-128zM256 256v384h256v-256h128v384h128v-512h-512zM128 768v128h512v-128h-512z" /> | |||
<glyph glyph-name="A" unicode="A" | |||
d="M0 0v768h128v-128h384v128h128v-768h-128v512h-384v-512h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="B" unicode="B" | |||
d="M512 128v384h128v-384h-128zM512 640v128h128v-128h-128zM0 0v896h512v-128h-384v-128h384v-128h-384v-384h384v-128h-512z" /> | |||
<glyph glyph-name="C" unicode="C" | |||
d="M128 0v128h384v-128h-384zM512 128v128h128v-128h-128zM0 128v640h128v-640h-128zM512 640v128h128v-128h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="D" unicode="D" | |||
d="M512 128v640h128v-640h-128zM0 0v896h512v-128h-384v-640h384v-128h-512z" /> | |||
<glyph glyph-name="E" unicode="E" | |||
d="M0 0v896h640v-128h-512v-128h256v-128h-256v-384h512v-128h-640z" /> | |||
<glyph glyph-name="F" unicode="F" | |||
d="M0 0v896h640v-128h-512v-128h256v-128h-256v-512h-128z" /> | |||
<glyph glyph-name="G" unicode="G" | |||
d="M128 0v128h384v-128h-384zM512 128v384h-128v128h256v-512h-128zM0 128v640h128v-640h-128zM128 768v128h512v-128h-512z" /> | |||
<glyph glyph-name="H" unicode="H" | |||
d="M0 0v896h128v-256h384v256h128v-896h-128v512h-384v-512h-128z" /> | |||
<glyph glyph-name="I" unicode="I" horiz-adv-x="512" | |||
d="M0 0v128h128v640h-128v128h384v-128h-128v-640h128v-128h-384z" /> | |||
<glyph glyph-name="J" unicode="J" | |||
d="M128 0v128h384v-128h-384zM0 128v128h128v-128h-128zM512 128v768h128v-768h-128z" /> | |||
<glyph glyph-name="K" unicode="K" | |||
d="M512 0v384h128v-384h-128zM384 384v128h128v-128h-128zM384 640v128h128v-128h-128zM0 0v896h128v-256h256v-128h-256v-512h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="L" unicode="L" | |||
d="M0 0v896h128v-768h512v-128h-640z" /> | |||
<glyph glyph-name="M" unicode="M" | |||
d="M256 512v128h128v-128h-128zM0 0v896h128v-128h128v-128h-128v-640h-128zM512 0v640h-128v128h128v128h128v-896h-128z" /> | |||
<glyph glyph-name="N" unicode="N" | |||
d="M256 512v128h128v-128h-128zM0 0v896h128v-128h128v-128h-128v-640h-128zM512 0v384h-128v128h128v384h128v-896h-128z" /> | |||
<glyph glyph-name="O" unicode="O" | |||
d="M128 0v128h384v-128h-384zM0 128v640h128v-640h-128zM512 128v640h128v-640h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="P" unicode="P" | |||
d="M512 640v128h128v-128h-128zM0 0v896h512v-128h-384v-128h384v-128h-384v-512h-128z" /> | |||
<glyph glyph-name="Q" unicode="Q" | |||
d="M128 0v128h256v-128h-256zM512 0v128h128v-128h-128zM384 128v128h128v-128h-128zM0 128v640h128v-640h-128zM512 256v512h128v-512h-128zM128 768v128h384v-128h-384z" /> | |||
<glyph glyph-name="R" unicode="R" | |||
d="M512 0v512h128v-512h-128zM512 640v128h128v-128h-128zM0 0v896h512v-128h-384v-128h384v-128h-384v-512h-128z" /> | |||
<glyph glyph-name="S" unicode="S" | |||
d="M128 0v128h384v-128h-384zM0 128v128h128v-128h-128zM512 128v384h128v-384h-128zM128 512v128h384v-128h-384zM0 640v128h128v-128h-128zM128 768v128h512v-128h-512z" /> | |||
<glyph glyph-name="T" unicode="T" | |||
d="M256 0v768h-256v128h640v-128h-256v-768h-128z" /> | |||
<glyph glyph-name="U" unicode="U" | |||
d="M128 0v128h384v-128h-384zM0 128v768h128v-768h-128zM512 128v768h128v-768h-128z" /> | |||
<glyph glyph-name="V" unicode="V" | |||
d="M256 0v128h128v-128h-128zM128 128v256h128v-256h-128zM384 128v256h128v-256h-128zM0 384v512h128v-512h-128zM512 384v512h128v-512h-128z" /> | |||
<glyph glyph-name="W" unicode="W" | |||
d="M256 256v128h128v-128h-128zM0 0v896h128v-640h128v-128h-128v-128h-128zM512 0v128h-128v128h128v640h128v-896h-128z" /> | |||
<glyph glyph-name="X" unicode="X" | |||
d="M0 0v384h128v-384h-128zM512 0v384h128v-384h-128zM128 384v128h128v-128h-128zM384 384v128h128v-128h-128zM256 512v128h128v-128h-128zM128 640v128h128v-128h-128zM384 640v128h128v-128h-128zM0 768v128h128v-128h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="Y" unicode="Y" | |||
d="M256 0v640h128v-640h-128zM128 640v128h128v-128h-128zM384 640v128h128v-128h-128zM0 768v128h128v-128h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="Z" unicode="Z" | |||
d="M0 0v256h128v-128h512v-128h-640zM128 256v128h128v-128h-128zM256 384v128h128v-128h-128zM384 512v128h128v-128h-128zM512 640v128h-512v128h640v-256h-128z" /> | |||
<glyph glyph-name="bracketleft" unicode="[" horiz-adv-x="512" | |||
d="M0 0v896h384v-128h-256v-640h256v-128h-384z" /> | |||
<glyph glyph-name="backslash" unicode="\" | |||
d="M512 0v128h128v-128h-128zM384 128v256h128v-256h-128zM256 384v128h128v-128h-128zM128 512v256h128v-256h-128zM0 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="bracketright" unicode="]" horiz-adv-x="512" | |||
d="M0 0v128h256v640h-256v128h384v-896h-384z" /> | |||
<glyph glyph-name="asciicircum" unicode="^" | |||
d="M0 512v128h128v-128h-128zM512 512v128h128v-128h-128zM128 640v128h128v-128h-128zM384 640v128h128v-128h-128zM256 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="underscore" unicode="_" | |||
d="M0 -128v128h640v-128h-640z" /> | |||
<glyph glyph-name="grave" unicode="`" horiz-adv-x="384" | |||
d="M0 640v128h128v-128h-128zM128 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="a" unicode="a" | |||
d="M0 128v128h128v-128h-128zM128 0v128h384v128h-384v128h384v128h128v-512h-512zM128 512v128h384v-128h-384z" /> | |||
<glyph glyph-name="b" unicode="b" | |||
d="M512 128v384h128v-384h-128zM256 512v128h256v-128h-256zM0 0v896h128v-384h128v-128h-128v-256h384v-128h-512z" /> | |||
<glyph glyph-name="c" unicode="c" | |||
d="M128 0v128h384v-128h-384zM512 128v128h128v-128h-128zM0 128v384h128v-384h-128zM512 384v128h128v-128h-128zM128 512v128h384v-128h-384z" /> | |||
<glyph glyph-name="d" unicode="d" | |||
d="M0 128v384h128v-384h-128zM128 512v128h256v-128h-256zM128 0v128h384v256h-128v128h128v384h128v-896h-512z" /> | |||
<glyph glyph-name="e" unicode="e" | |||
d="M128 0v128h512v-128h-512zM0 128v384h128v-128h384v128h128v-256h-512v-128h-128zM128 512v128h384v-128h-384z" /> | |||
<glyph glyph-name="f" unicode="f" horiz-adv-x="640" | |||
d="M128 0v512h-128v128h128v128h128v-128h256v-128h-256v-512h-128zM256 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="g" unicode="g" | |||
d="M0 -128v128h512v-128h-512zM0 256v256h128v-256h-128zM512 0v128h-384v128h384v256h-384v128h512v-640h-128z" /> | |||
<glyph glyph-name="h" unicode="h" | |||
d="M512 0v512h128v-512h-128zM256 512v128h256v-128h-256zM0 0v896h128v-384h128v-128h-128v-384h-128z" /> | |||
<glyph glyph-name="i" unicode="i" horiz-adv-x="256" | |||
d="M0 0v640h128v-640h-128zM0 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="j" unicode="j" | |||
d="M128 -128v128h384v-128h-384zM0 0v256h128v-256h-128zM512 0v640h128v-640h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="k" unicode="k" horiz-adv-x="640" | |||
d="M384 0v128h128v-128h-128zM256 128v128h128v-128h-128zM256 384v128h128v-128h-128zM384 512v128h128v-128h-128zM0 0v896h128v-512h128v-128h-128v-256h-128z" /> | |||
<glyph glyph-name="l" unicode="l" horiz-adv-x="384" | |||
d="M128 0v128h128v-128h-128zM0 128v768h128v-768h-128z" /> | |||
<glyph glyph-name="m" unicode="m" | |||
d="M256 256v256h128v-256h-128zM512 0v512h128v-512h-128zM0 0v640h256v-128h-128v-512h-128zM384 512v128h128v-128h-128z" /> | |||
<glyph glyph-name="n" unicode="n" | |||
d="M512 0v512h128v-512h-128zM0 0v640h512v-128h-384v-512h-128z" /> | |||
<glyph glyph-name="o" unicode="o" | |||
d="M128 0v128h384v-128h-384zM0 128v384h128v-384h-128zM512 128v384h128v-384h-128zM128 512v128h384v-128h-384z" /> | |||
<glyph glyph-name="p" unicode="p" | |||
d="M512 256v256h128v-256h-128zM0 -128v768h128v-128h128v-128h-128v-128h384v-128h-384v-256h-128zM256 512v128h256v-128h-256z" /> | |||
<glyph glyph-name="q" unicode="q" | |||
d="M0 256v256h128v-256h-128zM128 512v128h256v-128h-256zM512 -128v256h-384v128h384v128h-128v128h128v128h128v-768h-128z" /> | |||
<glyph glyph-name="r" unicode="r" | |||
d="M512 384v128h128v-128h-128zM0 0v640h128v-128h128v-128h-128v-384h-128zM256 512v128h256v-128h-256z" /> | |||
<glyph glyph-name="s" unicode="s" | |||
d="M0 0v128h512v-128h-512zM512 128v128h128v-128h-128zM128 256v128h384v-128h-384zM0 384v128h128v-128h-128zM128 512v128h512v-128h-512z" /> | |||
<glyph glyph-name="t" unicode="t" horiz-adv-x="512" | |||
d="M256 0v128h128v-128h-128zM128 128v512h-128v128h128v128h128v-128h128v-128h-128v-512h-128z" /> | |||
<glyph glyph-name="u" unicode="u" | |||
d="M0 128v512h128v-512h-128zM128 0v128h384v512h128v-640h-512z" /> | |||
<glyph glyph-name="v" unicode="v" | |||
d="M256 0v128h128v-128h-128zM128 128v128h128v-128h-128zM384 128v128h128v-128h-128zM0 256v384h128v-384h-128zM512 256v384h128v-384h-128z" /> | |||
<glyph glyph-name="w" unicode="w" | |||
d="M0 128v512h128v-512h-128zM128 0v128h128v256h128v-256h128v512h128v-640h-512z" /> | |||
<glyph glyph-name="x" unicode="x" | |||
d="M0 0v128h128v-128h-128zM512 0v128h128v-128h-128zM128 128v128h128v-128h-128zM384 128v128h128v-128h-128zM256 256v128h128v-128h-128zM128 384v128h128v-128h-128zM384 384v128h128v-128h-128zM0 512v128h128v-128h-128zM512 512v128h128v-128h-128z" /> | |||
<glyph glyph-name="y" unicode="y" | |||
d="M0 -128v128h512v-128h-512zM0 256v384h128v-384h-128zM512 0v128h-384v128h384v384h128v-640h-128z" /> | |||
<glyph glyph-name="z" unicode="z" | |||
d="M0 0v128h128v128h128v-128h384v-128h-640zM256 256v128h128v-128h-128zM384 384v128h-384v128h640v-128h-128v-128h-128z" /> | |||
<glyph glyph-name="braceleft" unicode="{" horiz-adv-x="640" | |||
d="M256 0v128h256v-128h-256zM128 128v256h128v-256h-128zM0 384v128h128v-128h-128zM128 512v256h128v-256h-128zM256 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="bar" unicode="|" horiz-adv-x="256" | |||
d="M0 0v384h128v-384h-128zM0 512v384h128v-384h-128z" /> | |||
<glyph glyph-name="braceright" unicode="}" horiz-adv-x="640" | |||
d="M0 0v128h256v-128h-256zM256 128v256h128v-256h-128zM384 384v128h128v-128h-128zM256 512v256h128v-256h-128zM0 768v128h256v-128h-256z" /> | |||
<glyph glyph-name="asciitilde" unicode="~" horiz-adv-x="896" | |||
d="M0 640v128h128v-128h-128zM384 640v128h256v-128h-256zM128 768v128h256v-128h-256zM640 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="quoteleft" unicode="‘" horiz-adv-x="384" | |||
d="M0 512v256h128v-256h-128zM128 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="quoteright" unicode="’" horiz-adv-x="384" | |||
d="M0 512v128h128v-128h-128zM128 640v256h128v-256h-128z" /> | |||
<glyph glyph-name="quotedblleft" unicode="“" horiz-adv-x="640" | |||
d="M0 512v256h128v-256h-128zM256 512v256h128v-256h-128zM128 768v128h128v-128h-128zM384 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="quotedblright" unicode="”" horiz-adv-x="640" | |||
d="M0 512v128h128v-128h-128zM256 512v128h128v-128h-128zM128 640v256h128v-256h-128zM384 640v256h128v-256h-128z" /> | |||
<glyph glyph-name="exclamdown" unicode="¡" horiz-adv-x="256" | |||
d="M0 0v640h128v-640h-128zM0 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="yen" unicode="¥" | |||
d="M256 0v128h-128v128h128v128h-128v128h128v128h128v-128h128v-128h-128v-128h128v-128h-128v-128h-128zM128 640v128h128v-128h-128zM384 640v128h128v-128h-128zM0 768v128h128v-128h-128zM512 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="dieresis" unicode="¨" horiz-adv-x="640" | |||
d="M128 768v128h128v-128h-128zM384 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="questiondown" unicode="¿" | |||
d="M128 0v128h384v-128h-384zM512 128v128h128v-128h-128zM0 128v256h128v-256h-128zM128 384v128h128v-128h-128zM256 512v128h128v-128h-128zM256 768v128h128v-128h-128z" /> | |||
<glyph glyph-name="Oslash" unicode="Ø" horiz-adv-x="896" | |||
d="M0 0v128h128v-128h-128zM256 0v128h256v-128h-256zM128 128v128h128v-128h-128zM512 128v128h128v-128h-128zM256 256v128h128v-128h-128zM0 256v256h128v-256h-128zM384 384v128h128v-128h-128zM640 256v256h128v-256h-128zM128 512v128h128v-128h-128zM512 512v128h128 | |||
v-128h-128zM256 640v128h256v-128h-256zM640 640v128h128v-128h-128z" /> | |||
<glyph glyph-name="aring" unicode="å" | |||
d="M128 0v128h256v-128h-256zM0 128v384h128v-384h-128zM512 0v128h-128v128h128v256h-384v128h512v-640h-128zM256 768v128h128v-128h-128zM128 896v128h128v-128h-128zM384 896v128h128v-128h-128zM256 1024v128h128v-128h-128z" /> | |||
<glyph glyph-name="ae" unicode="æ" horiz-adv-x="1408" | |||
d="M128 0v128h256v-128h-256zM768 0v128h512v-128h-512zM0 128v384h128v-384h-128zM1152 384v128h128v-128h-128zM512 0v128h-128v128h128v256h-384v128h512v-128h128v-128h384v-128h-384v-128h-128v-128h-128zM768 512v128h384v-128h-384z" /> | |||
<glyph glyph-name="oslash" unicode="ø" horiz-adv-x="896" | |||
d="M0 0v128h128v-128h-128zM256 0v128h256v-128h-256zM128 128v128h128v-128h-128zM512 128v128h128v-128h-128zM256 256v128h128v-128h-128zM0 256v256h128v-256h-128zM384 384v128h128v-128h-128zM640 256v256h128v-256h-128zM128 512v128h128v-128h-128zM512 512v128h128 | |||
v-128h-128zM256 640v128h256v-128h-256zM640 640v128h128v-128h-128z" /> | |||
</font> | |||
</defs></svg> |
@ -0,0 +1,52 @@ | |||
<html> | |||
<head> | |||
<title> Minecraft Server </title> | |||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | |||
<link rel="icon" type="image/png" href="/favicon.png"> | |||
<link rel="stylesheet" href="/css/index.css"> | |||
<script src="/js/vue.js"></script> | |||
<script src="/js/superagent.js"></script> | |||
<script src="/socket.io/socket.io.js"></script> | |||
</head> | |||
<body> | |||
<div id="app"> | |||
<header> | |||
<h1>Minecraft Server</h1> | |||
</header> | |||
<div v-if="profile" class="container"> | |||
<p> | |||
Server Status: <span style="padding-left: 20px;" :class="{ active: status.running, inactive: !status.running }">{{ status.running ? 'Running' : 'Stopped' }}</span> | |||
<button v-show="!status.running" class="pull-right" @click="start()">Start</button> | |||
<button v-show="status.running" class="pull-right" @click="stop()">Stop</button> | |||
</p> | |||
<!-- <p>Settings:</p> | |||
<textarea v-model="settings"></textarea> | |||
<button>Save</button> --> | |||
<div class="logstream"> | |||
<p v-for="line in logstream">{{ line }}</p> | |||
</div> | |||
<input type="text" v-model="cmd" placeholder="Send server commands here, try /help" class="command" @keyup.enter="sendCommand()"/> | |||
</div> | |||
<div v-else class="container login" style="max-width: 400px;"> | |||
<form @submit.prevent="onLogin"> | |||
<p>Username</p> | |||
<input type="text" v-model="login.username" required/> | |||
<p>Password</p> | |||
<input type="password" v-model="login.password" required/> | |||
<p><button type="submit" @click="onLogin" :disabled="loginSubmitBusy">Login</button></p> | |||
</form> | |||
</div> | |||
<footer style="height: 24px">Built by the <a href="https://cloudron.io" target="_blank">Cloudron.io</a> team</footer> | |||
<button v-if="profile" @click="onLogout" class="logout">Logout</button> | |||
</div> | |||
<script src="/js/index.js"></script> | |||
</body> | |||
</html> |
@ -0,0 +1,152 @@ | |||
'use strict'; | |||
/* global Vue */ | |||
/* global superagent */ | |||
new Vue({ | |||
el: '#app', | |||
data: { | |||
login: { | |||
username: '', | |||
password: '' | |||
}, | |||
loginSubmitBusy: false, | |||
status: {}, | |||
settings: '', | |||
logstream: [], | |||
cmd: '', | |||
profile: null | |||
}, | |||
methods: { | |||
onError: function (error) { | |||
console.error(error); | |||
}, | |||
onReady: function () { | |||
this.refresh(); | |||
this.loadSettings(); | |||
this.loadLogs(); | |||
}, | |||
refresh: function () { | |||
var that = this; | |||
superagent.get('/api/v1/status').auth(this.login.username, this.login.password).end(function (error, result) { | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 200) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
that.status = result.body.status; | |||
setTimeout(that.refresh, 5000); | |||
}); | |||
}, | |||
onLogin: function () { | |||
var that = this; | |||
that.loginSubmitBusy = true; | |||
superagent.get('/api/v1/profile').auth(this.login.username, this.login.password).end(function (error, result) { | |||
that.loginSubmitBusy = false; | |||
if (error && error.status === 401) { | |||
that.$refs.loginInput.focus(); | |||
that.login.username = ''; | |||
that.login.password = ''; | |||
return that.onError('Invalid username or password'); | |||
} | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 200) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
// stash the credentials in the local storage | |||
window.localStorage.username = that.login.username; | |||
window.localStorage.password = that.login.password; | |||
that.profile = result.body.user; | |||
that.onReady(); | |||
}); | |||
}, | |||
onLogout: function () { | |||
this.profile = null; | |||
// delete the credentials from the local storage | |||
delete window.localStorage.username; | |||
delete window.localStorage.password; | |||
}, | |||
start: function () { | |||
var that = this; | |||
superagent.post('/api/v1/start').auth(this.login.username, this.login.password).end(function (error, result) { | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 202) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
}); | |||
}, | |||
stop: function () { | |||
var that = this; | |||
superagent.post('/api/v1/stop').auth(this.login.username, this.login.password).end(function (error, result) { | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 202) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
}); | |||
}, | |||
loadSettings: function () { | |||
var that = this; | |||
superagent.get('/api/v1/settings').auth(this.login.username, this.login.password).end(function (error, result) { | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 200) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
that.settings = result.body.settings; | |||
}); | |||
}, | |||
sendCommand: function () { | |||
var that = this; | |||
superagent.post('/api/v1/command').send({ cmd: this.cmd }).auth(this.login.username, this.login.password).end(function (error, result) { | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 202) return that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
that.cmd = ''; | |||
}); | |||
}, | |||
loadLogs: function () { | |||
var that = this; | |||
var socket = io(); | |||
socket.on('line', function (line) { | |||
that.logstream.push(line); | |||
Vue.nextTick(function () { | |||
var elem = document.getElementsByClassName('logstream')[0]; | |||
elem.scrollTop = elem.scrollHeight - 100; | |||
}); | |||
}); | |||
} | |||
}, | |||
mounted: function () { | |||
var that = this; | |||
that.login.username = window.localStorage.username || ''; | |||
that.login.password = window.localStorage.password || ''; | |||
if (!that.login.username || !that.login.password) { | |||
that.profile = null; | |||
return; | |||
} | |||
superagent.get('/api/v1/profile').auth(that.login.username, that.login.password).end(function (error, result) { | |||
if (error && error.status === 401) { | |||
// clear the local storage on wrong credentials | |||
delete window.localStorage.username; | |||
delete window.localStorage.password; | |||
that.profile = null; | |||
return; | |||
} | |||
if (error) return that.onError(error); | |||
if (result.statusCode !== 200) that.onError('Unexpected response: ' + result.statusCode + ' ' + result.text); | |||
that.profile = result.body.user; | |||
that.onReady(); | |||
}); | |||
} | |||
}); |
@ -0,0 +1,100 @@ | |||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.superagent=f()}})(function(){var define,module,exports;return(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){function Agent(){this._defaults=[];} | |||
["use","on","once","set","query","type","accept","auth","withCredentials","sortQuery","retry","ok","redirects","timeout","buffer","serialize","parse","ca","key","pfx","cert"].forEach(function(fn){Agent.prototype[fn]=function(){this._defaults.push({fn:fn,arguments:arguments});return this;}});Agent.prototype._setDefaults=function(req){this._defaults.forEach(function(def){req[def.fn].apply(req,def.arguments);});};module.exports=Agent;},{}],2:[function(require,module,exports){'use strict';function isObject(obj){return null!==obj&&'object'===typeof obj;} | |||
module.exports=isObject;},{}],3:[function(require,module,exports){'use strict';var isObject=require('./is-object');module.exports=RequestBase;function RequestBase(obj){if(obj)return mixin(obj);} | |||
function mixin(obj){for(var key in RequestBase.prototype){obj[key]=RequestBase.prototype[key];} | |||
return obj;} | |||
RequestBase.prototype.clearTimeout=function _clearTimeout(){clearTimeout(this._timer);clearTimeout(this._responseTimeoutTimer);delete this._timer;delete this._responseTimeoutTimer;return this;};RequestBase.prototype.parse=function parse(fn){this._parser=fn;return this;};RequestBase.prototype.responseType=function(val){this._responseType=val;return this;};RequestBase.prototype.serialize=function serialize(fn){this._serializer=fn;return this;};RequestBase.prototype.timeout=function timeout(options){if(!options||'object'!==typeof options){this._timeout=options;this._responseTimeout=0;return this;} | |||
for(var option in options){switch(option){case 'deadline':this._timeout=options.deadline;break;case 'response':this._responseTimeout=options.response;break;default:console.warn("Unknown timeout option",option);}} | |||
return this;};RequestBase.prototype.retry=function retry(count,fn){if(arguments.length===0||count===true)count=1;if(count<=0)count=0;this._maxRetries=count;this._retries=0;this._retryCallback=fn;return this;};var ERROR_CODES=['ECONNRESET','ETIMEDOUT','EADDRINFO','ESOCKETTIMEDOUT'];RequestBase.prototype._shouldRetry=function(err,res){if(!this._maxRetries||this._retries++>=this._maxRetries){return false;} | |||
if(this._retryCallback){try{var override=this._retryCallback(err,res);if(override===true)return true;if(override===false)return false;}catch(e){console.error(e);}} | |||
if(res&&res.status&&res.status>=500&&res.status!=501)return true;if(err){if(err.code&&~ERROR_CODES.indexOf(err.code))return true;if(err.timeout&&err.code=='ECONNABORTED')return true;if(err.crossDomain)return true;} | |||
return false;};RequestBase.prototype._retry=function(){this.clearTimeout();if(this.req){this.req=null;this.req=this.request();} | |||
this._aborted=false;this.timedout=false;return this._end();};RequestBase.prototype.then=function then(resolve,reject){if(!this._fullfilledPromise){var self=this;if(this._endCalled){console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises");} | |||
this._fullfilledPromise=new Promise(function(innerResolve,innerReject){self.end(function(err,res){if(err)innerReject(err);else innerResolve(res);});});} | |||
return this._fullfilledPromise.then(resolve,reject);};RequestBase.prototype['catch']=function(cb){return this.then(undefined,cb);};RequestBase.prototype.use=function use(fn){fn(this);return this;};RequestBase.prototype.ok=function(cb){if('function'!==typeof cb)throw Error("Callback required");this._okCallback=cb;return this;};RequestBase.prototype._isResponseOK=function(res){if(!res){return false;} | |||
if(this._okCallback){return this._okCallback(res);} | |||
return res.status>=200&&res.status<300;};RequestBase.prototype.get=function(field){return this._header[field.toLowerCase()];};RequestBase.prototype.getHeader=RequestBase.prototype.get;RequestBase.prototype.set=function(field,val){if(isObject(field)){for(var key in field){this.set(key,field[key]);} | |||
return this;} | |||
this._header[field.toLowerCase()]=val;this.header[field]=val;return this;};RequestBase.prototype.unset=function(field){delete this._header[field.toLowerCase()];delete this.header[field];return this;};RequestBase.prototype.field=function(name,val){if(null===name||undefined===name){throw new Error('.field(name, val) name can not be empty');} | |||
if(this._data){console.error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()");} | |||
if(isObject(name)){for(var key in name){this.field(key,name[key]);} | |||
return this;} | |||
if(Array.isArray(val)){for(var i in val){this.field(name,val[i]);} | |||
return this;} | |||
if(null===val||undefined===val){throw new Error('.field(name, val) val can not be empty');} | |||
if('boolean'===typeof val){val=''+val;} | |||
this._getFormData().append(name,val);return this;};RequestBase.prototype.abort=function(){if(this._aborted){return this;} | |||
this._aborted=true;this.xhr&&this.xhr.abort();this.req&&this.req.abort();this.clearTimeout();this.emit('abort');return this;};RequestBase.prototype._auth=function(user,pass,options,base64Encoder){switch(options.type){case 'basic':this.set('Authorization','Basic '+base64Encoder(user+':'+pass));break;case 'auto':this.username=user;this.password=pass;break;case 'bearer':this.set('Authorization','Bearer '+user);break;} | |||
return this;};RequestBase.prototype.withCredentials=function(on){if(on==undefined)on=true;this._withCredentials=on;return this;};RequestBase.prototype.redirects=function(n){this._maxRedirects=n;return this;};RequestBase.prototype.maxResponseSize=function(n){if('number'!==typeof n){throw TypeError("Invalid argument");} | |||
this._maxResponseSize=n;return this;};RequestBase.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header,};};RequestBase.prototype.send=function(data){var isObj=isObject(data);var type=this._header['content-type'];if(this._formData){console.error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()");} | |||
if(isObj&&!this._data){if(Array.isArray(data)){this._data=[];}else if(!this._isHost(data)){this._data={};}}else if(data&&this._data&&this._isHost(this._data)){throw Error("Can't merge these send calls");} | |||
if(isObj&&isObject(this._data)){for(var key in data){this._data[key]=data[key];}}else if('string'==typeof data){if(!type)this.type('form');type=this._header['content-type'];if('application/x-www-form-urlencoded'==type){this._data=this._data?this._data+'&'+data:data;}else{this._data=(this._data||'')+data;}}else{this._data=data;} | |||
if(!isObj||this._isHost(data)){return this;} | |||
if(!type)this.type('json');return this;};RequestBase.prototype.sortQuery=function(sort){this._sort=typeof sort==='undefined'?true:sort;return this;};RequestBase.prototype._finalizeQueryString=function(){var query=this._query.join('&');if(query){this.url+=(this.url.indexOf('?')>=0?'&':'?')+query;} | |||
this._query.length=0;if(this._sort){var index=this.url.indexOf('?');if(index>=0){var queryArr=this.url.substring(index+1).split('&');if('function'===typeof this._sort){queryArr.sort(this._sort);}else{queryArr.sort();} | |||
this.url=this.url.substring(0,index)+'?'+queryArr.join('&');}}};RequestBase.prototype._appendQueryString=function(){console.trace("Unsupported");} | |||
RequestBase.prototype._timeoutError=function(reason,timeout,errno){if(this._aborted){return;} | |||
var err=new Error(reason+timeout+'ms exceeded');err.timeout=timeout;err.code='ECONNABORTED';err.errno=errno;this.timedout=true;this.abort();this.callback(err);};RequestBase.prototype._setTimeouts=function(){var self=this;if(this._timeout&&!this._timer){this._timer=setTimeout(function(){self._timeoutError('Timeout of ',self._timeout,'ETIME');},this._timeout);} | |||
if(this._responseTimeout&&!this._responseTimeoutTimer){this._responseTimeoutTimer=setTimeout(function(){self._timeoutError('Response timeout of ',self._responseTimeout,'ETIMEDOUT');},this._responseTimeout);}};},{"./is-object":2}],4:[function(require,module,exports){'use strict';var utils=require('./utils');module.exports=ResponseBase;function ResponseBase(obj){if(obj)return mixin(obj);} | |||
function mixin(obj){for(var key in ResponseBase.prototype){obj[key]=ResponseBase.prototype[key];} | |||
return obj;} | |||
ResponseBase.prototype.get=function(field){return this.header[field.toLowerCase()];};ResponseBase.prototype._setHeaderProperties=function(header){var ct=header['content-type']||'';this.type=utils.type(ct);var params=utils.params(ct);for(var key in params)this[key]=params[key];this.links={};try{if(header.link){this.links=utils.parseLinks(header.link);}}catch(err){}};ResponseBase.prototype._setStatusProperties=function(status){var type=status/100|0;this.status=this.statusCode=status;this.statusType=type;this.info=1==type;this.ok=2==type;this.redirect=3==type;this.clientError=4==type;this.serverError=5==type;this.error=(4==type||5==type)?this.toError():false;this.created=201==status;this.accepted=202==status;this.noContent=204==status;this.badRequest=400==status;this.unauthorized=401==status;this.notAcceptable=406==status;this.forbidden=403==status;this.notFound=404==status;this.unprocessableEntity=422==status;};},{"./utils":5}],5:[function(require,module,exports){'use strict';exports.type=function(str){return str.split(/ *; */).shift();};exports.params=function(str){return str.split(/ *; */).reduce(function(obj,str){var parts=str.split(/ *= */);var key=parts.shift();var val=parts.shift();if(key&&val)obj[key]=val;return obj;},{});};exports.parseLinks=function(str){return str.split(/ *, */).reduce(function(obj,str){var parts=str.split(/ *; */);var url=parts[0].slice(1,-1);var rel=parts[1].split(/ *= */)[1].slice(1,-1);obj[rel]=url;return obj;},{});};exports.cleanHeader=function(header,changesOrigin){delete header['content-type'];delete header['content-length'];delete header['transfer-encoding'];delete header['host'];if(changesOrigin){delete header['authorization'];delete header['cookie'];} | |||
return header;};},{}],6:[function(require,module,exports){if(typeof module!=='undefined'){module.exports=Emitter;} | |||
function Emitter(obj){if(obj)return mixin(obj);};function mixin(obj){for(var key in Emitter.prototype){obj[key]=Emitter.prototype[key];} | |||
return obj;} | |||
Emitter.prototype.on=Emitter.prototype.addEventListener=function(event,fn){this._callbacks=this._callbacks||{};(this._callbacks['$'+event]=this._callbacks['$'+event]||[]).push(fn);return this;};Emitter.prototype.once=function(event,fn){function on(){this.off(event,on);fn.apply(this,arguments);} | |||
on.fn=fn;this.on(event,on);return this;};Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(event,fn){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this;} | |||
var callbacks=this._callbacks['$'+event];if(!callbacks)return this;if(1==arguments.length){delete this._callbacks['$'+event];return this;} | |||
var cb;for(var i=0;i<callbacks.length;i++){cb=callbacks[i];if(cb===fn||cb.fn===fn){callbacks.splice(i,1);break;}} | |||
return this;};Emitter.prototype.emit=function(event){this._callbacks=this._callbacks||{};var args=[].slice.call(arguments,1),callbacks=this._callbacks['$'+event];if(callbacks){callbacks=callbacks.slice(0);for(var i=0,len=callbacks.length;i<len;++i){callbacks[i].apply(this,args);}} | |||
return this;};Emitter.prototype.listeners=function(event){this._callbacks=this._callbacks||{};return this._callbacks['$'+event]||[];};Emitter.prototype.hasListeners=function(event){return!!this.listeners(event).length;};},{}],7:[function(require,module,exports){var root;if(typeof window!=='undefined'){root=window;}else if(typeof self!=='undefined'){root=self;}else{console.warn("Using browser-only version of superagent in non-browser environment");root=this;} | |||
var Emitter=require('component-emitter');var RequestBase=require('./request-base');var isObject=require('./is-object');var ResponseBase=require('./response-base');var Agent=require('./agent-base');function noop(){};var request=exports=module.exports=function(method,url){if('function'==typeof url){return new exports.Request('GET',method).end(url);} | |||
if(1==arguments.length){return new exports.Request('GET',method);} | |||
return new exports.Request(method,url);} | |||
exports.Request=Request;request.getXHR=function(){if(root.XMLHttpRequest&&(!root.location||'file:'!=root.location.protocol||!root.ActiveXObject)){return new XMLHttpRequest;}else{try{return new ActiveXObject('Microsoft.XMLHTTP');}catch(e){} | |||
try{return new ActiveXObject('Msxml2.XMLHTTP.6.0');}catch(e){} | |||
try{return new ActiveXObject('Msxml2.XMLHTTP.3.0');}catch(e){} | |||
try{return new ActiveXObject('Msxml2.XMLHTTP');}catch(e){}} | |||
throw Error("Browser-only version of superagent could not find XHR");};var trim=''.trim?function(s){return s.trim();}:function(s){return s.replace(/(^\s*|\s*$)/g,'');};function serialize(obj){if(!isObject(obj))return obj;var pairs=[];for(var key in obj){pushEncodedKeyValuePair(pairs,key,obj[key]);} | |||
return pairs.join('&');} | |||
function pushEncodedKeyValuePair(pairs,key,val){if(val!=null){if(Array.isArray(val)){val.forEach(function(v){pushEncodedKeyValuePair(pairs,key,v);});}else if(isObject(val)){for(var subkey in val){pushEncodedKeyValuePair(pairs,key+'['+subkey+']',val[subkey]);}}else{pairs.push(encodeURIComponent(key) | |||
+'='+encodeURIComponent(val));}}else if(val===null){pairs.push(encodeURIComponent(key));}} | |||
request.serializeObject=serialize;function parseString(str){var obj={};var pairs=str.split('&');var pair;var pos;for(var i=0,len=pairs.length;i<len;++i){pair=pairs[i];pos=pair.indexOf('=');if(pos==-1){obj[decodeURIComponent(pair)]='';}else{obj[decodeURIComponent(pair.slice(0,pos))]=decodeURIComponent(pair.slice(pos+1));}} | |||
return obj;} | |||
request.parseString=parseString;request.types={html:'text/html',json:'application/json',xml:'text/xml',urlencoded:'application/x-www-form-urlencoded','form':'application/x-www-form-urlencoded','form-data':'application/x-www-form-urlencoded'};request.serialize={'application/x-www-form-urlencoded':serialize,'application/json':JSON.stringify};request.parse={'application/x-www-form-urlencoded':parseString,'application/json':JSON.parse};function parseHeader(str){var lines=str.split(/\r?\n/);var fields={};var index;var line;var field;var val;for(var i=0,len=lines.length;i<len;++i){line=lines[i];index=line.indexOf(':');if(index===-1){continue;} | |||
field=line.slice(0,index).toLowerCase();val=trim(line.slice(index+1));fields[field]=val;} | |||
return fields;} | |||
function isJSON(mime){return /[\/+]json($|[^-\w])/.test(mime);} | |||
function Response(req){this.req=req;this.xhr=this.req.xhr;this.text=((this.req.method!='HEAD'&&(this.xhr.responseType===''||this.xhr.responseType==='text'))||typeof this.xhr.responseType==='undefined')?this.xhr.responseText:null;this.statusText=this.req.xhr.statusText;var status=this.xhr.status;if(status===1223){status=204;} | |||
this._setStatusProperties(status);this.header=this.headers=parseHeader(this.xhr.getAllResponseHeaders());this.header['content-type']=this.xhr.getResponseHeader('content-type');this._setHeaderProperties(this.header);if(null===this.text&&req._responseType){this.body=this.xhr.response;}else{this.body=this.req.method!='HEAD'?this._parseBody(this.text?this.text:this.xhr.response):null;}} | |||
ResponseBase(Response.prototype);Response.prototype._parseBody=function(str){var parse=request.parse[this.type];if(this.req._parser){return this.req._parser(this,str);} | |||
if(!parse&&isJSON(this.type)){parse=request.parse['application/json'];} | |||
return parse&&str&&(str.length||str instanceof Object)?parse(str):null;};Response.prototype.toError=function(){var req=this.req;var method=req.method;var url=req.url;var msg='cannot '+method+' '+url+' ('+this.status+')';var err=new Error(msg);err.status=this.status;err.method=method;err.url=url;return err;};request.Response=Response;function Request(method,url){var self=this;this._query=this._query||[];this.method=method;this.url=url;this.header={};this._header={};this.on('end',function(){var err=null;var res=null;try{res=new Response(self);}catch(e){err=new Error('Parser is unable to parse the response');err.parse=true;err.original=e;if(self.xhr){err.rawResponse=typeof self.xhr.responseType=='undefined'?self.xhr.responseText:self.xhr.response;err.status=self.xhr.status?self.xhr.status:null;err.statusCode=err.status;}else{err.rawResponse=null;err.status=null;} | |||
return self.callback(err);} | |||
self.emit('response',res);var new_err;try{if(!self._isResponseOK(res)){new_err=new Error(res.statusText||'Unsuccessful HTTP response');}}catch(custom_err){new_err=custom_err;} | |||
if(new_err){new_err.original=err;new_err.response=res;new_err.status=res.status;self.callback(new_err,res);}else{self.callback(null,res);}});} | |||
Emitter(Request.prototype);RequestBase(Request.prototype);Request.prototype.type=function(type){this.set('Content-Type',request.types[type]||type);return this;};Request.prototype.accept=function(type){this.set('Accept',request.types[type]||type);return this;};Request.prototype.auth=function(user,pass,options){if(1===arguments.length)pass='';if(typeof pass==='object'&&pass!==null){options=pass;pass='';} | |||
if(!options){options={type:'function'===typeof btoa?'basic':'auto',};} | |||
var encoder=function(string){if('function'===typeof btoa){return btoa(string);} | |||
throw new Error('Cannot use basic auth, btoa is not a function');};return this._auth(user,pass,options,encoder);};Request.prototype.query=function(val){if('string'!=typeof val)val=serialize(val);if(val)this._query.push(val);return this;};Request.prototype.attach=function(field,file,options){if(file){if(this._data){throw Error("superagent can't mix .send() and .attach()");} | |||
this._getFormData().append(field,file,options||file.name);} | |||
return this;};Request.prototype._getFormData=function(){if(!this._formData){this._formData=new root.FormData();} | |||
return this._formData;};Request.prototype.callback=function(err,res){if(this._shouldRetry(err,res)){return this._retry();} | |||
var fn=this._callback;this.clearTimeout();if(err){if(this._maxRetries)err.retries=this._retries-1;this.emit('error',err);} | |||
fn(err,res);};Request.prototype.crossDomainError=function(){var err=new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.');err.crossDomain=true;err.status=this.status;err.method=this.method;err.url=this.url;this.callback(err);};Request.prototype.buffer=Request.prototype.ca=Request.prototype.agent=function(){console.warn("This is not supported in browser version of superagent");return this;};Request.prototype.pipe=Request.prototype.write=function(){throw Error("Streaming is not supported in browser version of superagent");};Request.prototype._isHost=function _isHost(obj){return obj&&'object'===typeof obj&&!Array.isArray(obj)&&Object.prototype.toString.call(obj)!=='[object Object]';} | |||
Request.prototype.end=function(fn){if(this._endCalled){console.warn("Warning: .end() was called twice. This is not supported in superagent");} | |||
this._endCalled=true;this._callback=fn||noop;this._finalizeQueryString();return this._end();};Request.prototype._end=function(){var self=this;var xhr=(this.xhr=request.getXHR());var data=this._formData||this._data;this._setTimeouts();xhr.onreadystatechange=function(){var readyState=xhr.readyState;if(readyState>=2&&self._responseTimeoutTimer){clearTimeout(self._responseTimeoutTimer);} | |||
if(4!=readyState){return;} | |||
var status;try{status=xhr.status}catch(e){status=0;} | |||
if(!status){if(self.timedout||self._aborted)return;return self.crossDomainError();} | |||
self.emit('end');};var handleProgress=function(direction,e){if(e.total>0){e.percent=e.loaded/e.total*100;} | |||
e.direction=direction;self.emit('progress',e);};if(this.hasListeners('progress')){try{xhr.onprogress=handleProgress.bind(null,'download');if(xhr.upload){xhr.upload.onprogress=handleProgress.bind(null,'upload');}}catch(e){}} | |||
try{if(this.username&&this.password){xhr.open(this.method,this.url,true,this.username,this.password);}else{xhr.open(this.method,this.url,true);}}catch(err){return this.callback(err);} | |||
if(this._withCredentials)xhr.withCredentials=true;if(!this._formData&&'GET'!=this.method&&'HEAD'!=this.method&&'string'!=typeof data&&!this._isHost(data)){var contentType=this._header['content-type'];var serialize=this._serializer||request.serialize[contentType?contentType.split(';')[0]:''];if(!serialize&&isJSON(contentType)){serialize=request.serialize['application/json'];} | |||
if(serialize)data=serialize(data);} | |||
for(var field in this.header){if(null==this.header[field])continue;if(this.header.hasOwnProperty(field)) | |||
xhr.setRequestHeader(field,this.header[field]);} | |||
if(this._responseType){xhr.responseType=this._responseType;} | |||
this.emit('request',this);xhr.send(typeof data!=='undefined'?data:null);return this;};request.agent=function(){return new Agent();};["GET","POST","OPTIONS","PATCH","PUT","DELETE"].forEach(function(method){Agent.prototype[method.toLowerCase()]=function(url,fn){var req=new request.Request(method,url);this._setDefaults(req);if(fn){req.end(fn);} | |||
return req;};});Agent.prototype.del=Agent.prototype['delete'];request.get=function(url,data,fn){var req=request('GET',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.query(data);if(fn)req.end(fn);return req;};request.head=function(url,data,fn){var req=request('HEAD',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.query(data);if(fn)req.end(fn);return req;};request.options=function(url,data,fn){var req=request('OPTIONS',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.send(data);if(fn)req.end(fn);return req;};function del(url,data,fn){var req=request('DELETE',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.send(data);if(fn)req.end(fn);return req;} | |||
request['del']=del;request['delete']=del;request.patch=function(url,data,fn){var req=request('PATCH',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.send(data);if(fn)req.end(fn);return req;};request.post=function(url,data,fn){var req=request('POST',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.send(data);if(fn)req.end(fn);return req;};request.put=function(url,data,fn){var req=request('PUT',url);if('function'==typeof data)(fn=data),(data=null);if(data)req.send(data);if(fn)req.end(fn);return req;};},{"./agent-base":1,"./is-object":2,"./request-base":3,"./response-base":4,"component-emitter":6}]},{},[7])(7)}); |
@ -1,110 +1,18 @@ | |||
'use strict'; | |||
var express = require('express'), | |||
path = require('path'), | |||
bodyParser = require('body-parser'), | |||
fs = require('fs'); | |||
var minecraft = null; | |||
var configFilePath = path.join('/app/data/', 'server.properties'); | |||
var opsFilePath = path.join('/app/data/', 'ops.txt'); | |||
function startMinecraft() { | |||
console.log('start minecraft server'); | |||
minecraft = require('child_process').spawn('java', ['-Xmx1024M', '-Xms1024M', '-jar', path.join(__dirname, 'minecraft_server.jar'), 'nogui'], { cwd: '/app/data/' }); | |||
minecraft.stdout.pipe(process.stdout); | |||
minecraft.stderr.pipe(process.stderr); | |||
minecraft.on('close', function () { | |||
minecraft = null; | |||
}); | |||
} | |||
function stopMinecraft(callback) { | |||
console.log('stop minecraft server'); | |||
if (!minecraft) return callback(); | |||
minecraft.kill(); | |||
minecraft.on('close', function () { | |||
minecraft = null; | |||
callback(); | |||
}); | |||
} | |||
var app = express(); | |||
app.use(bodyParser.json()); | |||
app.use(bodyParser.urlencoded()); | |||
app.get('/', function (req, res) { | |||
res.sendFile(path.join(__dirname, 'index.html')); | |||
}); | |||
app.get('/healthcheck', function (req, res) { | |||
res.sendStatus(200); | |||
}); | |||
#!/usr/bin/env node | |||
app.get('/config', function (req, res) { | |||
fs.readFile(configFilePath, function (error, result) { | |||
if (error) return res.status(500).send(error); | |||
res.sendStatus(200, result); | |||
}); | |||
}); | |||
app.post('/config', function (req, res) { | |||
stopMinecraft(function () { | |||
fs.writeFile(configFilePath, req.body.config, function (error) { | |||
if (error) return res.status(500).send(error); | |||
startMinecraft(); | |||
res.sendStatus(200); | |||
}); | |||
}); | |||
}); | |||
app.get('/ops', function (req, res) { | |||
fs.readFile(opsFilePath, function (error, result) { | |||
if (error) return res.status(500).send(error); | |||
res.status(200).send(result); | |||
}); | |||
}); | |||
app.post('/ops', function (req, res) { | |||
stopMinecraft(function () { | |||
fs.writeFile(opsFilePath, req.body.ops, function (error) { | |||
if (error) res.status(500).send(error); | |||
startMinecraft(); | |||
'use strict'; | |||
res.sendStatus(200); | |||
}); | |||
}); | |||
}); | |||
require('supererror'); | |||
app.get('/status', function (req, res) { | |||
res.status(200).send({ running: !!minecraft }); | |||
}); | |||
var server = require('./backend/server.js'), | |||
minecraft = require('./backend/minecraft.js'); | |||
app.post('/start', function (req, res) { | |||
startMinecraft(); | |||
res.sendStatus(200); | |||
}); | |||
const PORT = process.env.PORT || 3000; | |||
app.post('/stop', function (req, res) { | |||
stopMinecraft(function () { | |||
res.sendStatus(200); | |||
}); | |||
}); | |||
server.start(parseInt(PORT), function (error) { | |||
if (error) return console.error('Failed to start server.', error); | |||
var server = app.listen(3000, function () { | |||
var host = server.address().address; | |||
var port = server.address().port; | |||
console.log(`Server is up and running on port ${PORT}`); | |||
console.log('Configuration server listening at http://%s:%s', host, port); | |||
minecraft.start(); | |||
}); |