diff --git a/files/server.sh b/files/server.sh index 3a6944e..99640db 100755 --- a/files/server.sh +++ b/files/server.sh @@ -9,6 +9,7 @@ EOF # Uncomment the line below to run things manually in the container, then run: # docker compose exec main bash tail -f /dev/null +exit 0 # Otherwise, start the server normally -#/files/dayzserver start +/files/dayzserver start diff --git a/files/webserver.sh b/files/webserver.sh index 7ebbc37..6a6cad9 100755 --- a/files/webserver.sh +++ b/files/webserver.sh @@ -10,6 +10,12 @@ export PS1="${debian_chroot:+($debian_chroot)}\u@dz-main:\w\$ " EOF fi +# Uncomment the lines below to run things manually in the container, then run: +# docker compose exec main bash +tail -f /dev/null +exit 0 + +# Otherwise, start the server normally cd /web npm i node index.js diff --git a/server/bin/dz b/server/bin/dz index 8119510..839c016 100755 --- a/server/bin/dz +++ b/server/bin/dz @@ -56,7 +56,7 @@ loadconfig(){ if [ ! -f "${SERVER_INSTALL_FILE}" ] then echo - echo -e "The DayZ server files are not installed. Run '${green}docker-compose run --rm main dayzserver install${default}'" + echo -e "The DayZ server files are not installed. You need to do this first in the web UI." echo exit 1 fi diff --git a/web/index.js b/web/index.js index 63820ce..e099826 100644 --- a/web/index.js +++ b/web/index.js @@ -1,10 +1,139 @@ -const express = require('express') -const path = require('path') +import express from 'express' +import path from 'path' +import fs from 'fs' + const app = express() -const port = 8000 -app.use('/', express.static(path.join(__dirname, 'root'))) +/* + The DayZ server Steam app ID. USE ONE OR THE OTHER!! -app.listen(port, () => { - console.log(`Listening on port ${port}`) + Presumably once the Linux server is officially released, the binaries will come from this ID. + Meanwhile, if we have a release-compatible binary, the base files must be installed from this id, + even if the server binary and required shared objects don't come from it. (They'd come from...elsewhere...) + */ +//const server_appid = "223350" + +/* + Without a release binary, we must use the experimental server app ID. + */ +const server_appid = "1042420" + +/* + DayZ release client Steam app ID. This is for mods, as only the release client has them. + */ +const client_appid = "221100" + +/* + Base file locations + */ +const modDir = "/mods" +const serverFiles = "/serverfiles" + +const d = '/' + +/* + XML config files the system can handle. These are retrieved from values in templates located in /files/mods/:modId + */ +const configFiles = [ + 'cfgeventspawns.xml', + 'cfgspawnabletypes.xml', + 'events.xml', + 'types.xml', +] + +const config = { + installFile: serverFiles + "/DayZServer", + modDir: modDir + "/" + client_appid, + port: 8000, +} + +const getDirSize = (dirPath) => { + let size = 0 + const files = fs.readdirSync(dirPath) + for (let i = 0; i < files.length; i++) { + const filePath = path.join(dirPath, files[i]) + const stats = fs.statSync(filePath) + if (stats.isFile()) { + size += stats.size + } else if (stats.isDirectory()) { + size += getDirSize(filePath) + } + } + return size +} + +const getCustomXML = (modId) => { + const ret = [] + for(const file of configFiles) { + if (fs.existsSync(config.modDir + d + modId + d + file)) { + ret.push({name:file}) + } + } + return ret +} + +const getModNameById = (id) => { + const files = fs.readdirSync(serverFiles, {encoding: 'utf8', withFileTypes: true}) + for (const file of files) { + if (file.isSymbolicLink()) { + const sym = fs.readlinkSync(serverFiles + d + file.name) + if(sym.indexOf(id) > -1) return file.name + } + } +} + +const getMods = () => { + const mods = [] + fs.readdirSync(config.modDir).forEach(file => { + const name = getModNameById(file) + mods.push({name:name,id:file}) + }) + return mods +} + +app.use(express.static('root')) + +app.get('/status', (req, res) => { + // FIXME! Group these into a Promise.All() + const installed = fs.existsSync(config.installFile) + const mods = getMods() + const ret = { + "installed": installed, + "version": "1.20.bogus", + "mods": mods + } + res.send(ret) +}) + +app.route('/mod/:modId') + .get((req, res) => { + // Get mod metadata by ID + const modId = req.params["modId"] + const modDir = config.modDir + d + modId + const customXML = getCustomXML(modId) + const ret = { + id: modId, + name: getModNameById(modId), + size: getDirSize(modDir), + customXML: customXML + } + res.send(ret) + }) + .post((req, res) => { + // Add a mod by ID + }) + .put((req, res) => { + // Update a mod by ID + }) + +app.route('/mod/:modId/:file') + .get((req, res) => { + const modId = req.params["modId"] + const file = req.params["file"] + const contents = fs.readFileSync(config.modDir + d + modId + d + file) + res.send(contents) + }) + +app.listen(config.port, () => { + console.log(`Listening on port ${config.port}`) }) diff --git a/web/package.json b/web/package.json index 14398df..f606cfe 100644 --- a/web/package.json +++ b/web/package.json @@ -11,5 +11,6 @@ "license": "ISC", "dependencies": { "express": "^4.18.2" - } + }, + "type": "module" } diff --git a/web/root/index.css b/web/root/index.css new file mode 100644 index 0000000..8f1d3da --- /dev/null +++ b/web/root/index.css @@ -0,0 +1,30 @@ +body { + padding-top: 50px; + background-color: black; +} +.green { + color: green; + font-weight: bolder; +} +.yellow { + color: yellow; + font-weight: bolder; +} +.darkgrey { + background-color: darkgray; + font-weight: bolder; + margin-bottom: 10px; +} + +.modInfo { + background-color: aliceblue; +} + +.simulink { + cursor: pointer; + text-underline: blue; +} + +th, td { + padding-right: 10px +} diff --git a/web/root/index.html b/web/root/index.html index c0941c6..9a882f7 100644 --- a/web/root/index.html +++ b/web/root/index.html @@ -3,21 +3,19 @@ DayZ Docker Server - - + + + + - -
-
-

