From bf3cb0b807954e9158a8c96dae571e98f7f60437 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 21 Sep 2022 22:13:50 +0000 Subject: [PATCH 01/14] Init php build --- src/externalBuild/pocketmine.ts | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/externalBuild/pocketmine.ts diff --git a/src/externalBuild/pocketmine.ts b/src/externalBuild/pocketmine.ts new file mode 100644 index 0000000..f61ba82 --- /dev/null +++ b/src/externalBuild/pocketmine.ts @@ -0,0 +1,86 @@ +import fsOld from "node:fs"; +import fs from "node:fs/promises"; +import admZip from "adm-zip"; +import { execFileAsync } from "../childPromisses"; +import { saveFile } from "../httpRequest"; +import { promisify } from "node:util"; +import path from "node:path"; + +var PHP_MAJOR_VER = "8.0" +var PHP_VER = `${PHP_MAJOR_VER}.22` +var PHP_GIT_REV = `php-${PHP_VER}` +var PHP_DISPLAY_VER = PHP_VER +var PHP_SDK_VER = "2.2.0" +var VC_VER = "vs16" +var ARCH = "x64" +var VS_VER = "" +var VS_YEAR = "" +var CMAKE_TARGET = "" +var PHP_DEBUG_BUILD = "0"; +var MSBUILD_CONFIGURATION = "RelWithDebInfo" + +var LIBYAML_VER = "0.2.5" +var PTHREAD_W32_VER = "3.0.0" +var LEVELDB_MCPE_VER= "1c7564468b41610da4f498430e795ca4 de0931ff" +var LIBDEFLATE_VER= "b01537448e8eaf0803e38bdba5acef1d 1c8effba" + +var PHP_PTHREADS_VER = "4.1.3" +var PHP_YAML_VER = "2.2.2" +var PHP_CHUNKUTILS2_VER = "0.3.3" +var PHP_IGBINARY_VER = "3.2.7" +var PHP_LEVELDB_VER= "317fdcd8415e1566fc2835ce2bdb8e19 b890f9f3" +var PHP_CRYPTO_VER = "0.3.2" +var PHP_RECURSIONGUARD_VER = "0.1.0" +var PHP_MORTON_VER = "0.1.2" +var PHP_LIBDEFLATE_VER = "0.1.0" +var PHP_XXHASH_VER = "0.1.1" +var PHP_XDEBUG_VER = "3.1.5" + +var OUT_PATH_REL = "Release" +var PHP_HAVE_DEBUG = "enable-debug-pack" + +var SOURCES_PATH = process.env.SOURCES_PATH||`C:\\pocketmine-php-${PHP_DISPLAY_VER}-release` + +var VS_EDITION = process.env.VS_EDITION || "Community"; +var VS_YEAR = process.env.VS_YEAR; + +function getCode() { + if (!fsOld.existsSync(`C:\\Program Files (x86)\\Microsoft Visual Studio`)) throw new Error("Please install Visual Studio"); + if (!VS_YEAR) VS_YEAR = fsOld.readdirSync("C:\\Program Files (x86)\\Microsoft Visual Studio")[0]; + if (fsOld.existsSync(`C:\\Program Files (x86)\\Microsoft Visual Studio\\${VS_YEAR}\\${VS_EDITION}\\VC\\Auxiliary\\Build\\vcvarsall.bat`)) return `C:\\Program Files (x86)\\Microsoft Visual Studio\\${VS_YEAR}\\${VS_EDITION}`; + VS_EDITION = fsOld.readdirSync(`C:\\Program Files (x86)\\Microsoft Visual Studio\\${VS_YEAR}`)[0]; + return getCode(); +} + +async function get_zip(url: string, out: string) { + await (promisify((new admZip(await saveFile(url))).extractAllToAsync))(out, false, true); +} + +export default async function build(SOURCES_PATH: string) { + if (fsOld.existsSync(SOURCES_PATH)) fs.rm(SOURCES_PATH, {recursive: true, force: true}); + console.log("Getting SDK..."); + await execFileAsync("git", ["clone", "https://github.com/OSTC/php-sdk-binary-tools.git", "-b", `php-sdk-${PHP_SDK_VER}`, "-q", "--depth=1", SOURCES_PATH], {stdio: "inherit"}); + await execFileAsync("bin\\phpsdk_setvars.bat", {stdio: "inherit"}); + console.log("Downloading PHP source version %s...", PHP_VER); + await get_zip(`https://github.com/php/php-src/archive/${PHP_GIT_REV}.zip`, path.join(SOURCES_PATH, "php-src")); + + let DEPS_DIR_NAME="deps" + let DEPS_DIR=`${SOURCES_PATH}\\${DEPS_DIR_NAME}`; + await execFileAsync("bin\\phpsdk_deps.bat", ["-u", "-t", VS_VER, "-b", PHP_MAJOR_VER, "-a", process.arch, "-f", "-d", DEPS_DIR_NAME], {cwd: SOURCES_PATH, stdio: "inherit"}); + console.log("Getting additional dependencies..."); + SOURCES_PATH = path.join(SOURCES_PATH, DEPS_DIR); + + console.log("Downloading LibYAML version %s...", LIBYAML_VER); + await get_zip(`https://github.com/yaml/libyaml/archive/${LIBYAML_VER}.zip`, path.join(SOURCES_PATH, "libyaml")); + SOURCES_PATH = path.join(SOURCES_PATH, "libyaml"); + console.log("Generating build configuration..."); + await execFileAsync("cmake", ["-G", CMAKE_TARGET, "-A", process.arch, `-DCMAKE_PREFIX_PATH=${DEPS_DIR}`, `-DCMAKE_INSTALL_PREFIX=${DEPS_DIR}`, `-DBUILD_SHARED_LIBS=ON`, "."], {cwd: SOURCES_PATH, stdio: "inherit"}); + console.log("Compiling..."); + await execFileAsync("msbuild", ["ALL_BUILD.vcxproj", `/p:Configuration=${MSBUILD_CONFIGURATION}`, "/m"], {cwd: SOURCES_PATH, stdio: "inherit"}); + console.log("Installing files..."); + await execFileAsync("msbuild", ["INSTALL.vcxproj", `/p:Configuration=${MSBUILD_CONFIGURATION}`, "/m"], {cwd: SOURCES_PATH, stdio: "inherit"}); + fs.cp() + + SOURCES_PATH = path.join(SOURCES_PATH, DEPS_DIR); + +} \ No newline at end of file -- 2.50.0 From 22e856516b37bd364dd7429b2ef4adf783d689bb Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 21 Sep 2022 23:03:21 +0000 Subject: [PATCH 02/14] add unique download windows in pocketmine --- src/httpRequest.ts | 145 +++++++++++++++++++++++++++++++++++---------- src/pocketmine.ts | 10 +++- 2 files changed, 122 insertions(+), 33 deletions(-) diff --git a/src/httpRequest.ts b/src/httpRequest.ts index 081ad6a..5b5decf 100644 --- a/src/httpRequest.ts +++ b/src/httpRequest.ts @@ -5,37 +5,6 @@ import axios from "axios"; import got from "got"; import tar from "tar"; -export async function getBuffer(url: string, options?: {method?: string,body?: any, headers?: {[key: string]: string}}): Promise { - const Headers = {}; - let Body: any; - if (options) { - if (options.headers) Object.keys(options.headers).forEach(key => Headers[key] = options.headers[key]); - if (options.body) Body = options.body; - } - // if (typeof fetch === "undefined") - return axios.get(url, { - responseEncoding: "arraybuffer", - responseType: "arraybuffer", - headers: Headers, - data: Body, - method: (options?.method||"GET").toUpperCase() - }).then(({data}) => Buffer.from(data)); - // return fetch(url, { - // method: "GET", - // body: typeof Body === "object" ? JSON.stringify(Body, null, 2):Body, - // headers: Headers - // }).then(res => res.arrayBuffer()).then(res => Buffer.from(res)); -} - -export async function getJSON(url: string, options?: {method?: string, body?: any, headers?: {[key: string]: string}}): Promise { - return getBuffer(url, { - body: options?.body, - headers: options?.headers, - method: options?.method - }).then(res => JSON.parse(res.toString("utf8")) as JSONReturn); -} - -// Create function to save directly file in disk with stream export async function saveFile(url: string, options?: {filePath?: string, headers?: {[key: string]: string|number}}) { let fileSave = path.join(tmpdir(), "_bdscore", (Math.random()*155515151).toFixed()+"_raw_bdscore"); const Headers = {}; @@ -70,4 +39,116 @@ export async function tarExtract(url: string, options?: {folderPath?: string, he gotStream.on("error", reject); tarE.on("error", reject); }); -} \ No newline at end of file +} + +export async function getBuffer(url: string, options?: {method?: string,body?: any, headers?: {[key: string]: string}}): Promise { + const Headers = {}; + let Body: any; + if (options) { + if (options.headers) Object.keys(options.headers).forEach(key => Headers[key] = options.headers[key]); + if (options.body) Body = options.body; + } + // if (typeof fetch === "undefined") + return axios.get(url, { + responseEncoding: "arraybuffer", + responseType: "arraybuffer", + headers: Headers, + data: Body, + method: (options?.method||"GET").toUpperCase() + }).then(({data}) => Buffer.from(data)); + // return fetch(url, { + // method: "GET", + // body: typeof Body === "object" ? JSON.stringify(Body, null, 2):Body, + // headers: Headers + // }).then(res => res.arrayBuffer()).then(res => Buffer.from(res)); +} + +export async function getJSON(url: string, options?: {method?: string, body?: any, headers?: {[key: string]: string}}): Promise { + return getBuffer(url, { + body: options?.body, + headers: options?.headers, + method: options?.method + }).then(res => JSON.parse(res.toString("utf8")) as JSONReturn); +} + +export type githubRelease = { + url: string; + assets_url: string; + upload_url: string; + html_url: string; + id: number; + tarball_url: string; + zipball_url: string; + body: string; + author: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + node_id: string; + tag_name: string; + target_commitish: string; + name: string; + draft: boolean; + prerelease: boolean; + created_at: string; + published_at: string; + assets: Array<{ + url: string; + id: number; + node_id: string; + name: string; + label: string; + content_type: string; + state: string; + size: number; + download_count: number; + created_at: string; + updated_at: string; + browser_download_url: string; + uploader: { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: boolean; + }; + }>; +}; + +export async function GithubRelease(username: string, repo?: string): Promise { + let fullRepo = username; + if (!username) throw new Error("Repository is required, example: GithubRelease(\"Username/repo\") or GithubRelease(\"Username\", \"repo\")"); + if (repo) { + if (!/\//.test(fullRepo)) fullRepo += "/"+repo; + } + return getJSON(`https://api.github.com/repos/${fullRepo}/releases?per_page=100`); +} diff --git a/src/pocketmine.ts b/src/pocketmine.ts index 1814441..bd0a084 100644 --- a/src/pocketmine.ts +++ b/src/pocketmine.ts @@ -6,7 +6,7 @@ import { existsSync as fsExistsSync } from "node:fs"; import { platformManeger } from "@the-bds-maneger/server_versions"; import { execFileAsync, execAsync } from './childPromisses'; import { logRoot, serverRoot } from "./pathControl"; -import { getBuffer } from "./httpRequest"; +import { getBuffer, GithubRelease, saveFile } from "./httpRequest"; import { actionConfig, actions } from './globalPlatfroms'; import AdmZip from "adm-zip"; import { promisify } from 'node:util'; @@ -60,6 +60,14 @@ async function buildPhp() { } async function installPhp(): Promise { + if (process.platform === "win32") { + return await GithubRelease("The-Bds-Maneger", "Build-PHP-Bins").then(async releases => { + let url: string; + for (const release of releases) url = release.assets.filter(assert => assert.name.endsWith(".zip")).find(assert => /win32|windows/.test(assert.name))?.browser_download_url; + if (!url) throw new Error("Cannnot get php url"); + return promisify((new AdmZip(await saveFile(url))).extractAllToAsync)(serverPath, false, true); + }); + } const file = await platformManeger.pocketmine.getPhp(); if (fsExistsSync(path.resolve(serverPath, "bin"))) await fs.rm(path.resolve(serverPath, "bin"), {recursive: true}); await fs.mkdir(path.resolve(serverPath, "bin"), {recursive: true}); -- 2.50.0 From 3cf0af4a313b44f87322a0d566f937b2f1296015 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 21 Sep 2022 23:21:45 +0000 Subject: [PATCH 03/14] Update pocketmine download --- src/httpRequest.ts | 2 +- src/pocketmine.ts | 49 +++++++++++++++++++++++----------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/httpRequest.ts b/src/httpRequest.ts index 5b5decf..3055d47 100644 --- a/src/httpRequest.ts +++ b/src/httpRequest.ts @@ -6,7 +6,7 @@ import got from "got"; import tar from "tar"; export async function saveFile(url: string, options?: {filePath?: string, headers?: {[key: string]: string|number}}) { - let fileSave = path.join(tmpdir(), "_bdscore", (Math.random()*155515151).toFixed()+"_raw_bdscore"); + let fileSave = path.join(tmpdir(), "bdscore_"+(Math.random()*155515151).toFixed()+"_raw_bdscore_"+path.basename(url)); const Headers = {}; if (options) { if (options.filePath && typeof options.filePath === "string") fileSave = options.filePath; diff --git a/src/pocketmine.ts b/src/pocketmine.ts index bd0a084..63cd3a5 100644 --- a/src/pocketmine.ts +++ b/src/pocketmine.ts @@ -6,7 +6,7 @@ import { existsSync as fsExistsSync } from "node:fs"; import { platformManeger } from "@the-bds-maneger/server_versions"; import { execFileAsync, execAsync } from './childPromisses'; import { logRoot, serverRoot } from "./pathControl"; -import { getBuffer, GithubRelease, saveFile } from "./httpRequest"; +import { getBuffer, githubRelease, GithubRelease, saveFile } from "./httpRequest"; import { actionConfig, actions } from './globalPlatfroms'; import AdmZip from "adm-zip"; import { promisify } from 'node:util'; @@ -60,30 +60,31 @@ async function buildPhp() { } async function installPhp(): Promise { - if (process.platform === "win32") { - return await GithubRelease("The-Bds-Maneger", "Build-PHP-Bins").then(async releases => { - let url: string; - for (const release of releases) url = release.assets.filter(assert => assert.name.endsWith(".zip")).find(assert => /win32|windows/.test(assert.name))?.browser_download_url; - if (!url) throw new Error("Cannnot get php url"); - return promisify((new AdmZip(await saveFile(url))).extractAllToAsync)(serverPath, false, true); - }); - } - const file = await platformManeger.pocketmine.getPhp(); + const releases: (githubRelease["assets"][0])[] = []; + (await GithubRelease("The-Bds-Maneger", "Build-PHP-Bins")).map(re => re.assets).forEach(res => releases.push(...res)); if (fsExistsSync(path.resolve(serverPath, "bin"))) await fs.rm(path.resolve(serverPath, "bin"), {recursive: true}); - await fs.mkdir(path.resolve(serverPath, "bin"), {recursive: true}); - // Tar.gz - if (/tar\.gz/.test(file.name)) { - await fs.writeFile(path.join(os.tmpdir(), file.name), file.buffer); - await tar.extract({file: path.join(os.tmpdir(), file.name), C: path.join(serverPath, "bin"), keep: true, p: true, noChmod: false}); - } else await promisify((new AdmZip(file.buffer)).extractAllToAsync)(serverPath, false, true); - if (process.platform === "linux"||process.platform === "android"||process.platform === "darwin") { - const ztsFind = await Readdir(path.resolve(serverPath, "bin"), [/.*debug-zts.*/]); - if (ztsFind.length > 0) { - const phpIniPath = (await Readdir(path.resolve(serverPath, "bin"), [/php\.ini$/]))[0].path; - let phpIni = await fs.readFile(phpIniPath, "utf8"); - if (phpIni.includes("extension_dir")) await fs.writeFile(phpIniPath, phpIni.replace(/extension_dir=.*/g, "")); - phpIni = phpIni+`\nextension_dir=${path.resolve(ztsFind[0].path, "..")}` - await fs.writeFile(phpIniPath, phpIni); + if (process.platform === "win32") { + let url: string = releases.filter(assert => assert.name.endsWith(".zip")).find(assert => /win32|windows/.test(assert.name))?.browser_download_url; + if (!url) throw new Error("Cannnot get php url"); + return promisify((new AdmZip(await saveFile(url))).extractAllToAsync)(serverPath, false, true); + } else { + await fs.mkdir(path.resolve(serverPath, "bin"), {recursive: true}); + const file = releases.find(re => re.name.includes(process.platform) && re.name.includes(process.arch)); + if (file) { + const downloadFile = await saveFile(file.browser_download_url); + // Tar.gz + if (/tar\.gz/.test(file.name)) await tar.extract({file: downloadFile, C: path.join(serverPath, "bin"), keep: true, p: true, noChmod: false}); + else await promisify((new AdmZip(downloadFile)).extractAllToAsync)(serverPath, false, true); + if (process.platform === "linux"||process.platform === "android"||process.platform === "darwin") { + const ztsFind = await Readdir(path.resolve(serverPath, "bin"), [/.*debug-zts.*/]); + if (ztsFind.length > 0) { + const phpIniPath = (await Readdir(path.resolve(serverPath, "bin"), [/php\.ini$/]))[0].path; + let phpIni = await fs.readFile(phpIniPath, "utf8"); + if (phpIni.includes("extension_dir")) await fs.writeFile(phpIniPath, phpIni.replace(/extension_dir=.*/g, "")); + phpIni = phpIni+`\nextension_dir=${path.resolve(ztsFind[0].path, "..")}` + await fs.writeFile(phpIniPath, phpIni); + } + } } } // test it's works php -- 2.50.0 From 3b4c5f42a1ecc37baf9935be575f1b86b36e8c07 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 21 Sep 2022 23:46:30 +0000 Subject: [PATCH 04/14] Update plugin maneger --- .github/workflows/test.yml | 62 ++++++++++++++++++++++++++------- src/globalPlatfroms.ts | 6 ++-- src/index.ts | 3 +- src/paper.ts | 2 +- src/plugin/bedrock.ts | 60 ------------------------------- src/plugin/{java.ts => main.ts} | 19 +++++++--- src/spigot.ts | 2 +- 7 files changed, 70 insertions(+), 84 deletions(-) delete mode 100644 src/plugin/bedrock.ts rename src/plugin/{java.ts => main.ts} (75%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a217720..d7e541b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,23 +1,21 @@ -name: Test package +name: Test all platforms on: [push] jobs: - test: + test_prebuild: strategy: matrix: - os: [windows-2019, ubuntu-latest, macos-latest] + os: [windows-latest, ubuntu-latest, macos-latest] platform: - - Bedrock - - Pocketmine - - Powernukkit - - Java - - Spigot - - Paper + - Bedrock + - Powernukkit + - Java + - Paper exclude: - - os: macos-latest - platform: Bedrock + - os: macos-latest + platform: Bedrock runs-on: ${{ matrix.os }} - name: Test on ${{ matrix.os }} target ${{ matrix.platform }} + name: "${{ matrix.platform }}: Test on ${{ matrix.os }}" steps: - uses: actions/checkout@v3 name: Code checkout @@ -31,7 +29,45 @@ jobs: - name: Install latest java uses: actions/setup-java@v3 - if: matrix.platform == 'Java' || matrix.platform == 'Spigot' || matrix.platform == 'Paper' || matrix.platform == 'Powernukkit' + if: matrix.platform == 'Java' || matrix.platform == 'Paper' || matrix.platform == 'Powernukkit' + with: + distribution: temurin + java-version: "17" + + # Install dependecies + - name: Install nodejs dependencies + run: npm ci + + # Run test + - name: Test + run: npm run test:partial -- tests/${{ matrix.platform }}.ts + + test_needs_build: + strategy: + matrix: + os: + - windows-2019 + - ubuntu-latest + - macos-latest + platform: + - Pocketmine + - Spigot + runs-on: ${{ matrix.os }} + name: "${{ matrix.platform }}: Test on ${{ matrix.os }}" + steps: + - uses: actions/checkout@v3 + name: Code checkout + + # Install basic tools + - uses: actions/setup-node@v3 + name: Setup node.js + with: + node-version: 18.x + registry-url: https://registry.npmjs.org/ + + - name: Install latest java + uses: actions/setup-java@v3 + if: matrix.platform == 'Spigot' with: distribution: temurin java-version: "17" diff --git a/src/globalPlatfroms.ts b/src/globalPlatfroms.ts index 1a46ad2..a8eaf1b 100644 --- a/src/globalPlatfroms.ts +++ b/src/globalPlatfroms.ts @@ -1,5 +1,5 @@ import type { ObjectEncodingOptions } from "node:fs"; -import type javaPlugin from "./plugin/java"; +import type globalPluginManeger from "./plugin/main"; import readline from "node:readline"; import child_process from "node:child_process"; import { EventEmitter } from "node:events"; @@ -35,7 +35,7 @@ export type actionTp = { export type actionPlugin = { name: "pluginManeger", - class: () => javaPlugin + class: () => globalPluginManeger }; export type actionRun = actionsServerStop|actionTp; @@ -74,7 +74,7 @@ export class actions extends EventEmitter { #stopServerFunction: (childProcess: actions) => void = (child) => child.#childProcess.kill("SIGKILL"); #tpfunction?: (childProcess: actions, x: number|string, y: number|string, z: number|string) => void; - public plugin?: javaPlugin; + public plugin?: globalPluginManeger; public portListening: portListen[] = []; public playerActions: playerClass = {}; diff --git a/src/index.ts b/src/index.ts index bcf019c..de71f37 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,4 +4,5 @@ export * as Powernukkit from "./pwnuukit"; export * as Java from "./java"; export * as Spigot from "./spigot"; export * as PaperMC from "./paper"; -export { exportBds, importBds, payloadError } from "./export_import"; \ No newline at end of file +export { exportBds, importBds, payloadError } from "./export_import"; +export { pluginManeger } from "./plugin/main"; \ No newline at end of file diff --git a/src/paper.ts b/src/paper.ts index 46265da..f7c8f54 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -2,7 +2,7 @@ import path from "node:path"; import fs from "node:fs/promises"; import fsOld from "node:fs"; import os from "node:os"; -import plugin_maneger from "./plugin/java"; +import plugin_maneger from "./plugin/main"; import { platformManeger } from "@the-bds-maneger/server_versions"; import { serverRoot, logRoot } from './pathControl'; import { actions, actionConfig } from './globalPlatfroms'; diff --git a/src/plugin/bedrock.ts b/src/plugin/bedrock.ts deleted file mode 100644 index 1682a21..0000000 --- a/src/plugin/bedrock.ts +++ /dev/null @@ -1,60 +0,0 @@ -import path from "node:path"; -import fs from "node:fs/promises"; -import admZip from "adm-zip"; -import { serverPath as pocketmineServerPath } from "../pocketmine"; -import { serverPath as powernukkittServerPath } from "../pwnuukit"; -import { existsSync } from "node:fs"; -import { saveFile } from "../httpRequest"; -const defaultFolder = path.join(__dirname, "plugins"); - -export type pluginPlatform = "pocketmine"|"powernukkit"; -export type pluginConfig = { - name: string, - fileName?: string, - url: string, - type?: "zip"|"jar", - platforms: pluginPlatform[], - dependes?: (string|pluginConfig)[] -}; - -export default class plugin_maneger { - #platform: pluginPlatform = "pocketmine"; - pluginList: pluginConfig[] = []; - getPlatform() {return this.#platform}; - - async #addPlugin (file?: string): Promise { - const config: pluginConfig = JSON.parse(await fs.readFile(path.join(defaultFolder, file), "utf8")); - if (this.pluginList.some(plugin => plugin.name === config.name)) return config; - if (!config.platforms.includes(this.#platform)) return; - this.pluginList.push(config); - if (config.dependes) { - config.dependes = await Promise.all(config.dependes.filter(depend => typeof depend === "string"?depend.startsWith("./"):false).map((depend: string) => this.#addPlugin(depend.replace("./", "")))) as pluginConfig[]; - } - }; - - async installPlugin(name: string) { - const plugin = this.pluginList.find(plugin => plugin.name === name); - if (!plugin) throw new Error(`${name} plugin not avaible to install`); - console.log("Installing %s plugin", plugin.name); - const pluginFolder = path.join(this.#platform === "pocketmine"?pocketmineServerPath:powernukkittServerPath, "plugins"); - if (!existsSync(pluginFolder)) await fs.mkdir(pluginFolder, {recursive: true}); - const saveOut = path.join(pluginFolder, plugin.fileName||`${plugin.name}.${path.extname(plugin.fileName||plugin.url)}`); - await saveFile(plugin.url, {filePath: saveOut}); - if (plugin.type === "zip") { - const zip = new admZip(saveOut); - zip.extractAllTo(pluginFolder, true); - await fs.rm(saveOut, {force: true}); - } - if (plugin.dependes) await Promise.all(plugin.dependes.map((depend: pluginConfig) => this.installPlugin(depend.name))); - } - - async loadPlugins() { - for (const file of await fs.readdir(defaultFolder)) await this.#addPlugin(file); - return this; - } - - constructor(platform: pluginPlatform, autoLoad: boolean = true) { - this.#platform = platform; - if (autoLoad) this.loadPlugins(); - } -}; \ No newline at end of file diff --git a/src/plugin/java.ts b/src/plugin/main.ts similarity index 75% rename from src/plugin/java.ts rename to src/plugin/main.ts index f619337..afc3d4b 100644 --- a/src/plugin/java.ts +++ b/src/plugin/main.ts @@ -1,13 +1,15 @@ import path from "node:path"; import fs from "node:fs/promises"; import admZip from "adm-zip"; -import { serverPath as spigotServerPath } from "../spigot"; -import { serverPath as papertServerPath } from "../paper"; import { existsSync } from "node:fs"; import { saveFile } from "../httpRequest"; +import { serverPath as spigotServerPath } from "../spigot"; +import { serverPath as papertServerPath } from "../paper"; +import { serverPath as pocketmineServerPath } from "../pocketmine"; +import { serverPath as powernukkittServerPath } from "../pwnuukit"; const defaultFolder = path.join(__dirname, "plugins"); -export type pluginPlatform = "spigot"|"paper"; +export type pluginPlatform = "spigot"|"paper"|"pocketmine"|"powernukkit"; export type pluginConfig = { name: string, fileName?: string, @@ -17,7 +19,8 @@ export type pluginConfig = { dependes?: (string|pluginConfig)[] }; -export default class plugin_maneger { +export default pluginManeger; +export class pluginManeger { #platform: pluginPlatform = "spigot"; pluginList: pluginConfig[] = []; getPlatform() {return this.#platform}; @@ -36,8 +39,14 @@ export default class plugin_maneger { const plugin = this.pluginList.find(plugin => plugin.name === name); if (!plugin) throw new Error(`${name} plugin not avaible to install`); console.log("Installing %s plugin", plugin.name); - const pluginFolder = path.join(this.#platform === "spigot"?spigotServerPath:papertServerPath, "plugins"); + let pluginFolder: string; + if (this.#platform === "paper") pluginFolder = path.join(papertServerPath, "plugins"); + else if (this.#platform === "spigot") pluginFolder = path.join(spigotServerPath, "plugins"); + else if (this.#platform === "pocketmine") pluginFolder = path.join(pocketmineServerPath, "plugins"); + else if (this.#platform === "powernukkit") pluginFolder = path.join(powernukkittServerPath, "plugins"); + else throw new Error("Invalid platform"); if (!existsSync(pluginFolder)) await fs.mkdir(pluginFolder, {recursive: true}); + const saveOut = path.join(pluginFolder, plugin.fileName||`${plugin.name}.${path.extname(plugin.fileName||plugin.url)}`); await saveFile(plugin.url, {filePath: saveOut}); if (plugin.type === "zip") { diff --git a/src/spigot.ts b/src/spigot.ts index 465629b..1226377 100644 --- a/src/spigot.ts +++ b/src/spigot.ts @@ -2,7 +2,7 @@ import path from "node:path"; import fs from "node:fs/promises"; import fsOld from "node:fs"; import os from "node:os"; -import plugin_maneger from "./plugin/java"; +import plugin_maneger from "./plugin/main"; import { serverRoot, logRoot, BuildRoot } from './pathControl'; import { execFileAsync } from "./childPromisses"; import { actions, actionConfig } from './globalPlatfroms'; -- 2.50.0 From 1137ed976ba5879d1c014bdea93610f0ec73f295 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 21 Sep 2022 23:56:06 +0000 Subject: [PATCH 05/14] remove default export in plugin maneger --- .github/workflows/test.yml | 1 + src/globalPlatfroms.ts | 2 +- src/paper.ts | 2 +- src/plugin/main.ts | 1 - src/spigot.ts | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7e541b..f7fb99f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,4 +94,5 @@ jobs: # Run test - name: Test + timeout-minutes: 15 run: npm run test:partial -- tests/${{ matrix.platform }}.ts diff --git a/src/globalPlatfroms.ts b/src/globalPlatfroms.ts index a8eaf1b..2593fd2 100644 --- a/src/globalPlatfroms.ts +++ b/src/globalPlatfroms.ts @@ -1,5 +1,5 @@ import type { ObjectEncodingOptions } from "node:fs"; -import type globalPluginManeger from "./plugin/main"; +import type {pluginManeger as globalPluginManeger} from "./plugin/main"; import readline from "node:readline"; import child_process from "node:child_process"; import { EventEmitter } from "node:events"; diff --git a/src/paper.ts b/src/paper.ts index f7c8f54..f924de8 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -2,7 +2,7 @@ import path from "node:path"; import fs from "node:fs/promises"; import fsOld from "node:fs"; import os from "node:os"; -import plugin_maneger from "./plugin/main"; +import { pluginManeger as plugin_maneger } from "./plugin/main"; import { platformManeger } from "@the-bds-maneger/server_versions"; import { serverRoot, logRoot } from './pathControl'; import { actions, actionConfig } from './globalPlatfroms'; diff --git a/src/plugin/main.ts b/src/plugin/main.ts index afc3d4b..6924199 100644 --- a/src/plugin/main.ts +++ b/src/plugin/main.ts @@ -19,7 +19,6 @@ export type pluginConfig = { dependes?: (string|pluginConfig)[] }; -export default pluginManeger; export class pluginManeger { #platform: pluginPlatform = "spigot"; pluginList: pluginConfig[] = []; diff --git a/src/spigot.ts b/src/spigot.ts index 1226377..11d3a70 100644 --- a/src/spigot.ts +++ b/src/spigot.ts @@ -2,7 +2,7 @@ import path from "node:path"; import fs from "node:fs/promises"; import fsOld from "node:fs"; import os from "node:os"; -import plugin_maneger from "./plugin/main"; +import {pluginManeger as plugin_maneger} from "./plugin/main"; import { serverRoot, logRoot, BuildRoot } from './pathControl'; import { execFileAsync } from "./childPromisses"; import { actions, actionConfig } from './globalPlatfroms'; -- 2.50.0 From 85d90a30c0656ce35799b64393953bb678fe3610 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:05:07 -0300 Subject: [PATCH 06/14] Update package version v4.3.0 (#453) Update version v4.3.0 Co-authored-by: Sirherobrine23 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index da31a42..53cb949 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@the-bds-maneger/core", - "version": "4.2.3", + "version": "4.3.0", "description": "A very simple way to manage Minecraft servers", "author": "Sirherobrine23", "license": "GPL-3.0", @@ -49,4 +49,4 @@ "ts-node": "^10.9.1", "typescript": "^4.8.2" } -} +} \ No newline at end of file -- 2.50.0 From 2b0244fc3c2da34ce7c8a21b8fbcbbe53b0111c1 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Thu, 22 Sep 2022 01:52:53 +0000 Subject: [PATCH 07/14] Update plugin maneger Move files to another git repo --- package-lock.json | 4 ++-- src/httpRequest.ts | 17 +++++++++++++++++ src/java.ts | 13 ++++++++++--- src/paper.ts | 6 +++++- src/plugin/main.ts | 18 +++++++++++------- src/plugin/plugins/MobPlugin.json | 8 -------- src/plugin/plugins/SkinsRestorer.json | 7 ------- src/plugin/plugins/dynmap.json | 8 -------- src/plugin/plugins/floodgate.json | 8 -------- src/plugin/plugins/geyser.json | 11 ----------- src/pwnuukit.ts | 13 ++++++++++--- src/spigot.ts | 7 ++++++- tests/Paper.ts | 2 +- 13 files changed, 62 insertions(+), 60 deletions(-) delete mode 100644 src/plugin/plugins/MobPlugin.json delete mode 100644 src/plugin/plugins/SkinsRestorer.json delete mode 100644 src/plugin/plugins/dynmap.json delete mode 100644 src/plugin/plugins/floodgate.json delete mode 100644 src/plugin/plugins/geyser.json diff --git a/package-lock.json b/package-lock.json index dbc57bc..ae3c93c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@the-bds-maneger/core", - "version": "4.2.3", + "version": "4.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@the-bds-maneger/core", - "version": "4.2.3", + "version": "4.3.0", "license": "GPL-3.0", "dependencies": { "@the-bds-maneger/server_versions": "^4.1.2", diff --git a/src/httpRequest.ts b/src/httpRequest.ts index 3055d47..3b04d33 100644 --- a/src/httpRequest.ts +++ b/src/httpRequest.ts @@ -152,3 +152,20 @@ export async function GithubRelease(username: string, repo?: string): Promise(`https://api.github.com/repos/${fullRepo}/releases?per_page=100`); } + +export type githubTree = { + "sha": string, + "url": string, + "truncated": boolean, + "tree": { + "path": string, + "mode": string, + "type": "blob"|"tree", + "sha": string, + "size": number, + "url": string + }[], +}; +export async function githubTree(username: string, repo: string, tree: string) { + return getJSON(`https://api.github.com/repos/${username}/${repo}/git/trees/${tree}?recursive=true`); +} \ No newline at end of file diff --git a/src/java.ts b/src/java.ts index 137a5db..48aedfb 100644 --- a/src/java.ts +++ b/src/java.ts @@ -1,6 +1,7 @@ import path from "node:path"; import fs from "node:fs/promises"; import fsOld from "node:fs"; +import os from "node:os"; import { platformManeger } from "@the-bds-maneger/server_versions"; import { serverRoot, logRoot } from './pathControl'; import { actions, actionConfig } from './globalPlatfroms'; @@ -44,13 +45,19 @@ const serverConfig: actionConfig[] = [ }, ]; -export async function startServer(Config?: {maxMemory?: number, minMemory?: number}) { +export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist."); const command = "java"; const args = ["-jar"]; if (Config) { - if (Config?.minMemory) args.push(`-Xms${Config?.minMemory}m`); - if (Config?.maxMemory) args.push(`-Xmx${Config?.maxMemory}m`); + if (Config.maxFreeMemory) { + const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + if (safeFree > 1000) args.push(`-Xms${safeFree}m`); + else console.warn("There is little ram available!") + } else { + if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`); + if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`); + } } args.push(jarPath, "nogui"); const eula = path.join(serverPath, "eula.txt"); diff --git a/src/paper.ts b/src/paper.ts index f924de8..91ee28d 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -52,7 +52,7 @@ const serverConfig: actionConfig[] = [ }, ]; -export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { +export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, pluginList?: string[]}) { if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist."); const args = []; if (Config) { @@ -64,6 +64,10 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`); if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`); } + if (Config.pluginList) { + const pluginManeger = await (new plugin_maneger("paper")).loadPlugins(); + await Promise.all(Config.pluginList.map(pluginName => pluginManeger.installPlugin(pluginName))); + } } args.push("-jar", jarPath, "nogui"); diff --git a/src/plugin/main.ts b/src/plugin/main.ts index 6924199..5ac83b5 100644 --- a/src/plugin/main.ts +++ b/src/plugin/main.ts @@ -2,21 +2,21 @@ import path from "node:path"; import fs from "node:fs/promises"; import admZip from "adm-zip"; import { existsSync } from "node:fs"; -import { saveFile } from "../httpRequest"; +import { saveFile, githubTree, getJSON } from "../httpRequest"; import { serverPath as spigotServerPath } from "../spigot"; import { serverPath as papertServerPath } from "../paper"; import { serverPath as pocketmineServerPath } from "../pocketmine"; import { serverPath as powernukkittServerPath } from "../pwnuukit"; -const defaultFolder = path.join(__dirname, "plugins"); export type pluginPlatform = "spigot"|"paper"|"pocketmine"|"powernukkit"; export type pluginConfig = { name: string, fileName?: string, url: string, - type?: "zip"|"jar", + type?: "zip"|"jar"|"raw", platforms: pluginPlatform[], - dependes?: (string|pluginConfig)[] + dependes?: (string|pluginConfig)[], + hooksScript?: string }; export class pluginManeger { @@ -25,12 +25,16 @@ export class pluginManeger { getPlatform() {return this.#platform}; async #addPlugin (file?: string): Promise { - const config: pluginConfig = JSON.parse(await fs.readFile(path.join(defaultFolder, file), "utf8")); + // https://raw.githubusercontent.com/The-Bds-Maneger/plugin_list/main/plugins/MobPlugin.json + const config = await getJSON(`https://raw.githubusercontent.com/The-Bds-Maneger/plugin_list/main/${file}`); if (this.pluginList.some(plugin => plugin.name === config.name)) return config; if (!config.platforms?.includes(this.#platform)) return; this.pluginList.push(config); if (config.dependes) { - config.dependes = await Promise.all(config.dependes.filter(depend => typeof depend === "string"?depend.startsWith("./"):false).map((depend: string) => this.#addPlugin(depend.replace("./", "")))) as pluginConfig[]; + config.dependes = await Promise.all(config.dependes.filter(depend => typeof depend === "string"?depend.startsWith("./"):false).map((depend: string) => { + const url = new URL(`https://raw.githubusercontent.com/The-Bds-Maneger/plugin_list/main/${file}`); + return this.#addPlugin(path.join(path.dirname(url.pathname).replace("/The-Bds-Maneger/plugin_list/main/", ""), depend.replace("./", ""))); + })) as pluginConfig[]; } }; @@ -57,7 +61,7 @@ export class pluginManeger { } async loadPlugins() { - for (const file of await fs.readdir(defaultFolder)) await this.#addPlugin(file); + for (const file of (await githubTree("The-Bds-Maneger", "plugin_list", "main")).tree.filter(file => file.path.endsWith(".json"))) await this.#addPlugin(file.path); return this; } diff --git a/src/plugin/plugins/MobPlugin.json b/src/plugin/plugins/MobPlugin.json deleted file mode 100644 index 03da6b1..0000000 --- a/src/plugin/plugins/MobPlugin.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "MobPlugin", - "url": "https://cloudburstmc.org/resources/mobplugin.3/download", - "fileName": "MobPlugin.jar", - "platforms": [ - "powernukkit" - ] -} \ No newline at end of file diff --git a/src/plugin/plugins/SkinsRestorer.json b/src/plugin/plugins/SkinsRestorer.json deleted file mode 100644 index 70e17c5..0000000 --- a/src/plugin/plugins/SkinsRestorer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "SkinsRestorer", - "url": "https://nightly.link/SkinsRestorer/SkinsRestorerX/workflows/build/dev/SkinsRestorer.zip", - "type": "zip", - "fileName": "SkinsRestorer.jar", - "platforms": ["powernukkit"] -} \ No newline at end of file diff --git a/src/plugin/plugins/dynmap.json b/src/plugin/plugins/dynmap.json deleted file mode 100644 index ca5a6cf..0000000 --- a/src/plugin/plugins/dynmap.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "dynmap", - "url": "https://dev.bukkit.org/projects/dynmap/files/latest", - "platforms": [ - "spigot", - "paper" - ] -} \ No newline at end of file diff --git a/src/plugin/plugins/floodgate.json b/src/plugin/plugins/floodgate.json deleted file mode 100644 index 643029f..0000000 --- a/src/plugin/plugins/floodgate.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "Floodgate", - "url": "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/lastSuccessfulBuild/artifact/spigot/build/libs/floodgate-spigot.jar", - "platforms": [ - "spigot", - "paper" - ] -} \ No newline at end of file diff --git a/src/plugin/plugins/geyser.json b/src/plugin/plugins/geyser.json deleted file mode 100644 index d8e3431..0000000 --- a/src/plugin/plugins/geyser.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "Geyser", - "url": "https://ci.opencollab.dev//job/GeyserMC/job/Geyser/job/master/lastSuccessfulBuild/artifact/bootstrap/spigot/target/Geyser-Spigot.jar", - "dependes": [ - "./floodgate.json" - ], - "platforms": [ - "spigot", - "paper" - ] -} \ No newline at end of file diff --git a/src/pwnuukit.ts b/src/pwnuukit.ts index 6c706d4..dce03b9 100644 --- a/src/pwnuukit.ts +++ b/src/pwnuukit.ts @@ -1,6 +1,7 @@ import * as path from "node:path"; import * as fsOld from "node:fs"; import * as fs from "node:fs/promises"; +import os from "node:os"; import { serverRoot, logRoot } from './pathControl'; import { actions, actionConfig } from './globalPlatfroms'; import { platformManeger } from "@the-bds-maneger/server_versions"; @@ -69,7 +70,7 @@ export async function installServer(version: string|boolean) { await fs.writeFile(jarPath, await platformManeger.powernukkit.getJar(version)) } -export async function startServer(Config?: {maxMemory?: number, minMemory?: number}) { +export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist."); const args = [ "-XX:+UseG1GC", @@ -94,8 +95,14 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb "-Daikars.new.flags=true" ]; if (Config) { - if (Config?.minMemory) args.push(`-Xms${Config?.minMemory}m`); - if (Config?.maxMemory) args.push(`-Xmx${Config?.maxMemory}m`); + if (Config.maxFreeMemory) { + const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + if (safeFree > 1000) args.push(`-Xms${safeFree}m`); + else console.warn("There is little ram available!") + } else { + if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`); + if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`); + } } args.push("-jar", jarPath, "--language", "eng"); const logFileOut = path.join(logRoot, `bdsManeger_${Date.now()}_pwnukkit_${process.platform}_${process.arch}.stdout.log`); diff --git a/src/spigot.ts b/src/spigot.ts index 11d3a70..4eabff6 100644 --- a/src/spigot.ts +++ b/src/spigot.ts @@ -88,7 +88,7 @@ const serverConfig: actionConfig[] = [ }, ]; -export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { +export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, pluginList?: string[]}) { if (!fsOld.existsSync(jarPath)) throw new Error("Install server fist."); const args = []; if (Config) { @@ -100,8 +100,13 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb if (Config.minMemory) args.push(`-Xms${Config.minMemory}m`); if (Config.maxMemory) args.push(`-Xmx${Config.maxMemory}m`); } + if (Config.pluginList) { + const pluginManeger = await (new plugin_maneger("spigot")).loadPlugins(); + await Promise.all(Config.pluginList.map(pluginName => pluginManeger.installPlugin(pluginName))); + } } + args.push("-jar", jarPath, "nogui"); const eula = path.join(serverPath, "eula.txt"); await fs.readFile(eula, "utf8").catch(() => "eula=false").then(eulaFile => fs.writeFile(eula, eulaFile.replace("eula=false", "eula=true"))); diff --git a/tests/Paper.ts b/tests/Paper.ts index b3b0c8c..d566d2f 100644 --- a/tests/Paper.ts +++ b/tests/Paper.ts @@ -6,7 +6,7 @@ describe("PaperMC", () => { await paper.installServer("latest"); const plugin = await paper.pluginManger(); await plugin.installPlugin("Geyser"); - const serverManeger = await paper.startServer({}); + const serverManeger = await paper.startServer({maxFreeMemory: true, pluginList: ["Geyser"]}); serverManeger.on("log_stdout", console.log); serverManeger.on("log_stderr", console.info); serverManeger.on("portListening", console.log); -- 2.50.0 From 810989ee022eb2fd2411c4d6b85e47a7caf66fdc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Sep 2022 22:57:13 -0300 Subject: [PATCH 08/14] Update package version v4.3.1 (#454) Update version v4.3.1 Co-authored-by: Sirherobrine23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53cb949..c0069c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@the-bds-maneger/core", - "version": "4.3.0", + "version": "4.3.1", "description": "A very simple way to manage Minecraft servers", "author": "Sirherobrine23", "license": "GPL-3.0", -- 2.50.0 From 099328440be42ccc7a3c21eb46b516b96d13faef Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Thu, 22 Sep 2022 00:53:51 -0300 Subject: [PATCH 09/14] Fix free mem in java --- src/java.ts | 4 ++-- src/paper.ts | 4 ++-- src/pwnuukit.ts | 4 ++-- src/spigot.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/java.ts b/src/java.ts index 48aedfb..a9e15f1 100644 --- a/src/java.ts +++ b/src/java.ts @@ -51,7 +51,7 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb const args = ["-jar"]; if (Config) { if (Config.maxFreeMemory) { - const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + const safeFree = Math.floor(os.freemem()/1e6)-512; if (safeFree > 1000) args.push(`-Xms${safeFree}m`); else console.warn("There is little ram available!") } else { @@ -64,4 +64,4 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb await fs.writeFile(eula, (await fs.readFile(eula, "utf8").catch(() => "eula=false")).replace("eula=false", "eula=true")); const logFileOut = path.join(logRoot, `bdsManeger_${Date.now()}_java_${process.platform}_${process.arch}.stdout.log`); return new actions({command, args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}}, serverConfig); -} \ No newline at end of file +} diff --git a/src/paper.ts b/src/paper.ts index 91ee28d..319ab44 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -57,7 +57,7 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb const args = []; if (Config) { if (Config.maxFreeMemory) { - const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + const safeFree = Math.floor(os.freemem()/1e6)-512; if (safeFree > 1000) args.push(`-Xms${safeFree}m`); else console.warn("There is little ram available!") } else { @@ -75,4 +75,4 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb await fs.writeFile(eula, (await fs.readFile(eula, "utf8").catch(() => "eula=false")).replace("eula=false", "eula=true")); const logFileOut = path.join(logRoot, `bdsManeger_${Date.now()}_spigot_${process.platform}_${process.arch}.stdout.log`); return new actions({command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}}, serverConfig); -} \ No newline at end of file +} diff --git a/src/pwnuukit.ts b/src/pwnuukit.ts index dce03b9..4373758 100644 --- a/src/pwnuukit.ts +++ b/src/pwnuukit.ts @@ -96,7 +96,7 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb ]; if (Config) { if (Config.maxFreeMemory) { - const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + const safeFree = Math.floor(os.freemem()/1e6)-512; if (safeFree > 1000) args.push(`-Xms${safeFree}m`); else console.warn("There is little ram available!") } else { @@ -107,4 +107,4 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb args.push("-jar", jarPath, "--language", "eng"); const logFileOut = path.join(logRoot, `bdsManeger_${Date.now()}_pwnukkit_${process.platform}_${process.arch}.stdout.log`); return new actions({command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}}, serverConfig); -} \ No newline at end of file +} diff --git a/src/spigot.ts b/src/spigot.ts index 4eabff6..0dead3c 100644 --- a/src/spigot.ts +++ b/src/spigot.ts @@ -93,7 +93,7 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb const args = []; if (Config) { if (Config.maxFreeMemory) { - const safeFree = Math.floor(os.freemem() / (1024 * 1024 * 1024))-512; + const safeFree = Math.floor(os.freemem()/1e6)-512; if (safeFree > 1000) args.push(`-Xms${safeFree}m`); else console.warn("There is little ram available!") } else { @@ -112,4 +112,4 @@ export async function startServer(Config?: {maxMemory?: number, minMemory?: numb await fs.readFile(eula, "utf8").catch(() => "eula=false").then(eulaFile => fs.writeFile(eula, eulaFile.replace("eula=false", "eula=true"))); const logFileOut = path.join(logRoot, `bdsManeger_${Date.now()}_spigot_${process.platform}_${process.arch}.stdout.log`); return new actions({command: "java", args, options: {cwd: serverPath, maxBuffer: Infinity, logPath: {stdout: logFileOut}}}, serverConfig); -} \ No newline at end of file +} -- 2.50.0 From e6aa75dabd18ecbeca7ffac50d2499645fc35d63 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Sep 2022 01:07:53 -0300 Subject: [PATCH 10/14] Update package version v4.3.2 (#455) Update version v4.3.2 Co-authored-by: Sirherobrine23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c0069c0..99b9ca0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@the-bds-maneger/core", - "version": "4.3.1", + "version": "4.3.2", "description": "A very simple way to manage Minecraft servers", "author": "Sirherobrine23", "license": "GPL-3.0", -- 2.50.0 From 85533e56e25f95f8f42125b7c56491ebaf4aaa70 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Thu, 22 Sep 2022 14:30:34 +0000 Subject: [PATCH 11/14] Fix log save --- src/globalPlatfroms.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/globalPlatfroms.ts b/src/globalPlatfroms.ts index 2593fd2..860020e 100644 --- a/src/globalPlatfroms.ts +++ b/src/globalPlatfroms.ts @@ -1,8 +1,8 @@ -import type { ObjectEncodingOptions } from "node:fs"; -import type {pluginManeger as globalPluginManeger} from "./plugin/main"; +import fs from "node:fs"; import readline from "node:readline"; import child_process from "node:child_process"; import { EventEmitter } from "node:events"; +import type {pluginManeger as globalPluginManeger} from "./plugin/main"; export type playerClass = {[player: string]: {action: "connect"|"disconnect"|"unknown"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"; date: Date}>}}; export type playerBase = {playerName: string, connectTime: Date, xuid?: string}; @@ -58,7 +58,7 @@ export declare interface actions { once(act: "exit", fn: (data: {code: number, signal: NodeJS.Signals}) => void): this; } -export type actionCommandOption = {command: string, args?: string[], options?: ObjectEncodingOptions & child_process.ExecFileOptions & {logPath?: {stdout: string, stderr?: string}}}; +export type actionCommandOption = {command: string, args?: string[], options?: fs.ObjectEncodingOptions & child_process.ExecFileOptions & {logPath?: {stdout: string, stderr?: string}}}; export class actions extends EventEmitter { #childProcess: child_process.ChildProcess; public runCommand(...command: Array) { @@ -111,6 +111,11 @@ export class actions extends EventEmitter { this.processConfig = processConfig; this.#childProcess = child_process.execFile(processConfig.command, processConfig.args, processConfig.options); + if (processConfig.options.logPath) { + this.#childProcess.stdout.pipe(fs.createWriteStream(processConfig.options.logPath.stdout)); + if (processConfig.options.logPath.stderr) this.#childProcess.stderr.pipe(fs.createWriteStream(processConfig.options.logPath.stderr)); + } + this.#childProcess.on("error", data => this.emit("error", data)); this.#childProcess.on("close", (code, signal) => this.emit("exit", {code, signal})); const readlineStdout = readline.createInterface(this.#childProcess.stdout); -- 2.50.0 From 60b1489fb22b8e97793aaf802a4919a1cee305cd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Sep 2022 13:58:18 -0300 Subject: [PATCH 12/14] Update package version v4.3.3 (#456) Update version v4.3.3 Co-authored-by: Sirherobrine23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99b9ca0..9d5c166 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@the-bds-maneger/core", - "version": "4.3.2", + "version": "4.3.3", "description": "A very simple way to manage Minecraft servers", "author": "Sirherobrine23", "license": "GPL-3.0", -- 2.50.0 From 931f1209ec230c739fc27db7775523fa5145ae85 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Thu, 22 Sep 2022 22:36:21 +0000 Subject: [PATCH 13/14] Update all platforms I'm releasing some improvements, now you should use `playerAuctions` instead of `playerConnect`, `playerDisconnect` or `playerUnknown`, I'm still migrating some platforms. I removed linkWorld for now I will be migrating its links to each platform, and I will only allow it on Linux. I changed the Export/Import of bds to solve some implementation issues --- package-lock.json | 4 +- src/bedrock.ts | 15 +++--- src/childPromisses.ts | 75 +-------------------------- src/export_import.ts | 112 ++++++++++++++++++++++------------------- src/globalPlatfroms.ts | 34 ++++++++----- src/index.ts | 7 +-- src/java.ts | 8 +-- src/linkWorld.ts | 32 ------------ src/paper.ts | 7 +-- src/plugin/main.ts | 3 +- src/pocketmine.ts | 1 - src/pwnuukit.ts | 15 +++--- src/spigot.ts | 47 +++++++++++++---- 13 files changed, 151 insertions(+), 209 deletions(-) delete mode 100644 src/linkWorld.ts diff --git a/package-lock.json b/package-lock.json index ae3c93c..06a5ad2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@the-bds-maneger/core", - "version": "4.3.0", + "version": "4.3.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@the-bds-maneger/core", - "version": "4.3.0", + "version": "4.3.3", "license": "GPL-3.0", "dependencies": { "@the-bds-maneger/server_versions": "^4.1.2", diff --git a/src/bedrock.ts b/src/bedrock.ts index e502fe9..81b0829 100644 --- a/src/bedrock.ts +++ b/src/bedrock.ts @@ -8,27 +8,30 @@ import { execAsync } from "./childPromisses"; import { actions, actionConfig } from "./globalPlatfroms"; import { serverRoot, logRoot } from './pathControl'; import * as Proprieties from "./Proprieties"; +import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "Bedrock"); -export { bedrockServerWorld, bedrockWorld, linkBedrock } from "./linkWorld"; // RegExp export const saveFileFolder = /^(worlds|server\.properties|config|((permissions|allowlist|valid_known_packs)\.json)|(development_.*_packs))$/; export const portListen = /\[.*\]\s+(IPv[46])\s+supported,\s+port:\s+([0-9]+)/; export const started = /\[.*\]\s+Server\s+started\./; -// [2022-08-30 20:50:53:821 INFO] Player connected: Sirherobrine, xuid: 111111111111111 -// [2022-08-30 20:56:55:231 INFO] Player disconnected: Sirherobrine, xuid: 111111111111111 export const player = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/; -// [2022-08-30 20:56:55:601 INFO] Running AutoCompaction... export const compressWorld = /\[.*\]\s+Running\s+AutoCompaction/; export async function installServer(version: string|boolean) { - const zip = new admZip(await platformManeger.bedrock.getBedrockZip(version, {})); + const bedrockData = await platformManeger.bedrock.find(version); + const zip = new admZip(await saveFile(bedrockData.url[process.platform])); if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); // Remover files - for (const file of await fs.readdir(serverPath).then(files => files.filter(file => !saveFileFolder.test(file)))) await fs.rm(path.join(serverPath, file), {recursive: true, force: true}); + await fs.readdir(serverPath).then(files => files.filter(file => !saveFileFolder.test(file))).then(files => Promise.all(files.map(file => fs.rm(path.join(serverPath, file), {recursive: true, force: true})))); const serverConfig = (await fs.readFile(path.join(serverPath, "server.properties"), "utf8").catch(() => "")).trim(); await promisify(zip.extractAllToAsync)(serverPath, true, true); if (serverConfig) await fs.writeFile(path.join(serverPath, "server.properties"), serverConfig); + return { + version: bedrockData.version, + date: bedrockData.date, + url: bedrockData.url[process.platform] + }; } const serverConfig: actionConfig[] = [ diff --git a/src/childPromisses.ts b/src/childPromisses.ts index 0c7b248..ad7a8da 100644 --- a/src/childPromisses.ts +++ b/src/childPromisses.ts @@ -1,7 +1,5 @@ -import { ObjectEncodingOptions, createWriteStream, WriteStream } from "node:fs"; +import type { ObjectEncodingOptions } from "node:fs"; import * as child_process from "node:child_process"; -import { EventEmitter } from "node:events"; -import { createInterface } from "node:readline"; export const execFile = child_process.execFile; export type ExecFileOptions = ObjectEncodingOptions & child_process.ExecFileOptions & {stdio?: "ignore"|"inherit"}; @@ -39,75 +37,4 @@ export function execAsync(command: string, options?: execAsyncOptions) { child.stderr.on("data", data => process.stderr.write(data)); } }); -} - - -export declare interface customChild { - emit(act: "error", data: Error): boolean; - emit(act: "close", data: {code: number, signal: NodeJS.Signals}): boolean; - emit(act: "stdoutRaw", data: string): boolean; - emit(act: "stderrRaw", data: string): boolean; - emit(act: "stdout", data: string): boolean; - emit(act: "stderr", data: string): boolean; - - on(act: "error", fn: (data: Error) => void): this; - on(act: "close", fn: (data: {code: number, signal: NodeJS.Signals}) => void): this; - on(act: "stdoutRaw", fn: (data: string) => void): this; - on(act: "stderrRaw", fn: (data: string) => void): this; - on(act: "stdout", dn: (data: string) => void): this; - on(act: "stderr", fn: (data: string) => void): this; - - once(act: "error", fn: (data: Error) => void): this; - once(act: "close", fn: (data: {code: number, signal: NodeJS.Signals}) => void): this; - once(act: "stdoutRaw", fn: (data: string) => void): this; - once(act: "stderrRaw", fn: (data: string) => void): this; - once(act: "stdout", dn: (data: string) => void): this; - once(act: "stderr", fn: (data: string) => void): this; -} - -export class customChild extends EventEmitter { - public child: child_process.ChildProcess; - public kill(signal?: number|NodeJS.Signals) {if(this.child?.killed) return this.child?.killed;return this.child?.kill(signal);} - - public writeStdin(command: string, args?: string[]) { - let toWrite = command; - if (args?.length > 0) toWrite += (" "+args.join(" ")); - toWrite+="\n"; - this.child.stdin.write(toWrite); - } - - constructor(child: child_process.ChildProcess, logStream?: {stdout: WriteStream, stderr?: WriteStream}) { - super({captureRejections: false}); - this.child = child; - if (logStream) { - this.child.stdout.pipe(logStream.stdout); - if (logStream.stderr) this.child.stderr.pipe(logStream.stderr); - } - this.child.on("close", (code, signal) => this.emit("close", {code, signal})); - this.child.on("exit", (code, signal) => this.emit("close", {code, signal})); - this.child.on("error", err => this.emit("error", err)); - const stdoutBreak = createInterface(this.child.stdout); - const stderrBreak = createInterface(this.child.stderr); - stdoutBreak.on("line", line => this.emit("stdout", line)); - stderrBreak.on("line", line => this.emit("stderr", line)); - } -}; - -export type execOptions = ObjectEncodingOptions & child_process.ExecFileOptions & {logPath?: {stdout: string, stderr?: string}}; -export function exec(command: string): customChild; -export function exec(command: string, args: string[]): customChild; -export function exec(command: string, options: execOptions): customChild; -export function exec(command: string, args: string[], options: execOptions): customChild; -export function exec(command: string, args?: execOptions|string[], options?: execOptions): customChild { - let childOptions: execOptions = {}; - let childArgs: string[] = []; - if (args instanceof Array) childArgs = args; else if (args instanceof Object) childOptions = args as execOptions; - if (options) childOptions = options; - if (childOptions?.env) childOptions.env = {...process.env, ...childOptions.env}; - let logStream: undefined|{stdout: WriteStream, stderr?: WriteStream} = undefined; - if (childOptions.logPath) logStream = { - stdout: createWriteStream(childOptions.logPath.stdout, {flags: "a", autoClose: true}), - stderr: (!!childOptions.logPath.stderr)?createWriteStream(childOptions.logPath.stderr, {flags: "a", autoClose: true}):undefined - }; - return new customChild(execFile(command, childArgs, childOptions), logStream); } \ No newline at end of file diff --git a/src/export_import.ts b/src/export_import.ts index 835636a..0060cae 100644 --- a/src/export_import.ts +++ b/src/export_import.ts @@ -5,7 +5,6 @@ import tar from "tar"; import { bdsRoot } from "./pathControl"; export type payload = { - raw?: string, httpVersion?: string, request?: { method: string, @@ -15,24 +14,29 @@ export type payload = { code: number, text: string }, - header: {[key: string]: string|boolean|number}, + header?: {[key: string]: string|boolean|number}, second?: payload, - body?: any + body?: any, + raw?: string, }; -const payloadRequest = /^(GET|POST|CONNECT|HEAD|PUT|DELETE)\s+(.*)\s+HTTP\/([0-9\.]+)/; -const payloadResponse = /HTTP\/([0-9\.]+)\s+([0-9]+)\s+([\w\S\s]+)/; -const parseHeard = /^([0-9A-Za-z\._-\s@]+):([\w\S\s]+)/; - export class payloadError extends Error { - public payload: payload + public payload: payload; constructor(errMessage: string, payload: payload) { super(errMessage); this.payload = payload; } } -function parsePayload(data: string): payload { +const payloadRequest = /^(GET|POST|CONNECT|HEAD|PUT|DELETE)\s+(.*)\s+HTTP\/([0-9\.]+)/; +const payloadResponse = /HTTP\/([0-9\.]+)\s+([0-9]+)\s+([\w\S\s]+)/; +const parseHeard = /^([0-9A-Za-z\._-\s@]+):([\w\S\s]+)/; +async function parsePayload(input: string|Buffer|net.Socket): Promise { + let data = ""; + if (typeof input === "string") data = input; else { + if (Buffer.isBuffer(input)) data = input.toString("utf8"); + else data = await new Promise(done => input.once("data", dataInput => done(dataInput.toString("utf8")))) + } const payloadBody: payload = {raw: data, header: {}}; if (/^{.*}$/.test(data.replace(/\r?\n/, ""))) { payloadBody.body = JSON.parse(data); @@ -56,7 +60,7 @@ function parsePayload(data: string): payload { path: reqPath }; continue; - } else payloadBody.second = parsePayload(`${line}\r\n${data}`); + } else payloadBody.second = await parsePayload(`${line}\r\n${data}`); break; } else if (parseHeard.test(line.trim())) { const [, key, value] = line.trim().match(parseHeard); @@ -82,62 +86,68 @@ function parsePayload(data: string): payload { return payloadBody; } -function stringifyPayload(options: {code: number, message: string, headers?: {[keyName: string]: string|number|boolean}, body?: any}, socket: net.Socket) { - let message = `HTTP/1.0 ${options.code} ${options.message}\r\n`; - if (options.headers) Object.keys(options.headers).forEach(key => `${key}: ${options.headers[key]}\r\n`); +function stringifyPayload(socket: net.Socket, response: payload) { + let message = ""; + if (response.request) message += `${response.request.method.toUpperCase()} ${response.request.path} HTTP/${response.httpVersion||"1.0"}\r\n`; + else message += `HTTP/${response.httpVersion||"1.0"} ${response.response.code} ${response.response.text}\r\n`; + if (response.header) Object.keys(response.header).forEach(key => `${key}: ${response.header[key]}\r\n`); message += "\r\n"; - if (options.body) message += JSON.stringify(options.body); - socket.write(message+"\r\n"); - if (options.code !== 200) socket.end(); + if (response.body !== undefined) { + if (Array.isArray(response.body)||typeof response.body === "object") message += JSON.stringify(response.body); + else if (typeof response.body === "string") message += response.body; + else if (typeof response.body === "bigint") message += response.body.toString(); + else message += String(response.body); + } + socket.write(message); return socket; } -export function exportBds() { - const server = net.createServer(); - let newConnection = false; - const authToken = crypto.randomBytes(8).toString("base64"); - server.on("connection", async (socket): Promise => { - if (newConnection) return stringifyPayload({code: 400, message: "Server locked", body: {errro: "Server locked"}}, socket); - const payload = parsePayload(await new Promise(done => socket.once("data", res => done(res.toString("utf8"))))); +export class exportBds { + public acceptConnection = true; + public authToken = crypto.randomBytes(16).toString("base64"); + #server = net.createServer(async (socket): Promise => { + if (!this.acceptConnection) return stringifyPayload(socket, {response: {code: 400, text: "Server locked"}, body: {erro: "Server locked"}}).end(); + const payload = await parsePayload(await new Promise(done => socket.once("data", res => done(res.toString("utf8"))))); console.log(payload); - if (payload.header.Authorization !== authToken) return stringifyPayload({code: 401, message: "Not allowed", body: {error: "Invalid token"}}, socket); - else stringifyPayload({code: 200, message: "Success", headers: {Date: (new Date()).toISOString(), "Content-Type": "bdsStream/tar"}}, socket); - newConnection = true; + if (payload.header.Authorization !== this.authToken) return stringifyPayload(socket, {response: {code: 401, text: "Not allowed"}, body: {error: "Invalid token"}}).end(); + else stringifyPayload(socket, {response: {code: 200, text: "Success"}, header: {Date: (new Date()).toISOString(), "Content-Type": "bdsStream/tar"}}); + this.acceptConnection = false; console.log("Sending to %s", socket.localAddress+":"+socket.localPort); // Compact bds root const tarCompress = tar.create({gzip: true, cwd: bdsRoot}, await fs.readdir(bdsRoot)); tarCompress.pipe(socket); - tarCompress.on("end", () => server.close()); + tarCompress.on("data", ({length}) => console.log("Send to %s, size: %f", socket.localAddress+":"+socket.localPort, length)); + tarCompress.on("end", () => this.#server.close()); }); - return { - authToken, - server, - listen() { - return new Promise(done => { - server.listen(() => { - console.log("Port listen on http://0.0.0.0:%s/, auth token '%s'", server.address()["port"], authToken); - done(server.address()["port"]); - }); + + public async listen(port = 0) { + return new Promise(done => { + this.#server.listen(port, () => { + let address = this.#server.address()["address"], port = this.#server.address()["port"]; + if (/::/.test(address)) address = `[${address}]`; + console.log("Port listen on http://%s:%s/, auth token '%s'", address, port, this.authToken); + return done(port); }); - }, - PromisseWait: new Promise((done) => { - server.once("close", () => { - console.log("Export end"); - done(); - }); - }) - }; + }); + } + public async waitClose() { + return new Promise((done, reject) => { + this.#server.on("error", reject); + this.#server.once("close", done); + }); + } } -export async function importBds(host: string, port: number, authToken: string) { - const client = net.createConnection({host, port}); - client.write(`GET / HTTP/1.0\r\nAuthorization: ${authToken}\r\n\r\n`); - parsePayload(await new Promise(done => client.once("data", res => done(res.toString("utf8"))))); - const tarE = tar.extract({cwd: bdsRoot, noChmod: false, noMtime: false, preserveOwner: true}); - client.pipe(tarE); +export async function importBds(option: {host: string, port: number, authToken: string}) { + await fs.rename(bdsRoot, bdsRoot+"_backup_"+Date.now()); + const client = stringifyPayload(net.createConnection({host: option.host, port: option.port}), {request: {method: "GET", path: "/"}, header: {Authorization: option.authToken}}); + await parsePayload(client); + const tar_extract = tar.extract({cwd: bdsRoot, noChmod: false, noMtime: false, preserveOwner: true}); + client.pipe(tar_extract); + client.on("data", ({length}) => console.log("Recive size: %f", length)); return new Promise((done, reject) => { client.once("close", () => done()); client.on("error", reject); - tarE.on("error", reject); + tar_extract.on("error", reject); }); } \ No newline at end of file diff --git a/src/globalPlatfroms.ts b/src/globalPlatfroms.ts index 860020e..5dd3807 100644 --- a/src/globalPlatfroms.ts +++ b/src/globalPlatfroms.ts @@ -5,11 +5,15 @@ import { EventEmitter } from "node:events"; import type {pluginManeger as globalPluginManeger} from "./plugin/main"; export type playerClass = {[player: string]: {action: "connect"|"disconnect"|"unknown"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"; date: Date}>}}; -export type playerBase = {playerName: string, connectTime: Date, xuid?: string}; +export type playerBase = {playerName: string, connectTime: Date, xuid?: string, action?: string}; export type actionsPlayer = { name: "playerConnect"|"playerDisconnect"|"playerUnknown", callback: (data: string, done: (player: playerBase) => void) => void } +export type newPlayerAction = { + name: "playerAction", + callback: (data: string, playerConect: (player: playerBase) => void, playerDisconnect: (player: playerBase) => void, playerUnknown: (player: playerBase) => void) => void +}; export type portListen = {port: number, host?: string, type: "TCP"|"UDP"|"TCP/UDP", protocol: "IPv4"|"IPv6"|"IPV4/IPv6"|"Unknown", plugin?: string}; export type actionsPort = { @@ -39,7 +43,7 @@ export type actionPlugin = { }; export type actionRun = actionsServerStop|actionTp; -export type actionCallback = actionsPlayer|actionsPort|actionsServerStarted|actionsServerStarted; +export type actionCallback = actionsPlayer|newPlayerAction|actionsPort|actionsServerStarted|actionsServerStarted; export type actionConfig = actionCallback|actionRun|actionPlugin; export declare interface actions { @@ -65,19 +69,16 @@ export class actions extends EventEmitter { this.#childProcess.stdin.write(command.map(a => String(a)).join(" ")+"\n"); return this; } - public killProcess(signal?: number|NodeJS.Signals) { if(this.#childProcess?.killed) return this.#childProcess?.killed; return this.#childProcess?.kill(signal); } - #stopServerFunction: (childProcess: actions) => void = (child) => child.#childProcess.kill("SIGKILL"); - #tpfunction?: (childProcess: actions, x: number|string, y: number|string, z: number|string) => void; - public plugin?: globalPluginManeger; - public portListening: portListen[] = []; public playerActions: playerClass = {}; + #stopServerFunction: (actions: actions) => void = (child) => child.#childProcess.kill("SIGKILL"); + #tpfunction?: (actions: actions, playerName: string, x: number|string, y: number|string, z: number|string) => void = (actions, playerName, x,y,z) => actions.runCommand("tp", playerName, x,y,z); public stopServer() { if (typeof this.stopServer === "undefined") this.#childProcess.kill("SIGKILL"); @@ -85,7 +86,7 @@ export class actions extends EventEmitter { return this.waitExit(); } - public waitExit(): Promise { + public async waitExit(): Promise { if (this.#childProcess.exitCode === null) return new Promise((done, reject) => { this.#childProcess.once("error", err => reject(err)); this.#childProcess.once("exit", code => { @@ -93,12 +94,12 @@ export class actions extends EventEmitter { reject(new Error(`Server exit with ${code} code.`)); }); }); - return Promise.resolve(this.#childProcess.exitCode); + return this.#childProcess.exitCode; } - public tp(x: number|string = 0, y: number|string = 0, z: number|string = 0) { - if (typeof this.stopServer === "undefined") throw new Error("TP command not configured!"); - this.#tpfunction(this, x, y, z); + public tp(playerName: string, x: number|string = 0, y: number|string = 0, z: number|string = 0) { + if (!(playerName.startsWith("@")||!!this.playerActions[playerName])) throw new Error("Player or target not exist"); + this.#tpfunction(this, playerName, x, y, z); return this; } @@ -161,6 +162,13 @@ export class actions extends EventEmitter { // Callbacks (config.filter((a: actionCallback) => typeof a?.callback === "function") as actionCallback[]).forEach(fn => { + // Use new player actions + if (fn.name === "playerAction") { + const playerConnect = (data: playerBase) => this.emit("playerConnect", data), playerDisonnect = (data: playerBase) => this.emit("playerDisconnect", data), playerUnknown = (data: playerBase) => this.emit("playerUnknown", data); + this.on("log_stdout", data => fn.callback(data, playerConnect, playerDisonnect, playerUnknown)); + this.on("log_stderr", data => fn.callback(data, playerConnect, playerDisonnect, playerUnknown)); + return; + } else if (fn.name === "playerConnect"||fn.name === "playerDisconnect"||fn.name === "playerUnknown") console.warn("Migrate %s to playerAction", fn.name); this.on("log_stdout", data => fn.callback(data, (...args: any[]) => this.emit(fn.name, ...args))); this.on("log_stderr", data => fn.callback(data, (...args: any[]) => this.emit(fn.name, ...args))); }); @@ -173,7 +181,7 @@ export class actions extends EventEmitter { // Plugin maneger (config.filter((a: actionPlugin) => !!a?.class) as actionPlugin[]).forEach(action => { - if (action.name === "pluginManeger") this.plugin = action.class(); + if (action.name === "pluginManeger") (action.class()).loadPlugins().then(maneger => this.plugin = maneger); }); } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index de71f37..ffdff62 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,9 @@ +export { exportBds, importBds, payloadError } from "./export_import"; +export { pluginManeger } from "./plugin/main"; +export * as globalPlatfroms from "./globalPlatfroms"; export * as Bedrock from "./bedrock"; export * as PocketmineMP from "./pocketmine"; export * as Powernukkit from "./pwnuukit"; export * as Java from "./java"; export * as Spigot from "./spigot"; -export * as PaperMC from "./paper"; -export { exportBds, importBds, payloadError } from "./export_import"; -export { pluginManeger } from "./plugin/main"; \ No newline at end of file +export * as PaperMC from "./paper"; \ No newline at end of file diff --git a/src/java.ts b/src/java.ts index a9e15f1..a50d30c 100644 --- a/src/java.ts +++ b/src/java.ts @@ -3,17 +3,17 @@ import fs from "node:fs/promises"; import fsOld from "node:fs"; import os from "node:os"; import { platformManeger } from "@the-bds-maneger/server_versions"; -import { serverRoot, logRoot } from './pathControl'; -import { actions, actionConfig } from './globalPlatfroms'; +import { serverRoot, logRoot } from "./pathControl"; +import { actions, actionConfig } from "./globalPlatfroms"; +import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "java"); const jarPath = path.join(serverPath, "server.jar"); export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; -// [21:37:27] [Server thread/INFO]: Starting Minecraft server on *:25565 export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); - await fs.writeFile(jarPath, await platformManeger.java.getJar(version)); + return platformManeger.java.find(version).then(release => saveFile(release.url, {filePath: jarPath}).then(() => release)); } const serverConfig: actionConfig[] = [ diff --git a/src/linkWorld.ts b/src/linkWorld.ts deleted file mode 100644 index 28a646c..0000000 --- a/src/linkWorld.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as path from "node:path"; -import * as fs from "node:fs/promises"; -import { existsSync as fsExistsSync } from "node:fs"; -import { worldFolder } from "./pathControl"; -import { serverPath as bedrockServerPath } from "./bedrock"; -import { serverPath as pocketmineServerPath } from "./pocketmine"; - -export const bedrockWorld = path.join(worldFolder, "bedrock"); -export const bedrockServerWorld = path.join(bedrockServerPath, "worlds"); -export async function linkBedrock() { - if (!fsExistsSync(bedrockWorld)) await fs.mkdir(bedrockWorld, {recursive: true}); - if (fsExistsSync(bedrockServerWorld)) { - if (await fs.realpath(bedrockWorld) === bedrockServerWorld) return; - for (const folder of await fs.readdir(bedrockServerWorld)) await fs.cp(path.join(bedrockServerWorld, folder), path.join(bedrockWorld, folder), {recursive: true, force: true, preserveTimestamps: true, verbatimSymlinks: true}); - if (!fsExistsSync(bedrockServerWorld+"_backup")) await fs.rename(bedrockServerWorld, bedrockServerWorld+"_backup"); - } - await fs.symlink(bedrockWorld, bedrockServerWorld); - return; -} - -export const pocketmineWorld = path.join(worldFolder, "pocketmine"); -export const pocketmineServerWorld = path.join(pocketmineServerPath, "worlds"); -export async function linkPocketmine() { - if (!fsExistsSync(pocketmineWorld)) await fs.mkdir(pocketmineWorld, {recursive: true}); - if (fsExistsSync(pocketmineServerWorld)) { - if (await fs.realpath(pocketmineWorld) === pocketmineServerWorld) return; - for (const folder of await fs.readdir(pocketmineServerWorld)) await fs.cp(path.join(pocketmineServerWorld, folder), path.join(pocketmineWorld, folder), {recursive: true, force: true, preserveTimestamps: true, verbatimSymlinks: true}); - if (!fsExistsSync(pocketmineServerWorld+"_backup")) await fs.rename(pocketmineServerWorld, pocketmineServerWorld+"_backup"); - } - await fs.symlink(pocketmineWorld, pocketmineServerWorld); - return; -} \ No newline at end of file diff --git a/src/paper.ts b/src/paper.ts index 319ab44..5547029 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -4,8 +4,9 @@ import fsOld from "node:fs"; import os from "node:os"; import { pluginManeger as plugin_maneger } from "./plugin/main"; import { platformManeger } from "@the-bds-maneger/server_versions"; -import { serverRoot, logRoot } from './pathControl'; -import { actions, actionConfig } from './globalPlatfroms'; +import { serverRoot, logRoot } from "./pathControl"; +import { actions, actionConfig } from "./globalPlatfroms"; +import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "Papermc"); const jarPath = path.join(serverPath, "server.jar"); export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; @@ -13,7 +14,7 @@ export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9 export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); - await fs.writeFile(jarPath, await platformManeger.paper.getJar(version)); + return platformManeger.paper.find(version).then(release => saveFile(release.url, {filePath: jarPath}).then(() => release)); } export const pluginManger = () => (new plugin_maneger("paper", false)).loadPlugins(); diff --git a/src/plugin/main.ts b/src/plugin/main.ts index 5ac83b5..3359570 100644 --- a/src/plugin/main.ts +++ b/src/plugin/main.ts @@ -15,8 +15,7 @@ export type pluginConfig = { url: string, type?: "zip"|"jar"|"raw", platforms: pluginPlatform[], - dependes?: (string|pluginConfig)[], - hooksScript?: string + dependes?: (string|pluginConfig)[] }; export class pluginManeger { diff --git a/src/pocketmine.ts b/src/pocketmine.ts index 63cd3a5..a9c6745 100644 --- a/src/pocketmine.ts +++ b/src/pocketmine.ts @@ -13,7 +13,6 @@ import { promisify } from 'node:util'; export const serverPath = path.join(serverRoot, "pocketmine"); export const serverPhar = path.join(serverPath, "pocketmine.phar"); export const phpBinPath = path.join(serverPath, "bin", (process.platform === "win32"?"php":"bin"), "php"); -export { pocketmineServerWorld, pocketmineWorld, linkPocketmine } from "./linkWorld"; async function Readdir(pathRead: string, filter?: RegExp[]) { if (!filter) filter = [/.*/]; diff --git a/src/pwnuukit.ts b/src/pwnuukit.ts index 4373758..37e2f57 100644 --- a/src/pwnuukit.ts +++ b/src/pwnuukit.ts @@ -5,14 +5,10 @@ import os from "node:os"; import { serverRoot, logRoot } from './pathControl'; import { actions, actionConfig } from './globalPlatfroms'; import { platformManeger } from "@the-bds-maneger/server_versions"; +import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "power_nukkit"); const jarPath = path.join(serverPath, "pwnukkit.jar"); -export const portListen = /Opening\s+server\s+on\s+(([A-Za-z0-9:\.]+):([0-9]+))/; -// 14:19:28 [INFO ] Sirherobrine joined the game -// 14:25:10 [INFO ] Sirherobrine left the game -export const playerAction = /^.*\[.*\]\s(\S+)\s+(left|joined)\s+the\s+game$/; - const serverConfig: actionConfig[] = [ { name: "serverStop", @@ -28,6 +24,7 @@ const serverConfig: actionConfig[] = [ { name: "portListening", callback(data, done) { + const portListen = /Opening\s+server\s+on\s+(([A-Za-z0-9:\.]+):([0-9]+))/; if (portListen.test(data)) { const [,, host, port] = data.match(portListen); done({ @@ -42,24 +39,26 @@ const serverConfig: actionConfig[] = [ { name: "playerConnect", callback(data, done) { + const playerAction = /^.*\[.*\]\s(\S+)\s+(left|joined)\s+the\s+game$/; if (playerAction.test(data)) { const [,playerName, action] = data.match(playerAction); if (action === "joined") done({ connectTime: new Date(), playerName, - }) + }); } }, }, { name: "playerDisconnect", callback(data, done) { + const playerAction = /^.*\[.*\]\s(\S+)\s+(left|joined)\s+the\s+game$/; if (playerAction.test(data)) { const [,playerName, action] = data.match(playerAction); if (action === "left") done({ connectTime: new Date(), playerName, - }) + }); } }, }, @@ -67,7 +66,7 @@ const serverConfig: actionConfig[] = [ export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); - await fs.writeFile(jarPath, await platformManeger.powernukkit.getJar(version)) + return platformManeger.powernukkit.find(version).then(release => saveFile(release.url, {filePath: jarPath}).then(() => release)); } export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { diff --git a/src/spigot.ts b/src/spigot.ts index 0dead3c..c3ead2d 100644 --- a/src/spigot.ts +++ b/src/spigot.ts @@ -6,31 +6,46 @@ import {pluginManeger as plugin_maneger} from "./plugin/main"; import { serverRoot, logRoot, BuildRoot } from './pathControl'; import { execFileAsync } from "./childPromisses"; import { actions, actionConfig } from './globalPlatfroms'; -import { getBuffer } from "./httpRequest"; +import { getBuffer, getJSON, saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "spigot"); export const serverPathBuild = path.join(BuildRoot, "spigot"); const jarPath = path.join(serverPath, "server.jar"); -export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; -export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; -// [18:38:32] [Network Listener - #3/INFO]: [Geyser-Spigot] Started Geyser on 0.0.0.0:19132 -export const geyserPortListen = /^\[.*\].*Geyser.*\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9:]+):([0-9]+))/; -// [00:40:18] [Server thread/INFO]: [dynmap] Web server started on address 0.0.0.0:8123 -export const DynmapPortListen = /^\[.*\].*\[dynmap\].*\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9:]+):([0-9]+))/; + +async function listVersions() { + const data = (await getBuffer("https://hub.spigotmc.org/versions/")).toString("utf8").split("\r").filter(line => /\.json/.test(line)).map(line => {const [, data] = line.match(/>(.*)<\//); return data?.replace(".json", "");}).filter(ver => /^[0-9]+\./.test(ver)); + data.push("latest"); + return Promise.all(data.map(async (version) => { + const data = await getJSON<{name: string, description: string, toolsVersion: number, javaVersions?: number[], refs: {BuildData: string, Bukkit: string, CraftBukkit: string, Spigot: string}}>(`https://hub.spigotmc.org/versions/${version}.json`); + return { + version, + date: new Date((await getJSON(`https://hub.spigotmc.org/stash/rest/api/latest/projects/SPIGOT/repos/spigot/commits/${data.refs.Spigot}/`)).committerTimestamp), + data, + }; + })); +} export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); - if (!fsOld.existsSync(serverPathBuild)) await fs.mkdir(serverPathBuild, {recursive: true}); if (typeof version === "boolean") version = "latest"; - await fs.writeFile(path.join(serverPathBuild, "buildSpigot.jar"), await getBuffer("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar")); + const versions = (await listVersions()).find(ver => ver.version === version); + if (!versions) throw new Error("Version dont exists"); + await saveFile("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar", {filePath: path.join(serverPathBuild, "buildSpigot.jar")}); await execFileAsync("java", ["-jar", path.join(serverPathBuild, "buildSpigot.jar"), "-o", path.join(serverPathBuild, "output"), "--rev", version], {stdio: "inherit", cwd: serverPathBuild}); - await fs.cp(path.join(serverPathBuild, "output", (await fs.readdir(path.join(serverPathBuild, "output")))[0]), jarPath, {force: true, preserveTimestamps: true}); + await fs.cp(path.join(serverPathBuild, "output", (await fs.readdir(path.join(serverPathBuild, "output"))).find(file => file.endsWith(".jar"))), jarPath, {force: true, preserveTimestamps: true}); await fs.rm(path.join(serverPathBuild, "output"), {recursive: true, force: true}); + return versions; } export const pluginManger = () => (new plugin_maneger("spigot", false)).loadPlugins(); + +export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; +export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; +export const geyserPortListen = /^\[.*\].*Geyser.*\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9:]+):([0-9]+))/; +export const DynmapPortListen = /^\[.*\].*\[dynmap\].*\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9:]+):([0-9]+))/; +export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/; const serverConfig: actionConfig[] = [ { name: "serverStop", @@ -86,6 +101,18 @@ const serverConfig: actionConfig[] = [ } } }, + { + name: "playerAction", + callback(data, playerConect, playerDisconnect, playerUnknown) { + if (playerAction.test(data)) { + const [, playerName, action] = data.match(data)||[]; + if (action === "joined") playerConect({playerName, connectTime: new Date()}); + else if (action === "left") playerDisconnect({playerName, connectTime: new Date()}); + else if (action === "lost") playerUnknown({playerName, connectTime: new Date(), action: "lost"}); + else playerUnknown({playerName, connectTime: new Date()}); + } + }, + }, ]; export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, pluginList?: string[]}) { -- 2.50.0 From 99e580fae56b41c5894f8d1ab0563db1f08c187f Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Thu, 22 Sep 2022 23:16:01 +0000 Subject: [PATCH 14/14] Update all to playerActions --- .github/workflows/test.yml | 2 +- src/bedrock.ts | 90 ++++++++++++++++---------------------- src/globalPlatfroms.ts | 6 ++- src/httpRequest.ts | 3 ++ src/java.ts | 17 ++++++- src/paper.ts | 19 ++++++-- src/pocketmine.ts | 24 +++++----- src/pwnuukit.ts | 32 ++++---------- 8 files changed, 98 insertions(+), 95 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f7fb99f..83648d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -94,5 +94,5 @@ jobs: # Run test - name: Test - timeout-minutes: 15 + timeout-minutes: 25 run: npm run test:partial -- tests/${{ matrix.platform }}.ts diff --git a/src/bedrock.ts b/src/bedrock.ts index 81b0829..a271057 100644 --- a/src/bedrock.ts +++ b/src/bedrock.ts @@ -16,7 +16,6 @@ export const saveFileFolder = /^(worlds|server\.properties|config|((permissions| export const portListen = /\[.*\]\s+(IPv[46])\s+supported,\s+port:\s+([0-9]+)/; export const started = /\[.*\]\s+Server\s+started\./; export const player = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/; -export const compressWorld = /\[.*\]\s+Running\s+AutoCompaction/; export async function installServer(version: string|boolean) { const bedrockData = await platformManeger.bedrock.find(version); @@ -56,31 +55,15 @@ const serverConfig: actionConfig[] = [ } }, { - name: "playerConnect", - callback(data, done) { - const match = data.match(player); - if (!match) return; - const [, action,, playerName, xuid] = match; - if (action === "connect") done({connectTime: new Date(), playerName: playerName, xuid}); - } - }, - { - name: "playerDisconnect", - callback(data, done) { - const match = data.match(player); - if (!match) return; - const [, action,, playerName, xuid] = match; - if (action === "disconnect") done({connectTime: new Date(), playerName: playerName, xuid}); - } - }, - { - name: "playerUnknown", - callback(data, done) { - const match = data.match(player); - if (!match) return; - const [, action,, playerName, xuid] = match; - if (!(action === "disconnect" || action === "connect")) done({connectTime: new Date(), playerName: playerName, xuid}); - } + name: "playerAction", + callback(data, playerConnect, playerDisconnect, playerUnknown) { + if (player.test(data)) { + const [, action,, playerName, xuid] = data.match(player); + if (action === "connect") playerConnect({connectTime: new Date(), playerName: playerName, xuid}); + else if (action === "disconnect") playerDisconnect({connectTime: new Date(), playerName: playerName, xuid}); + else playerUnknown({connectTime: new Date(), playerName: playerName, xuid}); + } + }, }, ]; @@ -185,35 +168,36 @@ export type bedrockConfig = { }; type rawConfig = { - 'server-name': string, + "server-name": string, gamemode: string, - 'force-gamemode': boolean, + "force-gamemode": boolean, difficulty: string, - 'allow-cheats': boolean, - 'max-players': number, - 'online-mode': true, - 'allow-list': boolean, - 'server-port': number, - 'server-portv6': number, - 'view-distance': number, - 'tick-distance': number, - 'player-idle-timeout': number, - 'max-threads': number, - 'level-name': string, - 'level-seed': any, - 'default-player-permission-level': string, - 'texturepack-required': boolean, - 'content-log-file-enabled': boolean, - 'compression-threshold': number, - 'server-authoritative-movement': string, - 'player-movement-score-threshold': number, - 'player-movement-action-direction-threshold': number, - 'player-movement-distance-threshold': number, - 'player-movement-duration-threshold-in-ms': number, - 'correct-player-movement': boolean, - 'server-authoritative-block-breaking': boolean, - 'chat-restriction': string, - 'disable-player-interaction': boolean + "allow-cheats": boolean, + "max-players": number, + "online-mode": true, + "allow-list": boolean, + "server-port": number, + "server-portv6": number, + "view-distance": number, + "tick-distance": number, + "player-idle-timeout": number, + "max-threads": number, + "level-name": string, + "level-seed": any, + "default-player-permission-level": string, + "texturepack-required": boolean, + "content-log-file-enabled": boolean, + "compression-threshold": number, + "server-authoritative-movement": string, + "player-movement-score-threshold": number, + "player-movement-action-direction-threshold": number, + "player-movement-distance-threshold": number, + "player-movement-duration-threshold-in-ms": number, + "correct-player-movement": boolean, + "server-authoritative-block-breaking": boolean, + "chat-restriction": string, + "disable-player-interaction": boolean, + "emit-server-telemetry"?: boolean } export async function getConfig(): Promise { diff --git a/src/globalPlatfroms.ts b/src/globalPlatfroms.ts index 5dd3807..48c35c7 100644 --- a/src/globalPlatfroms.ts +++ b/src/globalPlatfroms.ts @@ -6,13 +6,17 @@ import type {pluginManeger as globalPluginManeger} from "./plugin/main"; export type playerClass = {[player: string]: {action: "connect"|"disconnect"|"unknown"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"; date: Date}>}}; export type playerBase = {playerName: string, connectTime: Date, xuid?: string, action?: string}; + +/** + * @deprecated Please use playerAction now + */ export type actionsPlayer = { name: "playerConnect"|"playerDisconnect"|"playerUnknown", callback: (data: string, done: (player: playerBase) => void) => void } export type newPlayerAction = { name: "playerAction", - callback: (data: string, playerConect: (player: playerBase) => void, playerDisconnect: (player: playerBase) => void, playerUnknown: (player: playerBase) => void) => void + callback: (data: string, playerConnect: (player: playerBase) => void, playerDisconnect: (player: playerBase) => void, playerUnknown: (player: playerBase) => void) => void }; export type portListen = {port: number, host?: string, type: "TCP"|"UDP"|"TCP/UDP", protocol: "IPv4"|"IPv6"|"IPV4/IPv6"|"Unknown", plugin?: string}; diff --git a/src/httpRequest.ts b/src/httpRequest.ts index 3b04d33..da43d00 100644 --- a/src/httpRequest.ts +++ b/src/httpRequest.ts @@ -167,5 +167,8 @@ export type githubTree = { }[], }; export async function githubTree(username: string, repo: string, tree: string) { + const validate = /^[a-zA-Z0-9_\-]+$/; + if (!validate.test(username)) throw new Error("Invalid username"); + if (!validate.test(repo)) throw new Error("Invalid repository name"); return getJSON(`https://api.github.com/repos/${username}/${repo}/git/trees/${tree}?recursive=true`); } \ No newline at end of file diff --git a/src/java.ts b/src/java.ts index a50d30c..3a5adc2 100644 --- a/src/java.ts +++ b/src/java.ts @@ -8,14 +8,15 @@ import { actions, actionConfig } from "./globalPlatfroms"; import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "java"); const jarPath = path.join(serverPath, "server.jar"); -export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; -export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); return platformManeger.java.find(version).then(release => saveFile(release.url, {filePath: jarPath}).then(() => release)); } +export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; +export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; +export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/; const serverConfig: actionConfig[] = [ { name: "serverStop", @@ -43,6 +44,18 @@ const serverConfig: actionConfig[] = [ }); } }, + { + name: "playerAction", + callback(data, playerConect, playerDisconnect, playerUnknown) { + if (playerAction.test(data)) { + const [, playerName, action] = data.match(data)||[]; + if (action === "joined") playerConect({playerName, connectTime: new Date()}); + else if (action === "left") playerDisconnect({playerName, connectTime: new Date()}); + else if (action === "lost") playerUnknown({playerName, connectTime: new Date(), action: "lost"}); + else playerUnknown({playerName, connectTime: new Date()}); + } + }, + }, ]; export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean}) { diff --git a/src/paper.ts b/src/paper.ts index 5547029..d53e79e 100644 --- a/src/paper.ts +++ b/src/paper.ts @@ -9,15 +9,16 @@ import { actions, actionConfig } from "./globalPlatfroms"; import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "Papermc"); const jarPath = path.join(serverPath, "server.jar"); -export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; -export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; +export const pluginManger = () => (new plugin_maneger("paper", false)).loadPlugins(); export async function installServer(version: string|boolean) { if (!fsOld.existsSync(serverPath)) await fs.mkdir(serverPath, {recursive: true}); return platformManeger.paper.find(version).then(release => saveFile(release.url, {filePath: jarPath}).then(() => release)); } -export const pluginManger = () => (new plugin_maneger("paper", false)).loadPlugins(); +export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; +export const portListen = /\[.*\]:\s+Starting\s+Minecraft\s+server\s+on\s+(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[A-Za-z0-9]+|\*):([0-9]+))/; +export const playerAction = /\[.*\]:\s+([\S\w]+)\s+(joined|left|lost)/; const serverConfig: actionConfig[] = [ { name: "serverStop", @@ -51,6 +52,18 @@ const serverConfig: actionConfig[] = [ }); } }, + { + name: "playerAction", + callback(data, playerConect, playerDisconnect, playerUnknown) { + if (playerAction.test(data)) { + const [, playerName, action] = data.match(data)||[]; + if (action === "joined") playerConect({playerName, connectTime: new Date()}); + else if (action === "left") playerDisconnect({playerName, connectTime: new Date()}); + else if (action === "lost") playerUnknown({playerName, connectTime: new Date(), action: "lost"}); + else playerUnknown({playerName, connectTime: new Date()}); + } + }, + }, ]; export async function startServer(Config?: {maxMemory?: number, minMemory?: number, maxFreeMemory?: boolean, pluginList?: string[]}) { diff --git a/src/pocketmine.ts b/src/pocketmine.ts index a9c6745..f9dd7e7 100644 --- a/src/pocketmine.ts +++ b/src/pocketmine.ts @@ -103,6 +103,17 @@ export const started = /\[.*\].*\s+Done\s+\(.*\)\!.*/; export const player = /[.*]:\s+(.*)\s+(.*)\s+the\s+game/gi; const serverConfig: actionConfig[] = [ + { + name: "serverStop", + run: (child) => child.runCommand("stop") + }, + { + name: "serverStarted", + callback(data, done) { + // [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help" + if (started.test(data)) done(new Date()); + } + }, { name: "portListening", callback(data, done) { @@ -118,22 +129,11 @@ const serverConfig: actionConfig[] = [ } }, { - name: "serverStarted", - callback(data, done) { - // [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help" - if (started.test(data)) done(new Date()); - } - }, - { - name: "playerConnect", + name: "playerAction", callback(data, done) { data; }, }, - { - name: "serverStop", - run: (child) => child.runCommand("stop") - } ]; export async function startServer() { diff --git a/src/pwnuukit.ts b/src/pwnuukit.ts index 37e2f57..e4bba09 100644 --- a/src/pwnuukit.ts +++ b/src/pwnuukit.ts @@ -8,6 +8,8 @@ import { platformManeger } from "@the-bds-maneger/server_versions"; import { saveFile } from "./httpRequest"; export const serverPath = path.join(serverRoot, "power_nukkit"); const jarPath = path.join(serverPath, "pwnukkit.jar"); +export const playerAction = /^.*\[.*\]\s([\S\w]+|"[\S\w]+")\s+(left|joined)\s+the\s+game$/; +export const portListen = /Opening\s+server\s+on\s+(([A-Za-z0-9:\.]+):([0-9]+))/; const serverConfig: actionConfig[] = [ { @@ -24,7 +26,6 @@ const serverConfig: actionConfig[] = [ { name: "portListening", callback(data, done) { - const portListen = /Opening\s+server\s+on\s+(([A-Za-z0-9:\.]+):([0-9]+))/; if (portListen.test(data)) { const [,, host, port] = data.match(portListen); done({ @@ -37,31 +38,16 @@ const serverConfig: actionConfig[] = [ }, }, { - name: "playerConnect", - callback(data, done) { - const playerAction = /^.*\[.*\]\s(\S+)\s+(left|joined)\s+the\s+game$/; + name: "playerAction", + callback(data, playerConect, playerDisconnect, playerUnknown) { if (playerAction.test(data)) { - const [,playerName, action] = data.match(playerAction); - if (action === "joined") done({ - connectTime: new Date(), - playerName, - }); + const [, playerName, action] = data.match(playerAction)||[]; + if (action === "joined") playerConect({connectTime: new Date(), playerName}); + else if (action === "left") playerDisconnect({connectTime: new Date(), playerName}); + else playerUnknown({connectTime: new Date(), playerName}); } }, - }, - { - name: "playerDisconnect", - callback(data, done) { - const playerAction = /^.*\[.*\]\s(\S+)\s+(left|joined)\s+the\s+game$/; - if (playerAction.test(data)) { - const [,playerName, action] = data.match(playerAction); - if (action === "left") done({ - connectTime: new Date(), - playerName, - }); - } - }, - }, + } ]; export async function installServer(version: string|boolean) { -- 2.50.0