working prototype

This commit is contained in:
WeeXnes 2025-03-05 06:57:32 +01:00
parent 2e55a6d566
commit abdf5ddefc
10 changed files with 317 additions and 71 deletions

View file

@ -14,10 +14,13 @@
"@nuxtjs/tailwindcss": "^6.13.1",
"axios": "^1.7.9",
"daisyui": "^4.12.23",
"execa": "^9.5.2",
"ini": "^5.0.0",
"nuxt": "^3.15.4",
"vue": "latest",
"vue-router": "latest",
"execa": "^9.5.2",
"ini": "^5.0.0"
"vue-router": "latest"
},
"devDependencies": {
"@types/ini": "^4.1.1"
}
}

View file

@ -3,18 +3,20 @@
<h1 class="text-4xl font-bold text-center mb-6">Minecraft Servers</h1>
<div class="grid md:grid-cols-3 gap-6 w-full max-w-5xl mb-8">
<div v-for="server in settings.servers" class="card bg-base-100 shadow-2xl p-6">
<h2 class="text-xl font-bold text-center cursor-pointer" @click="editServerDialog(server)">
<h2 class="text-xl font-bold text-center cursor-pointer" @click="showServerLogDialog(server)">
{{ server.name }}
</h2>
<div class="mt-2 text-sm">
<p><strong>Version:</strong> {{ server.version }}</p>
<p><strong>Port</strong> {{ server.port }}</p>
<p><strong>Memory:</strong> {{ server.minMemory }}-{{ server.maxMemory }}GB</p>
<p><strong>Memory:</strong> {{ server.maxMemory }}GB</p>
</div>
<div class="form-control mt-4 flex flex-row gap-2">
<button @click="startServer(server)" class="btn btn-primary w-1/2">Start</button>
<button @click="stopServer(server)" class="btn btn-error w-1/2">Stop</button>
<button @click="startServer(server)" class="btn btn-primary w-1/3">Start</button>
<button @click="showEditServerDialog(server)" class="btn btn-warning w-1/3">Edit</button>
<button @click="stopServer(server)" class="btn btn-error w-1/3">Stop</button>
</div>
</div>
@ -40,12 +42,6 @@
</div>
<input v-model="addDialog.newServer.name" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Port</span>
</div>
<input v-model="addDialog.newServer.port" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Version</span>
@ -59,15 +55,6 @@
<input v-model="addDialog.newServer.jar_url" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">JVM Min Memory</span>
</div>
<input v-model="addDialog.newServer.minMemory" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">JVM Max Memory</span>
@ -88,19 +75,96 @@
<input type="checkbox" id="editServerModal" class="modal-toggle" />
<input type="checkbox" id="serverLogModal" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box w-11/12 max-w-5xl">
<h3 class="text-lg font-bold text-center">{{ editDialog.editedServer.name }}</h3>
<h3 class="text-lg font-bold text-center">{{ serverLogDialog.selectedServer.name }}</h3>
<div class="mockup-code w-full">
<pre v-for="str in testrec.logs" data-prefix="$"><code>{{str}}</code></pre>
<pre v-for="str in serverLogDialog.logs" data-prefix="$"><code>{{str}}</code></pre>
</div>
<div class="modal-action flex justify-between space-x-4">
<!-- Start Button -->
<button @click="startServer(serverLogDialog.selectedServer)" class="btn btn-primary">Start</button>
<!-- Stop Button -->
<button @click="stopServer(serverLogDialog.selectedServer)" class="btn btn-error">Stop</button>
</div>
</div>
<label class="modal-backdrop" for="editServerModal">Close</label>
<label class="modal-backdrop" for="serverLogModal">Close</label>
</div>
<dialog id="editServerModal" class="modal">
<div class="modal-box">
<h3 class="text-lg font-bold">Edit Server: {{ editServerDialog.selectedServer.name }}</h3>
<div class="grid grid-cols-2 gap-4">
<!-- First row -->
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Difficulty</span>
</div>
<input v-model="editServerDialog.properties['difficulty']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Server Port</span>
</div>
<input v-model="editServerDialog.properties['server-port']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<!-- Second row (adding more elements) -->
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Command Blocks</span>
</div>
<input v-model="editServerDialog.properties['enable-command-block']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Gamemode</span>
</div>
<input v-model="editServerDialog.properties['gamemode']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<!-- Third row -->
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Slots</span>
</div>
<input v-model="editServerDialog.properties['max-players']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">PVP</span>
</div>
<input v-model="editServerDialog.properties['pvp']" type="text" placeholder="Type here" class="input input-bordered w-full max-w-xs" />
</label>
</div>
<div class="modal-action flex justify-between space-x-4">
<!-- Save Button -->
<form method="dialog">
<button class="btn btn-primary" @click="editServer">Save</button>
</form>
<!-- Delete Button -->
<form method="dialog">
<button class="btn btn-error" @click="deleteServer(editServerDialog)">Delete</button>
</form>
</div>
</div>
</dialog>
</template>
@ -110,11 +174,7 @@
import type {MinecraftServer} from "~/types/MinecraftServer";
import axios from 'axios';
const testrec = reactive({
logs: [] as string[],
})
import { stringify , parse } from 'ini'
const settings = reactive({
servers: [] as MinecraftServer[],
@ -124,8 +184,14 @@ const addDialog = reactive({
newServer: {} as MinecraftServer
})
const editDialog = reactive({
editedServer: {} as MinecraftServer
const serverLogDialog = reactive({
selectedServer: {} as MinecraftServer,
logs: [] as string[],
})
const editServerDialog = reactive({
selectedServer: {} as MinecraftServer,
properties: {} as { [p: string]: any }
})
@ -140,54 +206,111 @@ const getServers = async () => {
}
}
const showServerLogDialog = async (server: MinecraftServer) => {
serverLogDialog.selectedServer = server
// @ts-ignore
serverLogModal.checked = true
}
const getLogs = async () => {
// @ts-ignore
if(!editServerModal.checked)
if(!serverLogModal.checked){
if(serverLogDialog.logs.length != 0){
serverLogDialog.logs.length = 0;
}
return
}
if(!serverLogDialog.selectedServer)
return
try{
const response = await axios.post('/api/getLogs', {
name: editDialog.editedServer.name
name: serverLogDialog.selectedServer.name
});
console.log(response.data.message)
//console.log(response)
const strRet: string = response.data.logs;
const strRet = response.data.logs;
const stringArray = strRet.split('\n');
//console.log(stringArray);
testrec.logs.length = 0;
stringArray.slice(-20).forEach(element => {
testrec.logs.push(element);
serverLogDialog.logs.length = 0;
stringArray.slice(-20).forEach((element: string) => {
serverLogDialog.logs.push(element);
})
}catch(error){
console.error(`Error fetch: ${error}`);
}
}
const editServerDialog = async (server: MinecraftServer) => {
editDialog.editedServer = server
const showEditServerDialog = async (server: MinecraftServer) => {
editServerDialog.selectedServer = server
await getProperties()
// @ts-ignore
//editServerModal.showModal()
editServerModal.checked = true
editServerModal.showModal()
}
const getProperties = async () => {
// @ts-ignore
editServerModal.showModal()
try{
const response = await axios.post('/api/getProperties', {
name: editServerDialog.selectedServer.name
});
console.log(response.data.properties)
editServerDialog.properties = parse(response.data.properties)
}catch(error){
console.error(`Error fetch: ${error}`);
}
}
const addServer = async () => {
if (!settings.servers.some(server => server.name === addDialog.newServer.name)) {
settings.servers.push(addDialog.newServer)
await syncServers()
settings.servers.push({ ...addDialog.newServer });
await syncServers();
}
}
const deleteServer = async () => {
let index = settings.servers.findIndex(item => item.name === editDialog.editedServer.name);
settings.servers.splice(index, 1);
await syncServers()
const editServer = async () => {
try {
const response = await axios.post('/api/setProperties', {
name: editServerDialog.selectedServer.name,
properties: stringify(editServerDialog.properties)
});
console.log(response.data);
} catch (error) {
console.error(`Error `, error);
}
}
const deleteServer = async (server: MinecraftServer) => {
try {
const response = await axios.post('/api/deleteServer', {
name: server.name
});
console.log(response.data);
await getServers()
} catch (error) {
console.error(`Error `, error);
}
}
const syncServers = async () => {
try {
@ -195,6 +318,7 @@ const syncServers = async () => {
serverList: settings.servers
});
console.log(response.data);
} catch (error) {
console.error(`Error `, error);
}

View file

@ -0,0 +1,28 @@
import {environment} from "~/core/globals";
import {removeServerByName, saveJsonFile} from "~/util/jsonLoader";
import * as fs from 'fs/promises';
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const server_name: string = body.name
const server_properties: string = body.properties
const server = environment.settings.servers.find(server => server.name == server_name);
if(!server) {
return { message: "Server with name " + server_name + " does not exist" };
}
try {
console.log("Recived server list");
removeServerByName(server.name);
const logsPath = environment.paths.servers + "/" + server.name
await fs.rmdir(logsPath)
saveJsonFile()
return { status: 'success' };
} catch (error) {
return { status: 'error', error: error };
}
});

View file

@ -23,11 +23,16 @@ export default defineEventHandler(async (event) => {
try {
const data = await fs.readFile(logsPath, 'utf-8');
const strippedLogs = data.slice(0, -2);
return {
message: `Logs for ${server_name}`,
logs: data
logs: strippedLogs
};
} catch (error: any) {
return { message: "Failed to get logs for " + server_name, error: error.message };
return {
message: "Failed to get logs for " + server_name,
logs: "",
error: error.message
};
}
});

View file

@ -0,0 +1,32 @@
import {environment} from "~/core/globals";
import { defineEventHandler, getCookie, createError } from 'h3';
import {saveJsonFile} from "~/util/jsonLoader";
import {MinecraftServer} from "~/types/MinecraftServer";
import {execa} from "execa";
import * as fs from 'fs/promises';
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const server_name: string = body.name
const server = environment.settings.servers.find(server => server.name == server_name);
if(!server) {
return { message: "Server with name " + server_name + " does not exist" };
}
const workingDir = environment.paths.servers + "/" + server.name;
const logsPath = environment.paths.servers + "/" + server.name + "/server.properties";
try {
const data = await fs.readFile(logsPath, 'utf-8');
return {
message: `properties for ${server_name}`,
properties: data
};
} catch (error: any) {
return { message: "Failed to get logs for " + server_name, error: error.message };
}
});

View file

@ -0,0 +1,32 @@
import {environment} from "~/core/globals";
import { defineEventHandler, getCookie, createError } from 'h3';
import {saveJsonFile} from "~/util/jsonLoader";
import {MinecraftServer} from "~/types/MinecraftServer";
import {execa} from "execa";
import * as fs from 'fs/promises';
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const server_name: string = body.name
const server_properties: string = body.properties
const server = environment.settings.servers.find(server => server.name == server_name);
if(!server) {
return { message: "Server with name " + server_name + " does not exist" };
}
const workingDir = environment.paths.servers + "/" + server.name;
const logsPath = environment.paths.servers + "/" + server.name + "/server.properties";
try {
await fs.writeFile(logsPath, server_properties, 'utf8');
return {
message: `properties for ${server_name} set`,
};
} catch (error: any) {
return { message: "Failed to get logs for " + server_name, error: error.message };
}
});

View file

@ -23,13 +23,19 @@ export default defineEventHandler(async (event) => {
const jarPath = environment.paths.servers + "/" + server.name + "/server.jar";
try {
server.process = execa('java', ['-jar', jarPath, 'nogui'], {
const xmsArg = `-Xms${server.maxMemory}G`
const xmxArg = `-Xmx${server.maxMemory}G`
console.log(`Starting server ${server.name} with ${xmsArg} and ${xmxArg}`);
server.process = execa('java', [xmsArg, xmxArg, '-jar', jarPath, 'nogui'], {
cwd: workingDir,
});
server.process.stdout.on('data', (data: string) => {
const logData = data.toString();
console.log(logData);
//console.log(logData);
});
server.process.stderr.on('data', (data: string) => {

View file

@ -16,9 +16,6 @@ export default defineEventHandler(async (event) => {
return { message: "Minecraft server is not running." };
}
console.log(server.process)
console.log("currently contains: " + server.process)
try {
// Send "stop" command to the server process stdin

View file

@ -1,14 +1,23 @@
import type {ResultPromise} from "execa";
import {environment} from "~/core/globals";
export interface MinecraftServer {
name: string;
port: number;
version: string;
jar_url: string;
minMemory: number;
maxMemory: number;
process: any;
}
export function getServerDirectory (server: MinecraftServer): string {
return environment.paths.servers + "/" + server.name
}
export function getJarPath (server: MinecraftServer): string {
return environment.paths.servers + "/" + server.name + "/server.jar"
}
export function getPropertiesPath (server: MinecraftServer): string {
return environment.paths.servers + "/" + server.name + "/server.properties"
}

View file

@ -69,13 +69,23 @@ export function checkAllServerDirectories(){
})
environment.settings.servers.forEach(server => {
const destinationPath = environment.paths.servers + "/" + server.name + "/server.jar"
const destinationPathJar = environment.paths.servers + "/" + server.name + "/server.jar"
const destinationPathEula = environment.paths.servers + "/" + server.name + "/eula.txt"
try {
fs.accessSync(destinationPath);
fs.accessSync(destinationPathJar);
console.log('Settings already exists!');
} catch (error) {
downloadFile(server.jar_url, destinationPath);
downloadFile(server.jar_url, destinationPathJar);
}
try {
fs.accessSync(destinationPathEula);
console.log('eula exists');
} catch (error) {
console.log("setting eula to true")
fs.writeFileSync(destinationPathEula, 'eula=true');
}
})
}