Core apis #528
@ -1,14 +0,0 @@
|
||||
# npm
|
||||
/*.tgz
|
||||
|
||||
# Node
|
||||
node_modules/
|
||||
|
||||
# Typescript
|
||||
**/*.js
|
||||
**/*.d.ts
|
||||
**/tsconfig.tsbuildinfo
|
||||
|
||||
# PHP and Spigot Pre builds
|
||||
phpOutput/
|
||||
*.jar
|
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
@ -38,7 +38,7 @@ jobs:
|
||||
# Build Core
|
||||
- name: Core Build
|
||||
if: matrix.package != '@the-bds-maneger/core'
|
||||
run: npm run -w "@the-bds-maneger/core" build
|
||||
run: npm run -w "@the-bds-maneger/core" prepack
|
||||
|
||||
- name: Build "${{ matrix.package }}"
|
||||
run: npm run --if-present -w "${{ matrix.package }}" prepack
|
@ -5,91 +5,10 @@ import yargs from "yargs";
|
||||
|
||||
// Init yargs
|
||||
yargs(process.argv.slice(2)).version(false).help(true).strictCommands().demandCommand().alias("h", "help")
|
||||
.command("install", "Install server", async yargs => {
|
||||
const options = yargs.option("platform", {
|
||||
type: "string",
|
||||
string: true,
|
||||
alias: "p",
|
||||
choices: ["bedrock", "java"],
|
||||
default: "bedrock",
|
||||
description: "Platform to install"
|
||||
})
|
||||
.option("altserver", {
|
||||
type: "string",
|
||||
string: true,
|
||||
alias: "a",
|
||||
choices: ["spigot", "paper", "purpur", "pocketmine", "powernukkit", "nukkit", "cloudbust"],
|
||||
})
|
||||
.option("id", {
|
||||
alias: "i",
|
||||
type: "string",
|
||||
describe: "ID to update server"
|
||||
})
|
||||
.option("version", {
|
||||
type: "string",
|
||||
alias: "V",
|
||||
describe: "Server version",
|
||||
default: "latest"
|
||||
})
|
||||
.option("beta", {
|
||||
type: "boolean",
|
||||
boolean: true,
|
||||
default: false,
|
||||
describe: "allow install beta or snapshort versions"
|
||||
})
|
||||
.parseSync();
|
||||
|
||||
const serverPath = await bdsCore.serverManeger.serverManeger(options.platform === "java" ? "java" : "bedrock", {
|
||||
...(options.id ? {newID: false, ID: options.id} : {newID: true}),
|
||||
});
|
||||
|
||||
const installData = await (options.platform === "java" ? bdsCore.Java.installServer : bdsCore.Bedrock.installServer)(Object.assign({}, serverPath, {
|
||||
version: options.version,
|
||||
altServer: options.altserver as never,
|
||||
allowBeta: Boolean(options.beta)
|
||||
}));
|
||||
|
||||
console.log("ID: %O, Server Version: %O, Server Date: %O", installData.id, installData.version, installData.date);
|
||||
})
|
||||
.command("list", "list all versions", yargs => {
|
||||
const { platform, altserver } = yargs.option("platform", {
|
||||
type: "string",
|
||||
string: true,
|
||||
alias: "p",
|
||||
choices: ["bedrock", "java"],
|
||||
default: "bedrock",
|
||||
description: "Platform to install"
|
||||
}).option("altserver", {
|
||||
type: "string",
|
||||
string: true,
|
||||
alias: "a",
|
||||
choices: ["spigot", "paper", "purpur", "pocketmine", "powernukkit", "nukkit", "cloudbust"],
|
||||
}).parseSync();
|
||||
return (platform === "java" ? bdsCore.Java.listVersions : bdsCore.Bedrock.listVersions)(altserver as never).then(data => console.log(JSON.stringify(data, null, 2)));
|
||||
})
|
||||
.command("run", "Start server", async yargs => {
|
||||
const option = yargs.option("id", {
|
||||
type: "string",
|
||||
string: true,
|
||||
alias: "d",
|
||||
demandOption: true,
|
||||
}).parseSync();
|
||||
const idInfo = (await bdsCore.listIDs()).find(local => local.id === option.id);
|
||||
if (!idInfo) throw new Error("Invalid ID");
|
||||
const sserverPaths = await bdsCore.serverManeger.serverManeger(option.platform === "java" ? "java" : "bedrock", {ID: option.id, newID: false});
|
||||
const session = await (idInfo.platform === "java" ? bdsCore.Java.startServer : bdsCore.Bedrock.startServer)(sserverPaths);
|
||||
process.on("error", console.log);
|
||||
session.once("backup", filePath => console.log("Backup file path: %O", filePath));
|
||||
process.stdin.pipe(session.stdin);
|
||||
session.stdout.pipe(process.stdout);
|
||||
session.stderr.pipe(process.stderr);
|
||||
for (const ss of ([
|
||||
"SIGCONT",
|
||||
"SIGINT",
|
||||
"SIGTERM",
|
||||
] as NodeJS.Signals[])) process.on(ss, () => session.stopServer());
|
||||
return session;
|
||||
.command(["install", "i", "update"], "Install/update server platform", yargs => yargs, async options => {
|
||||
console.log(bdsCore);
|
||||
})
|
||||
.command(["start", "run", "$0"], "start server", yargs => yargs, async options => {})
|
||||
.parseAsync().catch(err => {
|
||||
console.log(err);
|
||||
process.exit(1);
|
||||
|
@ -172,4 +172,13 @@ export function getCacheVersions() {
|
||||
nukkit: Array.from(nukkitCache.keys()).reduce<{[k: string]: cloudburstDownload}>((acc, key) => {acc[key] = nukkitCache.get(key); return acc;}, {}),
|
||||
cloudburst: Array.from(cloudburstCache.keys()).reduce<{[k: string]: cloudburstDownload}>((acc, key) => {acc[key] = cloudburstCache.get(key); return acc;}, {}),
|
||||
};
|
||||
}
|
||||
|
||||
export async function syncCaches() {
|
||||
await Promise.all([
|
||||
listMojang(),
|
||||
listCloudburstProject(),
|
||||
listPocketmineProject(),
|
||||
listPowernukkitProject()
|
||||
]);
|
||||
}
|
@ -15,19 +15,26 @@ import * as bedrockVersions from "./listVersion.js";
|
||||
|
||||
export type platforms = "mojang" | "pocketmine" | "powernukkit" | "nukkit" | "cloudburst";
|
||||
|
||||
export interface bedrockPorts { }
|
||||
export interface bedrockPorts {
|
||||
port: number;
|
||||
localListen?: string;
|
||||
};
|
||||
|
||||
export interface playerInfo {
|
||||
connected: boolean;
|
||||
banned: boolean;
|
||||
xuid?: string;
|
||||
historic: {
|
||||
action: "connected" | "spawned" | "disconnected";
|
||||
action: string;
|
||||
actionDate: Date;
|
||||
}[];
|
||||
};
|
||||
|
||||
class playerListen extends Map<string, playerInfo> {
|
||||
constructor() { super(); }
|
||||
constructor(origem?: Record<string, playerInfo>) {
|
||||
super(Object.keys(origem || {}).map(key => ([key, origem[key]])));
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return Array.from(this.keys()).reduce<{ [playerName: string]: playerInfo }>((acc, player) => {
|
||||
acc[player] = this.get(player);
|
||||
@ -35,10 +42,20 @@ class playerListen extends Map<string, playerInfo> {
|
||||
}, {});
|
||||
}
|
||||
|
||||
init(playerName: string): this {
|
||||
if (!(this.has(playerName))) {
|
||||
super.set(playerName, {
|
||||
banned: false,
|
||||
connected: false,
|
||||
historic: [],
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
updateState(playerName: string, state: playerInfo["historic"][number]["action"]) {
|
||||
const actionDate = new Date();
|
||||
if (!(this.has(playerName))) throw new Error("Set Player");
|
||||
const playerData = super.get(playerName);
|
||||
const playerData = this.init(playerName).get(playerName);
|
||||
if (state === "disconnected") playerData.connected = false; else playerData.connected = true;
|
||||
playerData.historic.push({ action: state, actionDate });
|
||||
super.set(playerName, playerData);
|
||||
@ -56,7 +73,8 @@ export function isBedrock(event: Bedrock<any>): event is Bedrock<any> {
|
||||
|
||||
export type bedrockEvents = defineEvents<{
|
||||
logLine(lineString: string): void;
|
||||
portListen(info: bedrockPorts): void
|
||||
portListen(info: bedrockPorts): void;
|
||||
installedVersion(serverVersion: string): void;
|
||||
}>;
|
||||
|
||||
export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
@ -65,12 +83,12 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
readonly platform: P;
|
||||
constructor(rootServer: string, platform: P) {
|
||||
super();
|
||||
if ((!(["mojang", "pocketmine", "powernukkit", "nukkit", "cloudburst"]).includes(platform))) throw new Error("Invalid platform");
|
||||
this.platform = platform;
|
||||
this.rootServer = rootServer;
|
||||
this.serverFolder = path.join(rootServer, "server");
|
||||
Object.defineProperty(this, "rootServer", { writable: false });
|
||||
Object.defineProperty(this, "serverFolder", { writable: false });
|
||||
if ((!(["mojang", "pocketmine", "powernukkit", "nukkit", "cloudburst"]).includes(platform))) throw new Error("Invalid platform");
|
||||
Object.defineProperty(this, "platform", { writable: false });
|
||||
}
|
||||
|
||||
@ -86,30 +104,35 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
backupFiles = await Promise.all(backupFiles.map(async file => { file.data = await fs.readFile(path.join(this.serverFolder, file.file), "utf8").catch(() => ""); return file }));
|
||||
await finished((await http.streamRequest(serverURL)).pipe(tar.extract({ cwd: this.serverFolder, preserveOwner: true, keep: false })));
|
||||
await Promise.all(backupFiles.filter(file => !!(file.data.trim())).map(async file => fs.writeFile(path.join(this.serverFolder, file.file), file.data)));
|
||||
this.emit("installedVersion", bedrockVersions.mojangCache.prettyVersion(version));
|
||||
} else if (platform === "pocketmine") {
|
||||
const release = bedrockVersions.pocketmineCache.get(version);
|
||||
if (!release) throw new Error("Not valid Release");
|
||||
await finished(await http.streamRequest(release.url), createWriteStream(path.join(this.serverFolder, "server.phar")));
|
||||
await finished((await http.streamRequest(release.url)).pipe(createWriteStream(path.join(this.serverFolder, "server.phar"))));
|
||||
let phpFiles = (await bdsFilesBucket.listFiles("php_bin/")).map(file => ({ name: file.name.slice(8).toLowerCase(), data: file })).filter(file => file.name.startsWith(`${process.platform}_${process.arch}`));
|
||||
if (!phpFiles.length) throw new Error("Cannot get php binary to current platform");
|
||||
const phpFile = phpFiles.sort((b, a) => b.data.Dates.Modified.getTime() - a.data.Dates.Modified.getTime()).at(0);
|
||||
await fs.rm(path.join(this.serverFolder, "bin"), { recursive: true, force: true });
|
||||
if (phpFile.name.endsWith(".tar.gz") || phpFile.name.endsWith(".tgz")) await finished((await phpFile.data.getFile()).pipe(tar.extract({ cwd: path.join(this.serverFolder, "bin") })));
|
||||
else {
|
||||
const phpFile = phpFiles.sort((b, a) => a.data.Dates.Modified.getTime() - b.data.Dates.Modified.getTime()).at(0);
|
||||
const binPath = path.join(this.serverFolder, "bin");
|
||||
if (await extendsFS.exists(binPath)) await fs.rm(binPath, { recursive: true, force: true });
|
||||
if (phpFile.name.endsWith(".tar.gz") || phpFile.name.endsWith(".tgz")) await finished((await phpFile.data.getFile()).pipe(tar.extract({ cwd: binPath })));
|
||||
else if (phpFile.name.endsWith(".zip")) {
|
||||
const tmpFile = path.join(tmpdir(), Date.now() + "_" + phpFile.name);
|
||||
await finished((await phpFile.data.getFile()).pipe(createWriteStream(tmpFile)));
|
||||
await new Promise<void>((done, reject) => (new AdmZip(tmpFile)).extractAllToAsync(path.join(this.serverFolder, "bin"), true, true, err => err ? reject(err) : done()));
|
||||
await new Promise<void>((done, reject) => (new AdmZip(tmpFile)).extractAllToAsync(binPath, true, true, err => err ? reject(err) : done()));
|
||||
await fs.rm(tmpFile, { force: true });
|
||||
}
|
||||
this.emit("installedVersion", bedrockVersions.pocketmineCache.prettyVersion(version));
|
||||
} else if (platform === "powernukkit") {
|
||||
const release = bedrockVersions.powernukkitCache.get(version);
|
||||
if (!release) throw new Error("Not valid Release");
|
||||
await finished(await http.streamRequest(release.url), createWriteStream(path.join(this.serverFolder, "server.jar")));
|
||||
this.emit("installedVersion", bedrockVersions.powernukkitCache.prettyVersion(version));
|
||||
} else if (platform === "cloudburst" || platform === "nukkit") {
|
||||
const platformVersions = platform === "cloudburst" ? bedrockVersions.cloudburstCache : bedrockVersions.nukkitCache;
|
||||
const release = platformVersions.get(version);
|
||||
if (!release) throw new Error("Not valid Release");
|
||||
await finished(await http.streamRequest(release.url), createWriteStream(path.join(this.serverFolder, "server.jar")));
|
||||
this.emit("installedVersion", platformVersions.prettyVersion(version));
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,8 +142,74 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
serverProcess?: child_process.ChildProcess;
|
||||
async runServer() {
|
||||
const { platform } = this;
|
||||
if (platform === "nukkit" || platform === "powernukkit" || platform === "cloudburst") {
|
||||
const serverProcess = this.serverProcess = child_process.spawn("java", [
|
||||
const logLine: (bedrockEvents["logLine"])[] = [];
|
||||
|
||||
if (platform === "mojang") {
|
||||
const fileExec = path.join(this.serverFolder, (await fs.readdir(this.serverFolder)).find(file => file.startsWith("bedrock_server")));
|
||||
if (process.platform !== "win32") await fs.chmod(fileExec, 0o775);
|
||||
this.serverProcess = child_process.spawn(fileExec, {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"]
|
||||
});
|
||||
logLine.push(lineString => {
|
||||
// [INFO] IPv4 supported, port: 19132
|
||||
// [2023-03-08 13:01:57 INFO] Listening on IPv4 port: 19132
|
||||
const ipProtocol = lineString.slice(lineString.indexOf("IPv"), lineString.indexOf("IPv")+4);
|
||||
if (ipProtocol) {
|
||||
let port = lineString.slice(lineString.lastIndexOf("port:")+5).trim();
|
||||
if (port.indexOf(":") !== -1) port = port.slice(0, port.lastIndexOf(":"));
|
||||
const info: bedrockPorts = {
|
||||
port: Number(port),
|
||||
localListen: ipProtocol.toLowerCase() === "ipv4" ? "0.0.0.0" : "[::]",
|
||||
};
|
||||
this.ports.push(info);
|
||||
this.emit("portListen", info);
|
||||
}
|
||||
return null;
|
||||
}, lineString => {
|
||||
lineString = lineString.replace(/^(.*)?\[.*\]/, "").trim();
|
||||
if (lineString.startsWith("Player")) {
|
||||
lineString = lineString.replace("Player", "").trim();
|
||||
|
||||
// Spawned, disconnected, connected
|
||||
let action: string;
|
||||
if (lineString.startsWith("Spawned")) action = "Spawned";
|
||||
else if (lineString.startsWith("disconnected")) action = "disconnected";
|
||||
else if (lineString.startsWith("connected")) action = "connected";
|
||||
if (!action) return null;
|
||||
lineString = lineString.replace(action, "").trim();
|
||||
if (lineString.startsWith(":")) lineString = lineString.slice(1).trim();
|
||||
|
||||
let playerName = lineString.substring(0, lineString.indexOf("xuid:")-1).trim();
|
||||
if (!playerName) return null;
|
||||
if (playerName.endsWith(",")) playerName = playerName.slice(0, playerName.length - 1);
|
||||
|
||||
let xuid: string;
|
||||
if (lineString.indexOf("xuid:") !== -1) {
|
||||
xuid = lineString.slice(lineString.indexOf("xuid:")+5).trim();
|
||||
if (!xuid) xuid = null;
|
||||
}
|
||||
|
||||
if (!(this.players.has(playerName))) this.players.init(playerName);
|
||||
if (!!xuid) {
|
||||
if (!(this.players.get(playerName)).xuid) {
|
||||
const info = this.players.get(playerName);
|
||||
info.xuid = xuid;
|
||||
this.players.set(playerName, info);
|
||||
}
|
||||
}
|
||||
this.players.updateState(playerName, action);
|
||||
}
|
||||
});
|
||||
} else if (platform === "pocketmine") {
|
||||
const phpBin = (await extendsFS.readdirV2(this.serverFolder)).find(file => file.endsWith("php") || file.endsWith("php.exe"));
|
||||
if (!phpBin) throw new Error("Fist install php binary in server folder");
|
||||
this.serverProcess = child_process.spawn(phpBin, ["server.phar", "--no-wizard"], {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
} else if (platform === "nukkit" || platform === "powernukkit" || platform === "cloudburst") {
|
||||
this.serverProcess = child_process.spawn("java", [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
@ -146,46 +235,35 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
serverProcess;
|
||||
} else if (platform === "pocketmine") {
|
||||
const phpBin = (await extendsFS.readdirV2(this.serverFolder)).find(file => file.endsWith("php")||file.endsWith("php.exe"));
|
||||
if (!phpBin) throw new Error("Fist install php binary in server folder");
|
||||
this.serverProcess = child_process.spawn(phpBin, ["server.phar", "--no-wizard"], {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
} else if (platform === "mojang") {
|
||||
const fileExec = path.join(this.serverFolder, (await fs.readdir(this.serverFolder)).find(file => file.startsWith("bedrock_server")));
|
||||
const serverProcess = this.serverProcess = child_process.spawn(fileExec, {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"]
|
||||
});
|
||||
serverProcess;
|
||||
}
|
||||
|
||||
// Break lines
|
||||
([
|
||||
readline.createInterface(this.serverProcess.stdout),
|
||||
readline.createInterface(this.serverProcess.stderr)
|
||||
]).map(inter => inter.on("error", err => this.emit("error", err)).on("line", data => this.emit("logLine", typeof data === "string" ? data : data[0])));
|
||||
]).map(inter => inter.on("error", err => this.emit("error", err)).on("line", data => {
|
||||
this.emit("logLine", data);
|
||||
logLine.forEach(fn => Promise.resolve().then(() => fn(data)).catch(err => this.emit("error", err)));
|
||||
}));
|
||||
|
||||
return this.serverProcess;
|
||||
}
|
||||
|
||||
writeLn(data: string|Buffer) {
|
||||
writeLn(data: string | Buffer) {
|
||||
this.serverProcess.stdin.write(data);
|
||||
if (typeof data === "string" && !(data.trim().endsWith("\n"))) this.serverProcess.stdin.write("\n");
|
||||
if (Buffer.isBuffer(data) && (String.fromCharCode(data.at(-1)) !== "\n")) this.serverProcess.stdin.write("\n");
|
||||
else if (typeof data === "string" && !(data.trim().endsWith("\n"))) this.serverProcess.stdin.write("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
async stopServer() {
|
||||
this.writeLn("stop");
|
||||
return new Promise<{code: number, signal: NodeJS.Signals}>((done, reject) => this.serverProcess.once("error", reject).once("exit", (code, signal) => done({code, signal})));
|
||||
return new Promise<{ code: number, signal: NodeJS.Signals }>((done, reject) => this.serverProcess.once("error", reject).once("exit", (code, signal) => done({ code, signal })));
|
||||
}
|
||||
|
||||
async setPlayerPermission(playername: string, permission: P extends "mojang" ? "operator"|"member"|"visitor" : "admin"|"user") {
|
||||
async setPlayerPermission(playername: string, permission: P extends "mojang" ? "operator" | "member" | "visitor" : "admin" | "user") {
|
||||
if (this.platform === "mojang") {
|
||||
const permissions: {permission: "operator"|"member"|"visitor", xuid: string}[] = JSON.parse(await fs.readFile(path.join(this.serverFolder, "permissions.json"), "utf8"));
|
||||
const permissions: { permission: "operator" | "member" | "visitor", xuid: string }[] = JSON.parse(await fs.readFile(path.join(this.serverFolder, "permissions.json"), "utf8"));
|
||||
permissions.push({
|
||||
permission: permission as any,
|
||||
xuid: playername
|
||||
@ -195,9 +273,9 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
||||
}
|
||||
}
|
||||
|
||||
async allowList(playername: string, options?: {xuid?: string, ignoresPlayerLimit?: boolean}) {
|
||||
async allowList(playername: string, options?: { xuid?: string, ignoresPlayerLimit?: boolean }) {
|
||||
if (this.platform === "mojang") {
|
||||
const permissions: {ignoresPlayerLimit: boolean, name: string, xuid?: string}[] = JSON.parse(await fs.readFile(path.join(this.serverFolder, "allowlist.json"), "utf8"));
|
||||
const permissions: { ignoresPlayerLimit: boolean, name: string, xuid?: string }[] = JSON.parse(await fs.readFile(path.join(this.serverFolder, "allowlist.json"), "utf8"));
|
||||
await fs.writeFile(path.join(this.serverFolder, "allowlist.json"), JSON.stringify(permissions));
|
||||
permissions.push({
|
||||
name: playername,
|
||||
|
@ -1 +1,2 @@
|
||||
export * as listVersion from "./listVersion.js";
|
||||
export * as listVersion from "./listVersion.js";
|
||||
export * from "./main.js";
|
@ -1,8 +1,9 @@
|
||||
import { Github, http } from "@sirherobrine23/http";
|
||||
import stream from "node:stream";
|
||||
import semver from "semver";
|
||||
import path from "path";
|
||||
import semver from "semver";
|
||||
import { bdsFilesBucket } from "../../internalClouds.js";
|
||||
import { versionsStorages } from "../../serverRun.js";
|
||||
|
||||
interface baseDownload {
|
||||
URL: string;
|
||||
@ -28,7 +29,7 @@ async function PromiseSplit<T extends (any[])>(arrayInput: T, fn: (value: T[numb
|
||||
return result.flat(1);
|
||||
}
|
||||
|
||||
export const mojangCache = new Map<string, mojangInfo>();
|
||||
export const mojangCache = new versionsStorages<mojangInfo>();
|
||||
export async function listMojang() {
|
||||
const versions = (await http.jsonRequestBody<{ versions: { id: string, releaseTime: string, url: string, type: "snapshot" | "release" | "old_beta" | "old_alpha" }[] }>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json")).versions;
|
||||
await PromiseSplit(versions, async version => {
|
||||
@ -48,7 +49,7 @@ export interface spigotDownload {
|
||||
craftbukkit?(): Promise<stream.Readable>;
|
||||
}
|
||||
|
||||
const spigotCache = new Map<string, spigotDownload>();
|
||||
export const spigotCache = new versionsStorages<spigotDownload>();
|
||||
export async function listSpigot() {
|
||||
const spigotFiles = await bdsFilesBucket.listFiles("SpigotBuild/");
|
||||
for (const file of spigotFiles.filter(file => file.name.slice(12).startsWith("1.")).sort((b, a) => {
|
||||
@ -65,9 +66,9 @@ export async function listSpigot() {
|
||||
}
|
||||
}
|
||||
|
||||
export const paperCache = new Map<string, baseDownload>();
|
||||
export const velocityCache = new Map<string, baseDownload>();
|
||||
export const foliaCache = new Map<string, baseDownload>();
|
||||
export const paperCache = new versionsStorages<baseDownload>();
|
||||
export const velocityCache = new versionsStorages<baseDownload>();
|
||||
export const foliaCache = new versionsStorages<baseDownload>();
|
||||
export async function listPaperProject() {
|
||||
const paperProjects = ["paper", "velocity", "folia"] as const;
|
||||
await Promise.all(paperProjects.map(async projectName => {
|
||||
@ -96,7 +97,7 @@ export async function listPaperProject() {
|
||||
}));
|
||||
}
|
||||
|
||||
export const purpurCache = new Map<string, baseDownload>();
|
||||
export const purpurCache = new versionsStorages<baseDownload>();
|
||||
export async function listPurpurProject() {
|
||||
const baseURL = new URL("https://api.purpurmc.org/v2/purpur");
|
||||
const { versions } = await http.jsonRequestBody<{ versions: string[] }>(baseURL);
|
||||
@ -111,7 +112,7 @@ export async function listPurpurProject() {
|
||||
}
|
||||
}
|
||||
|
||||
export const glowstoneCache = new Map<string, baseDownload>();
|
||||
export const glowstoneCache = new versionsStorages<baseDownload>();
|
||||
export async function listGlowstoneProject() {
|
||||
const repo = await Github.repositoryManeger("GlowstoneMC", "Glowstone");
|
||||
const rels = (await repo.release.getRelease()).filter(rel => rel.assets.some(asset => asset.name.endsWith(".jar")));
|
||||
@ -121,20 +122,14 @@ export async function listGlowstoneProject() {
|
||||
})));
|
||||
}
|
||||
|
||||
export const cuberiteCache = new Map<string, { URL: string[] }>([
|
||||
[
|
||||
"win32-x64",
|
||||
{
|
||||
URL: ["https://download.cuberite.org/windows-x86_64/Cuberite.zip"]
|
||||
}
|
||||
],
|
||||
[
|
||||
"win32-ia32",
|
||||
{
|
||||
URL: ["https://download.cuberite.org/windows-i386/Cuberite.zip"]
|
||||
}
|
||||
]
|
||||
]);
|
||||
export const cuberiteCache = new versionsStorages<{ URL: string[] }>({
|
||||
"win32-x64": {
|
||||
URL: ["https://download.cuberite.org/windows-x86_64/Cuberite.zip"]
|
||||
},
|
||||
"win32-ia32": {
|
||||
URL: ["https://download.cuberite.org/windows-i386/Cuberite.zip"]
|
||||
}
|
||||
});
|
||||
export async function listCuberite() {
|
||||
const projects = ["android", "linux-aarch64", "linux-armhf", "linux-i386", "linux-x86_64", "darwin-x86_64"] as const;
|
||||
await Promise.all(projects.map(async project => {
|
||||
@ -143,7 +138,13 @@ export async function listCuberite() {
|
||||
const { artifacts = [], result } = await http.jsonRequestBody<{ result: string, artifacts: { relativePath: string, fileName: string }[] }>(`https://builds.cuberite.org/job/${project}/${job.number}/api/json`);
|
||||
if (result !== "SUCCESS") continue;
|
||||
let map = artifacts.filter(file => !file.fileName.endsWith(".sha1")).map(file => `https://builds.cuberite.org/job/${project}/${job.number}/artifact/${file.relativePath}`);
|
||||
if (project === "android") {
|
||||
if (!map.length) continue;
|
||||
else if (project === "darwin-x86_64") cuberiteCache.set("darwin-x64", { URL: map });
|
||||
else if (project === "linux-x86_64") cuberiteCache.set("linux-x64", { URL: map });
|
||||
else if (project === "linux-aarch64") cuberiteCache.set("linux-arm64", { URL: map });
|
||||
else if (project === "linux-armhf") cuberiteCache.set("linux-arm", { URL: map });
|
||||
else if (project === "linux-i386") cuberiteCache.set("linux-ia32", { URL: map });
|
||||
else if (project === "android") {
|
||||
const serverIndex = map.findIndex(file => file.toLowerCase().endsWith("server.zip"));
|
||||
const server = map[serverIndex];
|
||||
delete map[serverIndex];
|
||||
@ -156,8 +157,19 @@ export async function listCuberite() {
|
||||
else if (plat.startsWith("arm64")) cuberiteCache.set("android-arm64", { URL: [server, file] });
|
||||
else if (plat.startsWith("arm")) cuberiteCache.set("android-arm", { URL: [server, file] });
|
||||
}
|
||||
} else cuberiteCache.set(project, { URL: map });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
export async function syncCaches() {
|
||||
await Promise.all([
|
||||
listMojang(),
|
||||
listSpigot(),
|
||||
listPaperProject(),
|
||||
listPurpurProject(),
|
||||
listGlowstoneProject(),
|
||||
listCuberite(),
|
||||
]);
|
||||
}
|
143
packages/core/src/platform/java/main.ts
Normal file
143
packages/core/src/platform/java/main.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { extendsFS } from "@sirherobrine23/extends";
|
||||
import { http } from "@sirherobrine23/http";
|
||||
import AdmZip from "adm-zip";
|
||||
import child_process from "node:child_process";
|
||||
import { createWriteStream } from "node:fs";
|
||||
import fs from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import readline from "node:readline";
|
||||
import { finished } from "node:stream/promises";
|
||||
import tar from "tar";
|
||||
import { customEvent, defineEvents } from "../../serverRun.js";
|
||||
import * as javaVersions from "./listVersion.js";
|
||||
|
||||
export type platform = "mojang" | "spigot" | "paper" | "purpur" | "glowstone" | "folia" | "cuberite";
|
||||
export type javaEvents = defineEvents<{
|
||||
logLine(lineString: string): void;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Return boolean if Class input is Java class server
|
||||
* @param event - Java class
|
||||
* @returns
|
||||
*/
|
||||
export function isJava(event: Java<any>): event is Java<any> {
|
||||
return event instanceof Java;
|
||||
}
|
||||
|
||||
export class Java<P extends platform> extends customEvent<javaEvents> {
|
||||
readonly serverFolder: string;
|
||||
readonly rootServer: string;
|
||||
readonly platform: P;
|
||||
constructor(rootServer: string, platform: P) {
|
||||
super();
|
||||
if ((!(["mojang", "spigot", "paper", "purpur", "glowstone", "folia", "cuberite"]).includes(platform))) throw new Error("Invalid platform");
|
||||
this.platform = platform;
|
||||
this.rootServer = rootServer;
|
||||
this.serverFolder = path.join(rootServer, "server");
|
||||
Object.defineProperty(this, "rootServer", { writable: false });
|
||||
Object.defineProperty(this, "serverFolder", { writable: false });
|
||||
Object.defineProperty(this, "platform", { writable: false });
|
||||
}
|
||||
|
||||
async installServer(version: string | number) {
|
||||
const { platform } = this;
|
||||
if (!(await extendsFS.exists(this.serverFolder))) await fs.mkdir(this.serverFolder, { recursive: true });
|
||||
if (platform === "mojang") {
|
||||
if (!javaVersions.mojangCache.size) await javaVersions.listMojang();
|
||||
await finished((await http.streamRequest(javaVersions.mojangCache.get(version).URL)).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
} else if (platform === "spigot") {
|
||||
if (!javaVersions.spigotCache.size) await javaVersions.listSpigot();
|
||||
const spigotRel = javaVersions.spigotCache.get(version);
|
||||
await finished((await spigotRel.getServer()).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
if (typeof spigotRel.craftbukkit === "function") await finished((await spigotRel.craftbukkit()).pipe(createWriteStream(path.join(this.serverFolder, "craftbukkit.jar"))));
|
||||
} else if (platform === "paper") {
|
||||
if (!javaVersions.paperCache.size) await javaVersions.listPaperProject();
|
||||
await finished((await http.streamRequest(javaVersions.paperCache.get(version).URL)).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
} else if (platform === "purpur") {
|
||||
if (!javaVersions.purpurCache.size) await javaVersions.listPaperProject();
|
||||
await finished((await http.streamRequest(javaVersions.purpurCache.get(version).URL)).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
} else if (platform === "glowstone") {
|
||||
if (!javaVersions.glowstoneCache.size) await javaVersions.listPaperProject();
|
||||
await finished((await http.streamRequest(javaVersions.glowstoneCache.get(version).URL)).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
} else if (platform === "folia") {
|
||||
if (!javaVersions.foliaCache.size) await javaVersions.listGlowstoneProject();
|
||||
await finished((await http.streamRequest(javaVersions.foliaCache.get(version).URL)).pipe(createWriteStream(path.join(this.serverFolder, "server.jar"))));
|
||||
} else if (platform === "cuberite") {
|
||||
if (javaVersions.cuberiteCache.size < 3) await javaVersions.listCuberite();
|
||||
const files = javaVersions.cuberiteCache.get(`${process.platform}-${process.arch}`).URL;
|
||||
for (const fileURL of files) {
|
||||
if (fileURL.endsWith(".zip")) {
|
||||
const tmpFile = path.join(tmpdir(), Date.now() + "_" + path.basename((new URL(fileURL)).pathname));
|
||||
await finished((await http.streamRequest(fileURL)).pipe(createWriteStream(tmpFile)));
|
||||
await new Promise<void>((done, reject) => (new AdmZip(tmpFile)).extractAllToAsync(this.serverFolder, true, true, err => err ? reject(err) : done()));
|
||||
await fs.rm(tmpFile, { force: true });
|
||||
} else await finished((await http.streamRequest(fileURL)).pipe(tar.extract({cwd: this.serverFolder})));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serverProcess?: child_process.ChildProcess;
|
||||
async runServer() {
|
||||
if (this.platform === "cuberite") {
|
||||
let execPath = path.join(this.serverFolder, "Cuberite");
|
||||
if (process.platform === "win32") execPath += ".exe";
|
||||
this.serverProcess = child_process.spawn(execPath, {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
} else {
|
||||
this.serverProcess = child_process.spawn("java", [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+DisableExplicitGC",
|
||||
"-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30",
|
||||
"-XX:G1MaxNewSizePercent=40",
|
||||
"-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20",
|
||||
"-XX:G1HeapWastePercent=5",
|
||||
"-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||
"-XX:SurvivorRatio=32",
|
||||
"-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1",
|
||||
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true",
|
||||
"-jar", "server.jar",
|
||||
], {
|
||||
cwd: this.serverFolder,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
}
|
||||
|
||||
// Break line
|
||||
([
|
||||
readline.createInterface(this.serverProcess.stdout),
|
||||
readline.createInterface(this.serverProcess.stderr),
|
||||
]).forEach(readline => readline.on("error", err => this.emit("error", err)).on("line", line => this.emit("logLine", line)));
|
||||
|
||||
this.on("logLine", (line) => {
|
||||
line = line.replace(/^.*?\[.*\]:/, "").trim();
|
||||
if (line.startsWith("Starting Minecraft server on")) {
|
||||
if (line.lastIndexOf(":") === -1) return null;
|
||||
// const port = Number(line.slice(line.lastIndexOf(":")+1));
|
||||
// this.emit("portListen", {
|
||||
// port,
|
||||
// localListen: "0.0.0.0"
|
||||
// });
|
||||
// this.ports.push({
|
||||
// port,
|
||||
// localListen: "0.0.0.0"
|
||||
// });
|
||||
}
|
||||
});
|
||||
|
||||
return this.serverProcess;
|
||||
}
|
||||
}
|
@ -5,4 +5,5 @@ export { isBedrock } from "./platform/bedrock/index.js";
|
||||
|
||||
// Java platform
|
||||
export * as Java from "./platform/java/index.js";
|
||||
export * as java from "./platform/java/index.js";
|
||||
export * as java from "./platform/java/index.js";
|
||||
export { isJava } from "./platform/java/index.js";
|
@ -1,58 +1,70 @@
|
||||
import EventEmitter from "node:events";
|
||||
|
||||
export type EventMap = Record<string, (...args: any[]) => void>;
|
||||
export type defineEvents<T extends EventMap> = T;
|
||||
type EventKey<T extends EventMap> = string & keyof T;
|
||||
|
||||
export type defineEvents<T extends EventMap> = T;
|
||||
export interface customEvent<T extends EventMap> extends EventEmitter {
|
||||
emit<K extends EventKey<T>>(eventName: K, ...args: Parameters<T[K]>): boolean;
|
||||
emit(name: "error", err: Error): boolean;
|
||||
|
||||
on<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
on(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
prependListener<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
prependListener(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
once<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
once(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
prependOnceListener<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
prependOnceListener(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
removeListener<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
removeListener(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
off<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
off(eventName: "error", fn: (err: Error) => void): this;
|
||||
|
||||
removeAllListeners<K extends EventKey<T>>(eventName: K): this;
|
||||
removeAllListeners(eventName: "error"): this;
|
||||
|
||||
rawListeners<K extends EventKey<T>>(eventName: K): (T[K])[];
|
||||
rawListeners(eventName: "error"): ((err: Error) => void)[];
|
||||
|
||||
eventNames(): (EventKey<T> | "error")[];
|
||||
}
|
||||
|
||||
export class customEvent<T extends EventMap> extends EventEmitter {
|
||||
constructor() {
|
||||
super({captureRejections: true});
|
||||
}
|
||||
on<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
on(eventName: "error", fn: (err: Error) => void): this;
|
||||
on(eventName: string, fn: (...args: any) => void): this {
|
||||
super.on(eventName, fn);
|
||||
return this;
|
||||
}
|
||||
|
||||
once<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
once(eventName: "error", fn: (err: Error) => void): this;
|
||||
once(eventName: string, fn: (...args: any) => void): this {
|
||||
super.once(eventName, fn);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeListener<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
removeListener(eventName: "error", fn: (err: Error) => void): this;
|
||||
removeListener(eventName: string, listener: (...args: any[]) => void): this {
|
||||
super.removeListener(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
off<K extends EventKey<T>>(eventName: K, fn: T[K]): this;
|
||||
off(eventName: "error", fn: (err: Error) => void): this;
|
||||
off(eventName: string, listener: (...args: any[]) => void): this {
|
||||
super.off(eventName, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
removeAllListeners<K extends EventKey<T>>(eventName: K): this;
|
||||
removeAllListeners(event?: string): this {
|
||||
super.removeAllListeners(event);
|
||||
return this;
|
||||
}
|
||||
|
||||
emit<K extends EventKey<T>>(eventName: K, ...args: Parameters<T[K]>): boolean;
|
||||
emit(name: "error", err: Error): boolean;
|
||||
emit(eventName: string, ...args: any): boolean {
|
||||
return super.emit(eventName, args);
|
||||
}
|
||||
};
|
||||
|
||||
export class versionsStorages<T> extends Map<string, T> {
|
||||
get(key: string|number): T {
|
||||
if (typeof key === "number") return super.get(Array.from(this.keys()).at(key));
|
||||
return super.get(key);
|
||||
constructor(origem: Record<string, T> = {}) {
|
||||
super(Object.keys(origem).map(key => ([key, origem[key]])));
|
||||
}
|
||||
|
||||
prettyVersion(serverVersion: string|number): string {
|
||||
const checkIsNumber = (arg0: string|number) => typeof arg0 === "number" ? arg0 : Number(arg0).toString() === arg0 ? Number(arg0) : arg0;
|
||||
serverVersion = checkIsNumber(serverVersion);
|
||||
if (typeof serverVersion === "number") return Array.from(this.keys()).at(serverVersion);
|
||||
return serverVersion;
|
||||
}
|
||||
|
||||
get(serverVersion: string|number): T {
|
||||
return super.get(this.prettyVersion(serverVersion));
|
||||
}
|
||||
|
||||
has(serverVersion: string|number): boolean {
|
||||
return super.has(this.prettyVersion(serverVersion));
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return Array.from(super.keys()).reduce<{[version: string]: T}>((acc, key) => {
|
||||
acc[key] = super.get(key);
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import path from "node:path";
|
||||
import { listVersion, Bedrock } from "../src/platform/bedrock/index.js";
|
||||
import { homedir } from "node:os";
|
||||
await listVersion.listMojang();
|
||||
|
||||
const mojang = new Bedrock(path.join(homedir(), ".bdsmaneger/playgroud/mojang"), "mojang");
|
||||
const version = Array.from(listVersion.mojangCache.keys()).at(9);
|
||||
console.log("Installing %s", version);
|
||||
await mojang.installServer(version);
|
||||
mojang.on("logLine", (line) => console.log(line[0]));
|
||||
const pr = await mojang.runServer();
|
||||
const server = new Bedrock(path.join(homedir(), ".bdsmaneger/playgroud/mojang"), "pocketmine");
|
||||
server.once("installedVersion", version => console.log("Installed %s server", version));
|
||||
await listVersion.listPocketmineProject();
|
||||
console.log("Init install");
|
||||
await server.installServer(0);
|
||||
server.on("logLine", (line) => console.log(line[0]));
|
||||
const pr = await server.runServer();
|
||||
process.stdin.pipe(pr.stdin);
|
11
packages/core/tests/java.ts
Normal file
11
packages/core/tests/java.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import path from "node:path";
|
||||
import { Java } from "../src/platform/java/index.js";
|
||||
import { homedir } from "node:os";
|
||||
import { rm } from "node:fs/promises";
|
||||
|
||||
await rm(path.join(homedir(), ".bdsmaneger/playgroud/java"), { recursive: true }).catch(() => {});
|
||||
const server = new Java(path.join(homedir(), ".bdsmaneger/playgroud/java"), "cuberite");
|
||||
await server.installServer(0);
|
||||
server.on("logLine", line => console.log(line));
|
||||
const run = await server.runServer();
|
||||
process.stdin.pipe(run.stdin);
|
7
packages/verapi/.dockerignore
Normal file
7
packages/verapi/.dockerignore
Normal file
@ -0,0 +1,7 @@
|
||||
# Node
|
||||
node_modules/
|
||||
|
||||
# Typescript
|
||||
**/*.js
|
||||
**/*.d.ts
|
||||
**/*.tsbuildinfo
|
@ -1,133 +1,186 @@
|
||||
#!/usr/bin/env node
|
||||
import { Java, Bedrock } from "@the-bds-maneger/core";
|
||||
import { createServer } from "node:http";
|
||||
import { Bedrock, Java } from "@the-bds-maneger/core";
|
||||
import express from "express";
|
||||
import expressLayer from "express/lib/router/layer.js";
|
||||
import { createServer } from "node:http";
|
||||
import { format } from "node:util";
|
||||
|
||||
process.on("unhandledRejection", err => console.error(err));
|
||||
|
||||
expressLayer.prototype.handle_request = async function handle_request_promised(...args) {
|
||||
var fn = this.handle;
|
||||
if (fn.length > 3) return args.at(-1)();
|
||||
await Promise.resolve().then(() => fn.call(this, ...args)).catch(args.at(-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} nextTime
|
||||
*/
|
||||
function printDate(nextTime = 0) {
|
||||
const dd = new Date(Date.now() + nextTime);
|
||||
return format("%f/%f/%f %f:%f:%f", dd.getDate(), dd.getMonth() + 1, dd.getFullYear(), dd.getMinutes(), dd.getHours(), dd.getSeconds());
|
||||
}
|
||||
|
||||
const interval = 1000 * 60 * 60 * 2;
|
||||
console.log("Initial versions");
|
||||
await Promise.all([Bedrock.listVersion.syncCaches(), Java.listVersion.syncCaches()]);
|
||||
console.log("Next sync in", printDate(interval));
|
||||
setInterval(async () => {
|
||||
console.log("Sync versions");
|
||||
await Promise.all([Bedrock.listVersion.syncCaches(), Java.listVersion.syncCaches()]);
|
||||
console.log("Next sync in", printDate(interval));
|
||||
}, interval);
|
||||
|
||||
const app = express();
|
||||
app.use((req, res, next) => {
|
||||
if (!(req.query.pretty === "off" || req.query.pretty === "false")) {
|
||||
res.json = (body) => res.setHeader("Content-Type", "application/json").send(JSON.stringify(body, null, 2));
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
const server = createServer(app);
|
||||
server.listen(Number(process.env.PORT || 3000), () => {
|
||||
const addr = server.address();
|
||||
console.log("Listening on http://localhost:%f", Number(typeof addr === "object" ? addr.port : addr));
|
||||
if (typeof addr === "string") console.log("Server listen on socket %O path", addr);
|
||||
else if (typeof addr === "number") console.log("Listening on http://localhost:%f", addr);
|
||||
else if (typeof addr === "object") console.log("Listen on http://localhost:%s", addr?.port);
|
||||
});
|
||||
|
||||
// Bedrock
|
||||
const bedrockRoute = express.Router();
|
||||
app.use("/bedrock", bedrockRoute);
|
||||
const bedrockStash = {};
|
||||
bedrockRoute.get("/", async ({res}) => {
|
||||
const bedrockOficial = (await (async () => {if (bedrockStash["oficial"]) return bedrockStash["oficial"];bedrockStash["oficial"] = await Bedrock.listVersions();setTimeout(() => delete bedrockStash["oficial"], 60000);return bedrockStash["oficial"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
const cloudbust = (await (async () => {if (bedrockStash["cloudbust"]) return bedrockStash["cloudbust"];bedrockStash["cloudbust"] = await Bedrock.listVersions("cloudbust");setTimeout(() => delete bedrockStash["cloudbust"], 60000);return bedrockStash["cloudbust"];})()).at(0);
|
||||
const nukkit = (await (async () => {if (bedrockStash["nukkit"]) return bedrockStash["nukkit"];bedrockStash["nukkit"] = await Bedrock.listVersions("nukkit");setTimeout(() => delete bedrockStash["nukkit"], 60000);return bedrockStash["nukkit"];})()).at(0);
|
||||
const powernukkit = (await (async () => {if (bedrockStash["powernukkit"]) return bedrockStash["powernukkit"];bedrockStash["powernukkit"] = await Bedrock.listVersions("powernukkit");setTimeout(() => delete bedrockStash["powernukkit"], 60000);return bedrockStash["powernukkit"];})()).at(0);
|
||||
const pocketmine = (await (async () => {if (bedrockStash["pocketmine"]) return bedrockStash["pocketmine"];bedrockStash["pocketmine"] = await Bedrock.listVersions("pocketmine");setTimeout(() => delete bedrockStash["pocketmine"], 60000);return bedrockStash["pocketmine"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
|
||||
bedrockRoute.get("/", async ({ res }) => {
|
||||
return res.json({
|
||||
bedrockOficial,
|
||||
pocketmine,
|
||||
cloudbust,
|
||||
nukkit,
|
||||
powernukkit
|
||||
bedrockOficial: Bedrock.listVersion.mojangCache,
|
||||
pocketmine: Bedrock.listVersion.pocketmineCache,
|
||||
cloudbust: Bedrock.listVersion.cloudburstCache,
|
||||
nukkit: Bedrock.listVersion.nukkitCache,
|
||||
powernukkit: Bedrock.listVersion.powernukkitCache
|
||||
});
|
||||
});
|
||||
|
||||
bedrockRoute.get("/((oficial|cloudbust|nukkit|nukkit|powernukkit|pocketmine))", async (req, res) => {
|
||||
let platform = req.params[0];
|
||||
if (!bedrockStash[platform]) {
|
||||
if (platform === "oficial") platform = null;
|
||||
bedrockStash[(platform === null ? "oficial" : platform)] = await Bedrock.listVersions(platform);
|
||||
setTimeout(() => delete bedrockStash[(platform === null ? "oficial" : platform)], 60000);
|
||||
}
|
||||
const list = bedrockStash[(platform === null ? "oficial" : platform)];
|
||||
/** @type {"oficial" | "cloudbust" | "nukkit" | "nukkit" | "powernukkit" | "pocketmine"} */
|
||||
const platform = req.params[0];
|
||||
const ver = String(req.query.v || req.query.version || "");
|
||||
if (ver) {
|
||||
const data = list.find(e => e.version === ver);
|
||||
if (!data) return res.status(400).json({error: "Not found version."});
|
||||
return res.json(data);
|
||||
if (platform === "oficial") {
|
||||
if (!ver) return res.json(Bedrock.listVersion.mojangCache.toJSON());
|
||||
else {
|
||||
if (!(Bedrock.listVersion.mojangCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Bedrock.listVersion.mojangCache.get(ver));
|
||||
}
|
||||
} else if (platform === "pocketmine") {
|
||||
if (!ver) return res.json(Bedrock.listVersion.pocketmineCache.toJSON());
|
||||
else {
|
||||
if (!(Bedrock.listVersion.pocketmineCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Bedrock.listVersion.pocketmineCache.get(ver));
|
||||
}
|
||||
} else if (platform === "nukkit") {
|
||||
if (!ver) return res.json(Bedrock.listVersion.nukkitCache.toJSON());
|
||||
else {
|
||||
if (!(Bedrock.listVersion.nukkitCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Bedrock.listVersion.nukkitCache.get(ver));
|
||||
}
|
||||
} else if (platform === "cloudbust") {
|
||||
if (!ver) return res.json(Bedrock.listVersion.cloudburstCache.toJSON());
|
||||
else {
|
||||
if (!(Bedrock.listVersion.cloudburstCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Bedrock.listVersion.cloudburstCache.get(ver));
|
||||
}
|
||||
} else if (platform === "powernukkit") {
|
||||
if (!ver) return res.json(Bedrock.listVersion.powernukkitCache.toJSON());
|
||||
else {
|
||||
if (!(Bedrock.listVersion.powernukkitCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Bedrock.listVersion.powernukkitCache.get(ver));
|
||||
}
|
||||
}
|
||||
return res.json(list);
|
||||
});
|
||||
|
||||
// Java
|
||||
const javaRoute = express.Router();
|
||||
app.use("/java", javaRoute);
|
||||
const javaStash = {};
|
||||
javaRoute.get("/", async ({res}) => {
|
||||
const javaOficial = (await (async () => {if (javaStash["oficial"]) return javaStash["oficial"]; javaStash["oficial"] = await Java.listVersions(); setTimeout(() => delete javaStash["oficial"], 6000); return javaStash["oficial"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
const spigot = (await (async () => {if (javaStash["spigot"]) return javaStash["spigot"]; javaStash["spigot"] = await Java.listVersions("spigot"); setTimeout(() => delete javaStash["spigot"], 6000); return javaStash["spigot"];})()).at(0);
|
||||
const paper = (await (async () => {if (javaStash["paper"]) return javaStash["paper"]; javaStash["paper"] = await Java.listVersions("paper"); setTimeout(() => delete javaStash["paper"], 6000); return javaStash["paper"];})()).at(0);
|
||||
const glowstone = (await (async () => {if (javaStash["glowstone"]) return javaStash["glowstone"]; javaStash["glowstone"] = await Java.listVersions("glowstone"); setTimeout(() => delete javaStash["glowstone"], 6000); return javaStash["glowstone"];})()).at(0);
|
||||
const purpur = (await (async () => {if (javaStash["purpur"]) return javaStash["purpur"]; javaStash["purpur"] = await Java.listVersions("purpur"); setTimeout(() => delete javaStash["purpur"], 6000); return javaStash["purpur"];})()).at(0);
|
||||
const folia = (await (async () => {if (javaStash["folia"]) return javaStash["folia"]; javaStash["folia"] = await Java.listVersions("folia"); setTimeout(() => delete javaStash["folia"], 6000); return javaStash["folia"];})()).at(0);
|
||||
const cuberite = (await (async () => {if (javaStash["cuberite"]) return javaStash["cuberite"]; javaStash["cuberite"] = await Java.listVersions("cuberite"); setTimeout(() => delete javaStash["cuberite"], 6000); return javaStash["cuberite"];})()).at(0);
|
||||
|
||||
javaRoute.get("/", async ({ res }) => {
|
||||
return res.json({
|
||||
javaOficial,
|
||||
spigot,
|
||||
paper,
|
||||
glowstone,
|
||||
purpur,
|
||||
folia,
|
||||
cuberite
|
||||
javaOficial: Java.listVersion.mojangCache,
|
||||
spigot: Java.listVersion.spigotCache,
|
||||
paper: Java.listVersion.paperCache,
|
||||
glowstone: Java.listVersion.glowstoneCache,
|
||||
purpur: Java.listVersion.purpurCache,
|
||||
folia: Java.listVersion.foliaCache,
|
||||
cuberite: Java.listVersion.cuberiteCache
|
||||
});
|
||||
});
|
||||
javaRoute.get("/((oficial|spigot|paper|purpur|glowstone|folia|cuberite))", async (req, res) => {
|
||||
let platform = req.params[0];
|
||||
if (!javaStash[platform]) {
|
||||
if (platform === "oficial") platform = null;
|
||||
javaStash[(platform === null ? "oficial" : platform)] = await Java.listVersions(platform);
|
||||
setTimeout(() => delete javaStash[(platform === null ? "oficial" : platform)], 60000);
|
||||
}
|
||||
const list = javaStash[(platform === null ? "oficial" : platform)];
|
||||
/** @type {"oficial" | "spigot" | "paper" | "purpur" | "glowstone" | "folia" | "cuberite"} */
|
||||
const platform = req.params[0];
|
||||
const ver = String(req.query.v || req.query.version || "");
|
||||
if (ver) {
|
||||
const data = list.find(e => e.version === ver);
|
||||
if (!data) return res.status(400).json({error: "Not found version."});
|
||||
return res.json(data);
|
||||
if (platform === "oficial") {
|
||||
if (!ver) return res.json(Java.listVersion.mojangCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.mojangCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.mojangCache.get(ver));
|
||||
}
|
||||
} else if (platform === "spigot") {
|
||||
if (!ver) return res.json(Java.listVersion.spigotCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.spigotCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.spigotCache.get(ver));
|
||||
}
|
||||
} else if (platform === "paper") {
|
||||
if (!ver) return res.json(Java.listVersion.paperCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.paperCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.paperCache.get(ver));
|
||||
}
|
||||
} else if (platform === "purpur") {
|
||||
if (!ver) return res.json(Java.listVersion.purpurCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.purpurCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.purpurCache.get(ver));
|
||||
}
|
||||
} else if (platform === "glowstone") {
|
||||
if (!ver) return res.json(Java.listVersion.glowstoneCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.glowstoneCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.glowstoneCache.get(ver));
|
||||
}
|
||||
} else if (platform === "cuberite") {
|
||||
if (!ver) return res.json(Java.listVersion.cuberiteCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.cuberiteCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.cuberiteCache.get(ver));
|
||||
}
|
||||
} else if (platform === "folia") {
|
||||
if (!ver) return res.json(Java.listVersion.foliaCache.toJSON());
|
||||
else {
|
||||
if (!(Java.listVersion.foliaCache.has(ver))) return res.status(400).json({error: "This version not exists!"});
|
||||
return res.json(Java.listVersion.foliaCache.get(ver));
|
||||
}
|
||||
}
|
||||
return res.json(list);
|
||||
});
|
||||
|
||||
app.get("/", async ({res}) => {
|
||||
// Bedrock
|
||||
const bedrockOficial = (await (async () => {if (bedrockStash["oficial"]) return bedrockStash["oficial"];bedrockStash["oficial"] = await Bedrock.listVersions();setTimeout(() => delete bedrockStash["oficial"], 60000);return bedrockStash["oficial"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
const cloudbust = (await (async () => {if (bedrockStash["cloudbust"]) return bedrockStash["cloudbust"];bedrockStash["cloudbust"] = await Bedrock.listVersions("cloudbust");setTimeout(() => delete bedrockStash["cloudbust"], 60000);return bedrockStash["cloudbust"];})()).at(0);
|
||||
const nukkit = (await (async () => {if (bedrockStash["nukkit"]) return bedrockStash["nukkit"];bedrockStash["nukkit"] = await Bedrock.listVersions("nukkit");setTimeout(() => delete bedrockStash["nukkit"], 60000);return bedrockStash["nukkit"];})()).at(0);
|
||||
const powernukkit = (await (async () => {if (bedrockStash["powernukkit"]) return bedrockStash["powernukkit"];bedrockStash["powernukkit"] = await Bedrock.listVersions("powernukkit");setTimeout(() => delete bedrockStash["powernukkit"], 60000);return bedrockStash["powernukkit"];})()).at(0);
|
||||
const pocketmine = (await (async () => {if (bedrockStash["pocketmine"]) return bedrockStash["pocketmine"];bedrockStash["pocketmine"] = await Bedrock.listVersions("pocketmine");setTimeout(() => delete bedrockStash["pocketmine"], 60000);return bedrockStash["pocketmine"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
|
||||
// Java
|
||||
const javaOficial = (await (async () => {if (javaStash["oficial"]) return javaStash["oficial"]; javaStash["oficial"] = await Java.listVersions(); setTimeout(() => delete javaStash["oficial"], 6000); return javaStash["oficial"];})()).filter(rel => rel.release === "stable").at(0);
|
||||
const spigot = (await (async () => {if (javaStash["spigot"]) return javaStash["spigot"]; javaStash["spigot"] = await Java.listVersions("spigot"); setTimeout(() => delete javaStash["spigot"], 6000); return javaStash["spigot"];})()).at(0);
|
||||
const paper = (await (async () => {if (javaStash["paper"]) return javaStash["paper"]; javaStash["paper"] = await Java.listVersions("paper"); setTimeout(() => delete javaStash["paper"], 6000); return javaStash["paper"];})()).at(0);
|
||||
const glowstone = (await (async () => {if (javaStash["glowstone"]) return javaStash["glowstone"]; javaStash["glowstone"] = await Java.listVersions("glowstone"); setTimeout(() => delete javaStash["glowstone"], 6000); return javaStash["glowstone"];})()).at(0);
|
||||
const purpur = (await (async () => {if (javaStash["purpur"]) return javaStash["purpur"]; javaStash["purpur"] = await Java.listVersions("purpur"); setTimeout(() => delete javaStash["purpur"], 6000); return javaStash["purpur"];})()).at(0);
|
||||
const folia = (await (async () => {if (javaStash["folia"]) return javaStash["folia"]; javaStash["folia"] = await Java.listVersions("folia"); setTimeout(() => delete javaStash["folia"], 6000); return javaStash["folia"];})()).at(0);
|
||||
const cuberite = (await (async () => {if (javaStash["cuberite"]) return javaStash["cuberite"]; javaStash["cuberite"] = await Java.listVersions("cuberite"); setTimeout(() => delete javaStash["cuberite"], 6000); return javaStash["cuberite"];})()).at(0);
|
||||
|
||||
app.get("/", async ({ res }) => {
|
||||
return res.json({
|
||||
bedrock: {
|
||||
bedrockOficial,
|
||||
pocketmine,
|
||||
cloudbust,
|
||||
nukkit,
|
||||
powernukkit
|
||||
bedrockOficial: Bedrock.listVersion.mojangCache,
|
||||
pocketmine: Bedrock.listVersion.pocketmineCache,
|
||||
cloudbust: Bedrock.listVersion.cloudburstCache,
|
||||
nukkit: Bedrock.listVersion.nukkitCache,
|
||||
powernukkit: Bedrock.listVersion.powernukkitCache
|
||||
},
|
||||
java: {
|
||||
javaOficial,
|
||||
spigot,
|
||||
paper,
|
||||
glowstone,
|
||||
purpur,
|
||||
folia,
|
||||
cuberite
|
||||
javaOficial: Java.listVersion.mojangCache,
|
||||
spigot: Java.listVersion.spigotCache,
|
||||
paper: Java.listVersion.paperCache,
|
||||
glowstone: Java.listVersion.glowstoneCache,
|
||||
purpur: Java.listVersion.purpurCache,
|
||||
folia: Java.listVersion.foliaCache,
|
||||
cuberite: Java.listVersion.cuberiteCache
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// 404
|
||||
app.use(({res}) => res.status(404).json({error: "Not found page."}));
|
||||
app.use((error, _req, res, _next) => res.status(500).json({error: error?.message || String(error) || "Unknown error."}));
|
||||
app.use(({ res }) => res.status(404).json({ error: "Not found page." }));
|
||||
app.use((error, _req, res, _next) => res.status(500).json({ error: error?.message || String(error) || "Unknown error." }));
|
9
railway.json
Normal file
9
railway.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"build": {
|
||||
"builder": "DOCKERFILE",
|
||||
"dockerfilePath": "packages/verapiDockerfile"
|
||||
},
|
||||
"deploy": {
|
||||
"restartPolicyType": "ALWAYS"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user