DayZ Docker Server

-
-
- +
+ diff --git a/web/root/index.js b/web/root/index.js new file mode 100644 index 0000000..bc4a3e5 --- /dev/null +++ b/web/root/index.js @@ -0,0 +1,136 @@ +const template = ` +
+
+
+

DayZ Docker Server

+
+
+
+ Server files installed: {{ installed }} +
+
+ Version: {{ version }} +
+
+
+
+ {{ fetchError }} +
+
+
+

Mods

+ + + + + + +
Steam LinkMod Info
+
+
+
+

{{ modInfo.name }}

+
+
+
+
+ ID: {{ modInfo.id }} +
+
+ Size: {{ modInfo.size.toLocaleString("en-US") }} +
+
+ Custom XML files: + +
+
+
+ +
+
+
+
+
+ +` + +export default { + name: 'DazDockerServer', + template: template, + data() { + return { + fetchError: "", + installed: false, + mods: [], + modInfo: "", + version: "Unknown", + XMLInfo: "", + } + }, + methods: { + getModInfo(modId) { + fetch('/mod/' + modId) + .then(response => response.json()) + .then(response => { + this.modInfo = response + this.XMLInfo = "" + }) + .catch((error) => { + console.error(error) + this.fetchError = error.message + }) + }, + getXMLInfo(modId, file) { + fetch('/mod/' + modId + '/' + file) + .then(response => response.text()) + .then(response => { + this.XMLInfo = response + }) + .catch((error) => { + console.error(error) + this.fetchError = error.message + }) + } + }, + mounted() { + // Get the data + fetch('/status') + .then(response => response.json()) + .then(response => { + this.installed = response.installed + this.version = response.version + this.mods = response.mods + if(response.error) { + this.fetchError = response.error + } + }) + .catch((error) => { + console.error(error) + this.fetchError = error.message + }) + } +}