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
|
# Build Core
|
||||||
- name: Core Build
|
- name: Core Build
|
||||||
if: matrix.package != '@the-bds-maneger/core'
|
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 }}"
|
- name: Build "${{ matrix.package }}"
|
||||||
run: npm run --if-present -w "${{ matrix.package }}" prepack
|
run: npm run --if-present -w "${{ matrix.package }}" prepack
|
@ -5,91 +5,10 @@ import yargs from "yargs";
|
|||||||
|
|
||||||
// Init yargs
|
// Init yargs
|
||||||
yargs(process.argv.slice(2)).version(false).help(true).strictCommands().demandCommand().alias("h", "help")
|
yargs(process.argv.slice(2)).version(false).help(true).strictCommands().demandCommand().alias("h", "help")
|
||||||
.command("install", "Install server", async yargs => {
|
.command(["install", "i", "update"], "Install/update server platform", yargs => yargs, async options => {
|
||||||
const options = yargs.option("platform", {
|
console.log(bdsCore);
|
||||||
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(["start", "run", "$0"], "start server", yargs => yargs, async options => {})
|
||||||
.parseAsync().catch(err => {
|
.parseAsync().catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -173,3 +173,12 @@ export function getCacheVersions() {
|
|||||||
cloudburst: Array.from(cloudburstCache.keys()).reduce<{[k: string]: cloudburstDownload}>((acc, key) => {acc[key] = cloudburstCache.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 type platforms = "mojang" | "pocketmine" | "powernukkit" | "nukkit" | "cloudburst";
|
||||||
|
|
||||||
export interface bedrockPorts { }
|
export interface bedrockPorts {
|
||||||
|
port: number;
|
||||||
|
localListen?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface playerInfo {
|
export interface playerInfo {
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
banned: boolean;
|
banned: boolean;
|
||||||
|
xuid?: string;
|
||||||
historic: {
|
historic: {
|
||||||
action: "connected" | "spawned" | "disconnected";
|
action: string;
|
||||||
actionDate: Date;
|
actionDate: Date;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
class playerListen extends Map<string, playerInfo> {
|
class playerListen extends Map<string, playerInfo> {
|
||||||
constructor() { super(); }
|
constructor(origem?: Record<string, playerInfo>) {
|
||||||
|
super(Object.keys(origem || {}).map(key => ([key, origem[key]])));
|
||||||
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return Array.from(this.keys()).reduce<{ [playerName: string]: playerInfo }>((acc, player) => {
|
return Array.from(this.keys()).reduce<{ [playerName: string]: playerInfo }>((acc, player) => {
|
||||||
acc[player] = this.get(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"]) {
|
updateState(playerName: string, state: playerInfo["historic"][number]["action"]) {
|
||||||
const actionDate = new Date();
|
const actionDate = new Date();
|
||||||
if (!(this.has(playerName))) throw new Error("Set Player");
|
const playerData = this.init(playerName).get(playerName);
|
||||||
const playerData = super.get(playerName);
|
|
||||||
if (state === "disconnected") playerData.connected = false; else playerData.connected = true;
|
if (state === "disconnected") playerData.connected = false; else playerData.connected = true;
|
||||||
playerData.historic.push({ action: state, actionDate });
|
playerData.historic.push({ action: state, actionDate });
|
||||||
super.set(playerName, playerData);
|
super.set(playerName, playerData);
|
||||||
@ -56,7 +73,8 @@ export function isBedrock(event: Bedrock<any>): event is Bedrock<any> {
|
|||||||
|
|
||||||
export type bedrockEvents = defineEvents<{
|
export type bedrockEvents = defineEvents<{
|
||||||
logLine(lineString: string): void;
|
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> {
|
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;
|
readonly platform: P;
|
||||||
constructor(rootServer: string, platform: P) {
|
constructor(rootServer: string, platform: P) {
|
||||||
super();
|
super();
|
||||||
|
if ((!(["mojang", "pocketmine", "powernukkit", "nukkit", "cloudburst"]).includes(platform))) throw new Error("Invalid platform");
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
this.rootServer = rootServer;
|
this.rootServer = rootServer;
|
||||||
this.serverFolder = path.join(rootServer, "server");
|
this.serverFolder = path.join(rootServer, "server");
|
||||||
Object.defineProperty(this, "rootServer", { writable: false });
|
Object.defineProperty(this, "rootServer", { writable: false });
|
||||||
Object.defineProperty(this, "serverFolder", { 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 });
|
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 }));
|
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 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)));
|
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") {
|
} else if (platform === "pocketmine") {
|
||||||
const release = bedrockVersions.pocketmineCache.get(version);
|
const release = bedrockVersions.pocketmineCache.get(version);
|
||||||
if (!release) throw new Error("Not valid Release");
|
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}`));
|
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");
|
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);
|
const phpFile = phpFiles.sort((b, a) => a.data.Dates.Modified.getTime() - b.data.Dates.Modified.getTime()).at(0);
|
||||||
await fs.rm(path.join(this.serverFolder, "bin"), { recursive: true, force: true });
|
const binPath = path.join(this.serverFolder, "bin");
|
||||||
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") })));
|
if (await extendsFS.exists(binPath)) await fs.rm(binPath, { recursive: true, force: true });
|
||||||
else {
|
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);
|
const tmpFile = path.join(tmpdir(), Date.now() + "_" + phpFile.name);
|
||||||
await finished((await phpFile.data.getFile()).pipe(createWriteStream(tmpFile)));
|
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 });
|
await fs.rm(tmpFile, { force: true });
|
||||||
}
|
}
|
||||||
|
this.emit("installedVersion", bedrockVersions.pocketmineCache.prettyVersion(version));
|
||||||
} else if (platform === "powernukkit") {
|
} else if (platform === "powernukkit") {
|
||||||
const release = bedrockVersions.powernukkitCache.get(version);
|
const release = bedrockVersions.powernukkitCache.get(version);
|
||||||
if (!release) throw new Error("Not valid Release");
|
if (!release) throw new Error("Not valid Release");
|
||||||
await finished(await http.streamRequest(release.url), createWriteStream(path.join(this.serverFolder, "server.jar")));
|
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") {
|
} else if (platform === "cloudburst" || platform === "nukkit") {
|
||||||
const platformVersions = platform === "cloudburst" ? bedrockVersions.cloudburstCache : bedrockVersions.nukkitCache;
|
const platformVersions = platform === "cloudburst" ? bedrockVersions.cloudburstCache : bedrockVersions.nukkitCache;
|
||||||
const release = platformVersions.get(version);
|
const release = platformVersions.get(version);
|
||||||
if (!release) throw new Error("Not valid Release");
|
if (!release) throw new Error("Not valid Release");
|
||||||
await finished(await http.streamRequest(release.url), createWriteStream(path.join(this.serverFolder, "server.jar")));
|
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;
|
serverProcess?: child_process.ChildProcess;
|
||||||
async runServer() {
|
async runServer() {
|
||||||
const { platform } = this;
|
const { platform } = this;
|
||||||
if (platform === "nukkit" || platform === "powernukkit" || platform === "cloudburst") {
|
const logLine: (bedrockEvents["logLine"])[] = [];
|
||||||
const serverProcess = this.serverProcess = child_process.spawn("java", [
|
|
||||||
|
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:+UseG1GC",
|
||||||
"-XX:+ParallelRefProcEnabled",
|
"-XX:+ParallelRefProcEnabled",
|
||||||
"-XX:MaxGCPauseMillis=200",
|
"-XX:MaxGCPauseMillis=200",
|
||||||
@ -146,35 +235,24 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
|
|||||||
cwd: this.serverFolder,
|
cwd: this.serverFolder,
|
||||||
stdio: ["pipe", "pipe", "pipe"],
|
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.stdout),
|
||||||
readline.createInterface(this.serverProcess.stderr)
|
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;
|
return this.serverProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLn(data: string | Buffer) {
|
writeLn(data: string | Buffer) {
|
||||||
this.serverProcess.stdin.write(data);
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 { Github, http } from "@sirherobrine23/http";
|
||||||
import stream from "node:stream";
|
import stream from "node:stream";
|
||||||
import semver from "semver";
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import semver from "semver";
|
||||||
import { bdsFilesBucket } from "../../internalClouds.js";
|
import { bdsFilesBucket } from "../../internalClouds.js";
|
||||||
|
import { versionsStorages } from "../../serverRun.js";
|
||||||
|
|
||||||
interface baseDownload {
|
interface baseDownload {
|
||||||
URL: string;
|
URL: string;
|
||||||
@ -28,7 +29,7 @@ async function PromiseSplit<T extends (any[])>(arrayInput: T, fn: (value: T[numb
|
|||||||
return result.flat(1);
|
return result.flat(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mojangCache = new Map<string, mojangInfo>();
|
export const mojangCache = new versionsStorages<mojangInfo>();
|
||||||
export async function listMojang() {
|
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;
|
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 => {
|
await PromiseSplit(versions, async version => {
|
||||||
@ -48,7 +49,7 @@ export interface spigotDownload {
|
|||||||
craftbukkit?(): Promise<stream.Readable>;
|
craftbukkit?(): Promise<stream.Readable>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const spigotCache = new Map<string, spigotDownload>();
|
export const spigotCache = new versionsStorages<spigotDownload>();
|
||||||
export async function listSpigot() {
|
export async function listSpigot() {
|
||||||
const spigotFiles = await bdsFilesBucket.listFiles("SpigotBuild/");
|
const spigotFiles = await bdsFilesBucket.listFiles("SpigotBuild/");
|
||||||
for (const file of spigotFiles.filter(file => file.name.slice(12).startsWith("1.")).sort((b, a) => {
|
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 paperCache = new versionsStorages<baseDownload>();
|
||||||
export const velocityCache = new Map<string, baseDownload>();
|
export const velocityCache = new versionsStorages<baseDownload>();
|
||||||
export const foliaCache = new Map<string, baseDownload>();
|
export const foliaCache = new versionsStorages<baseDownload>();
|
||||||
export async function listPaperProject() {
|
export async function listPaperProject() {
|
||||||
const paperProjects = ["paper", "velocity", "folia"] as const;
|
const paperProjects = ["paper", "velocity", "folia"] as const;
|
||||||
await Promise.all(paperProjects.map(async projectName => {
|
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() {
|
export async function listPurpurProject() {
|
||||||
const baseURL = new URL("https://api.purpurmc.org/v2/purpur");
|
const baseURL = new URL("https://api.purpurmc.org/v2/purpur");
|
||||||
const { versions } = await http.jsonRequestBody<{ versions: string[] }>(baseURL);
|
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() {
|
export async function listGlowstoneProject() {
|
||||||
const repo = await Github.repositoryManeger("GlowstoneMC", "Glowstone");
|
const repo = await Github.repositoryManeger("GlowstoneMC", "Glowstone");
|
||||||
const rels = (await repo.release.getRelease()).filter(rel => rel.assets.some(asset => asset.name.endsWith(".jar")));
|
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[] }>([
|
export const cuberiteCache = new versionsStorages<{ URL: string[] }>({
|
||||||
[
|
"win32-x64": {
|
||||||
"win32-x64",
|
|
||||||
{
|
|
||||||
URL: ["https://download.cuberite.org/windows-x86_64/Cuberite.zip"]
|
URL: ["https://download.cuberite.org/windows-x86_64/Cuberite.zip"]
|
||||||
}
|
},
|
||||||
],
|
"win32-ia32": {
|
||||||
[
|
|
||||||
"win32-ia32",
|
|
||||||
{
|
|
||||||
URL: ["https://download.cuberite.org/windows-i386/Cuberite.zip"]
|
URL: ["https://download.cuberite.org/windows-i386/Cuberite.zip"]
|
||||||
}
|
}
|
||||||
]
|
});
|
||||||
]);
|
|
||||||
export async function listCuberite() {
|
export async function listCuberite() {
|
||||||
const projects = ["android", "linux-aarch64", "linux-armhf", "linux-i386", "linux-x86_64", "darwin-x86_64"] as const;
|
const projects = ["android", "linux-aarch64", "linux-armhf", "linux-i386", "linux-x86_64", "darwin-x86_64"] as const;
|
||||||
await Promise.all(projects.map(async project => {
|
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`);
|
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;
|
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}`);
|
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 serverIndex = map.findIndex(file => file.toLowerCase().endsWith("server.zip"));
|
||||||
const server = map[serverIndex];
|
const server = map[serverIndex];
|
||||||
delete 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("arm64")) cuberiteCache.set("android-arm64", { URL: [server, file] });
|
||||||
else if (plat.startsWith("arm")) cuberiteCache.set("android-arm", { URL: [server, file] });
|
else if (plat.startsWith("arm")) cuberiteCache.set("android-arm", { URL: [server, file] });
|
||||||
}
|
}
|
||||||
} else cuberiteCache.set(project, { URL: map });
|
}
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -6,3 +6,4 @@ export { isBedrock } from "./platform/bedrock/index.js";
|
|||||||
// Java platform
|
// 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 * as java from "./platform/java/index.js";
|
||||||
|
export { isJava } from "./platform/java/index.js";
|
@ -1,58 +1,70 @@
|
|||||||
import EventEmitter from "node:events";
|
import EventEmitter from "node:events";
|
||||||
|
|
||||||
export type EventMap = Record<string, (...args: any[]) => void>;
|
export type EventMap = Record<string, (...args: any[]) => void>;
|
||||||
|
export type defineEvents<T extends EventMap> = T;
|
||||||
type EventKey<T extends EventMap> = string & keyof 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 {
|
export class customEvent<T extends EventMap> extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({captureRejections: true});
|
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> {
|
export class versionsStorages<T> extends Map<string, T> {
|
||||||
get(key: string|number): T {
|
constructor(origem: Record<string, T> = {}) {
|
||||||
if (typeof key === "number") return super.get(Array.from(this.keys()).at(key));
|
super(Object.keys(origem).map(key => ([key, origem[key]])));
|
||||||
return super.get(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 path from "node:path";
|
||||||
import { listVersion, Bedrock } from "../src/platform/bedrock/index.js";
|
import { listVersion, Bedrock } from "../src/platform/bedrock/index.js";
|
||||||
import { homedir } from "node:os";
|
import { homedir } from "node:os";
|
||||||
await listVersion.listMojang();
|
|
||||||
|
|
||||||
const mojang = new Bedrock(path.join(homedir(), ".bdsmaneger/playgroud/mojang"), "mojang");
|
const server = new Bedrock(path.join(homedir(), ".bdsmaneger/playgroud/mojang"), "pocketmine");
|
||||||
const version = Array.from(listVersion.mojangCache.keys()).at(9);
|
server.once("installedVersion", version => console.log("Installed %s server", version));
|
||||||
console.log("Installing %s", version);
|
await listVersion.listPocketmineProject();
|
||||||
await mojang.installServer(version);
|
console.log("Init install");
|
||||||
mojang.on("logLine", (line) => console.log(line[0]));
|
await server.installServer(0);
|
||||||
const pr = await mojang.runServer();
|
server.on("logLine", (line) => console.log(line[0]));
|
||||||
|
const pr = await server.runServer();
|
||||||
process.stdin.pipe(pr.stdin);
|
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,129 +1,182 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { Java, Bedrock } from "@the-bds-maneger/core";
|
import { Bedrock, Java } from "@the-bds-maneger/core";
|
||||||
import { createServer } from "node:http";
|
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import expressLayer from "express/lib/router/layer.js";
|
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) {
|
expressLayer.prototype.handle_request = async function handle_request_promised(...args) {
|
||||||
var fn = this.handle;
|
var fn = this.handle;
|
||||||
if (fn.length > 3) return args.at(-1)();
|
if (fn.length > 3) return args.at(-1)();
|
||||||
await Promise.resolve().then(() => fn.call(this, ...args)).catch(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();
|
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);
|
const server = createServer(app);
|
||||||
server.listen(Number(process.env.PORT || 3000), () => {
|
server.listen(Number(process.env.PORT || 3000), () => {
|
||||||
const addr = server.address();
|
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
|
// Bedrock
|
||||||
const bedrockRoute = express.Router();
|
const bedrockRoute = express.Router();
|
||||||
app.use("/bedrock", bedrockRoute);
|
app.use("/bedrock", bedrockRoute);
|
||||||
const bedrockStash = {};
|
|
||||||
bedrockRoute.get("/", async ({ res }) => {
|
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);
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
bedrockOficial,
|
bedrockOficial: Bedrock.listVersion.mojangCache,
|
||||||
pocketmine,
|
pocketmine: Bedrock.listVersion.pocketmineCache,
|
||||||
cloudbust,
|
cloudbust: Bedrock.listVersion.cloudburstCache,
|
||||||
nukkit,
|
nukkit: Bedrock.listVersion.nukkitCache,
|
||||||
powernukkit
|
powernukkit: Bedrock.listVersion.powernukkitCache
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
bedrockRoute.get("/((oficial|cloudbust|nukkit|nukkit|powernukkit|pocketmine))", async (req, res) => {
|
bedrockRoute.get("/((oficial|cloudbust|nukkit|nukkit|powernukkit|pocketmine))", async (req, res) => {
|
||||||
let platform = req.params[0];
|
/** @type {"oficial" | "cloudbust" | "nukkit" | "nukkit" | "powernukkit" | "pocketmine"} */
|
||||||
if (!bedrockStash[platform]) {
|
const platform = req.params[0];
|
||||||
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)];
|
|
||||||
const ver = String(req.query.v || req.query.version || "");
|
const ver = String(req.query.v || req.query.version || "");
|
||||||
if (ver) {
|
if (platform === "oficial") {
|
||||||
const data = list.find(e => e.version === ver);
|
if (!ver) return res.json(Bedrock.listVersion.mojangCache.toJSON());
|
||||||
if (!data) return res.status(400).json({error: "Not found version."});
|
else {
|
||||||
return res.json(data);
|
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
|
// Java
|
||||||
const javaRoute = express.Router();
|
const javaRoute = express.Router();
|
||||||
app.use("/java", javaRoute);
|
app.use("/java", javaRoute);
|
||||||
const javaStash = {};
|
|
||||||
javaRoute.get("/", async ({ res }) => {
|
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);
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
javaOficial,
|
javaOficial: Java.listVersion.mojangCache,
|
||||||
spigot,
|
spigot: Java.listVersion.spigotCache,
|
||||||
paper,
|
paper: Java.listVersion.paperCache,
|
||||||
glowstone,
|
glowstone: Java.listVersion.glowstoneCache,
|
||||||
purpur,
|
purpur: Java.listVersion.purpurCache,
|
||||||
folia,
|
folia: Java.listVersion.foliaCache,
|
||||||
cuberite
|
cuberite: Java.listVersion.cuberiteCache
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
javaRoute.get("/((oficial|spigot|paper|purpur|glowstone|folia|cuberite))", async (req, res) => {
|
javaRoute.get("/((oficial|spigot|paper|purpur|glowstone|folia|cuberite))", async (req, res) => {
|
||||||
let platform = req.params[0];
|
/** @type {"oficial" | "spigot" | "paper" | "purpur" | "glowstone" | "folia" | "cuberite"} */
|
||||||
if (!javaStash[platform]) {
|
const platform = req.params[0];
|
||||||
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)];
|
|
||||||
const ver = String(req.query.v || req.query.version || "");
|
const ver = String(req.query.v || req.query.version || "");
|
||||||
if (ver) {
|
if (platform === "oficial") {
|
||||||
const data = list.find(e => e.version === ver);
|
if (!ver) return res.json(Java.listVersion.mojangCache.toJSON());
|
||||||
if (!data) return res.status(400).json({error: "Not found version."});
|
else {
|
||||||
return res.json(data);
|
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 }) => {
|
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);
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
bedrock: {
|
bedrock: {
|
||||||
bedrockOficial,
|
bedrockOficial: Bedrock.listVersion.mojangCache,
|
||||||
pocketmine,
|
pocketmine: Bedrock.listVersion.pocketmineCache,
|
||||||
cloudbust,
|
cloudbust: Bedrock.listVersion.cloudburstCache,
|
||||||
nukkit,
|
nukkit: Bedrock.listVersion.nukkitCache,
|
||||||
powernukkit
|
powernukkit: Bedrock.listVersion.powernukkitCache
|
||||||
},
|
},
|
||||||
java: {
|
java: {
|
||||||
javaOficial,
|
javaOficial: Java.listVersion.mojangCache,
|
||||||
spigot,
|
spigot: Java.listVersion.spigotCache,
|
||||||
paper,
|
paper: Java.listVersion.paperCache,
|
||||||
glowstone,
|
glowstone: Java.listVersion.glowstoneCache,
|
||||||
purpur,
|
purpur: Java.listVersion.purpurCache,
|
||||||
folia,
|
folia: Java.listVersion.foliaCache,
|
||||||
cuberite
|
cuberite: Java.listVersion.cuberiteCache
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
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