mcgrizz/state/serverState.ts
2023-10-05 12:55:50 -06:00

152 lines
3.7 KiB
TypeScript

import { Sockpuppet } from "puppet/client";
import { acceptEULA, checkEULA } from "../util/EULA.ts";
import { Loader } from "../types/mcgrizzconf.ts";
import { getConfFile, updateConfFile } from "../util/confFile.ts";
import { IS_BROWSER } from "$fresh/runtime.ts";
type MCServerEvent = 'message';
type MCServerEventCallback = (msg: string) => void;
class ServerState {
private _status: "running" | "stopped" = "stopped";
public get status() {
return this._status;
}
private command!: Deno.Command;
private process!: Deno.ChildProcess;
private _eulaAccepted = false;
private sockpuppet!: Sockpuppet;
private _channelId = "blanaba";
public get channelId() {
return this._channelId;
}
public get eulaAccepted() {
return this._eulaAccepted;
}
private stdin!: WritableStreamDefaultWriter;
private _serverType: Loader = 'unset';
public get serverType(): Loader {
return this._serverType;
}
public set serverType(loader: Loader) {
updateConfFile({loader});
this._serverType = loader;
}
private _serverVersion: string;
public get serverVersion(): string {
return this._serverVersion;
}
public set serverVersion(version: string) {
updateConfFile({version});
this._serverVersion = version;
}
constructor() {
const conf = getConfFile();
this._serverType = conf.loader;
this._serverVersion = conf.version;
// if (this.serverType !== 'unset') this._eulaAccepted = checkEULA();
this.sockpuppet = new Sockpuppet(
"ws://sockpuppet.cyborggrizzly.com",
() => {
this.sockpuppet.joinChannel(this.channelId, async (msg) => {
if (msg === 'log' && !IS_BROWSER) {
const log = await Deno.readTextFile('./server/logs/latest.log');
this.channel?.send(log);
} else
this.sendStdIn(msg);
});
},
);
}
public get channel() {
return this.sockpuppet.getChannel(this.channelId);
}
public async sendStdIn(message: string) {
if (IS_BROWSER || !this.stdin) return;
const msg = new TextEncoder().encode(message + "\n");
await this.stdin.write(msg);
}
// "instance" should be moved to a private member once multi-instance support is implemented
public startMCServer(instance = "server") {
this.command = new Deno.Command("java", {
args: [
"-Xmx2G",
"-jar",
"./server.jar",
"nogui",
],
cwd: "./" + instance,
stdin: "piped",
stdout: "piped",
});
this.process = this.command.spawn();
const {readable, writable} = new TransformStream();
readable.pipeTo(this.process.stdin);
this.stdin = writable.getWriter();
this._status = "running";
this.startStream();
}
private async startStream() {
const stream = this.process.stdout.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await stream.read();
if (value) {
const line = decoder.decode(value);
this.channel?.send(line);
const stdoutMsg = new CustomEvent('stdoutmsg', {
detail: line
})
globalThis.dispatchEvent(stdoutMsg);
}
if (done) break;
}
}
public gracefullyStopMCServer() {
this._status = "stopped";
this.sendStdIn("stop");
}
public forceStopMCServer() {
this._status = "stopped";
this.process.kill();
}
public async restartMCServer() {
if (this.status === "running") {
await this.sendStdIn("stop");
// while (true) {
await this.process.status;
// }
}
this.startMCServer();
}
public acceptEULA() {
this._eulaAccepted = true;
acceptEULA();
}
}
export const SERVER_STATE = new ServerState();