UNPKG

@levimc-lse/scaffold

Version:

A utility for assisting in the development of Legacy Script Engine plugins.

301 lines (300 loc) 14.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LeviLaminaServer = void 0; const File = __importStar(require("fs")); const Path = __importStar(require("path")); const node_events_1 = require("node:events"); const node_child_process_1 = require("node:child_process"); const ssh2_1 = require("ssh2"); const SocketServer_1 = require("../debugger/SocketServer"); const LeviLaminaPluginNotFoundError_1 = require("./exceptions/LeviLaminaPluginNotFoundError"); const RemoteSSHConnectionError_1 = require("./exceptions/RemoteSSHConnectionError"); const RemoteSSHFileUploadError_1 = require("./exceptions/RemoteSSHFileUploadError"); const RemotePluginInstallationError_1 = require("./exceptions/RemotePluginInstallationError"); class LeviLaminaServer { static deleteDirectory(basePath) { if (File.existsSync(basePath)) { File.readdirSync(basePath).forEach((file) => { const currentPath = Path.join(basePath, file); if (File.lstatSync(currentPath).isDirectory()) { LeviLaminaServer.deleteDirectory(currentPath); } else { File.unlinkSync(currentPath); } }); File.rmdirSync(basePath); } } constructor(rootPath, remoteHost = "localhost", remotePort = 22, remoteUsername = "administrator", remotePassword = "password") { this.remoteHost = remoteHost; this.remotePort = remotePort; this.remoteUsername = remoteUsername; this.remotePassword = remotePassword; this.rootPath = rootPath; this.pluginDirectory = Path.join(rootPath, "plugins"); } start(aliasName, logger) { return __awaiter(this, void 0, void 0, function* () { const serverExecutedPath = Path.join(this.getRootPath(), "bedrock_server_mod.exe"); const serverOutputReceiver = new node_events_1.EventEmitter(); let serverCommandSender; if (this.remoteHost !== "localhost") { const remoteSSH = new ssh2_1.Client(); let remoteSSHChannel; remoteSSH .on("ready", () => { remoteSSH.exec(serverExecutedPath, (error, channel) => { if (error) throw error; remoteSSHChannel = channel; channel .on("data", (chunk) => { logger.info(chunk.toString()); serverOutputReceiver.emit("output", chunk.toString()); }) .on("close", (code, signal) => { remoteSSH.end(); process.exit(0); }); process.stdin.pipe(channel); }); }) .connect({ host: this.remoteHost, port: this.remotePort, username: this.remoteUsername, password: this.remotePassword }); serverCommandSender = (command) => { if (remoteSSHChannel && !remoteSSHChannel.destroyed) { remoteSSHChannel.write(command); } }; } else { const serverInstance = (0, node_child_process_1.spawn)(serverExecutedPath); serverInstance.on("close", (code, signal) => { process.exit(0); }); serverInstance.stdout.on("data", (chunk) => { logger.info(chunk.toString()); serverOutputReceiver.emit("output", chunk.toString()); }); process.stdin.on("data", (chunk) => { serverInstance.stdin.write(chunk); }); serverCommandSender = (command) => { serverInstance.stdin.write(command); }; } const socketServer = new SocketServer_1.SocketServer(aliasName); yield socketServer.start(); socketServer.on("message", (socket, message) => { if (message === "0") { const remoteConfiguration = { path: this.getRootPath(), host: this.remoteHost, port: this.remotePort, username: this.remoteUsername, password: this.remotePassword }; socketServer.sendMessage(JSON.stringify(remoteConfiguration, null, 4)); } else if (message.startsWith("1")) { const pluginName = message.split("_")[1]; serverOutputReceiver.on("output", (output) => { if (output.includes(`Reload mod ${pluginName} successfully`)) { socket.destroy(); } }); serverCommandSender(`ll reload ${pluginName}\n`); } }); }); } removePlugin(pluginName) { return __awaiter(this, void 0, void 0, function* () { const pluginPath = Path.join(this.pluginDirectory, pluginName.replace("/", "-").replace("@", "")); if (this.remoteHost === "localhost") { if (File.existsSync(pluginPath)) { LeviLaminaServer.deleteDirectory(pluginPath); } else { throw new LeviLaminaPluginNotFoundError_1.LeviLaminaPluginNotFoundError(pluginName); } } else { const remoteSSH = new ssh2_1.Client(); try { yield new Promise((resolve, reject) => { remoteSSH .on('ready', () => resolve()) .on('error', (error) => reject(new RemoteSSHConnectionError_1.RemoteSSHConnectionError(this))) .connect({ host: this.remoteHost, port: this.remotePort, username: this.remoteUsername, password: this.remotePassword }); }); } catch (error) { throw new RemoteSSHConnectionError_1.RemoteSSHConnectionError(this); } try { const result = yield new Promise((resolve, reject) => { remoteSSH.exec(`if exist "${pluginPath}" (echo true) else (echo false)`, (error, stream) => { if (error) { reject(error); return; } let stdout = ''; stream .on('data', (chunk) => { stdout += chunk.toString(); }) .on('end', () => { resolve({ stdout }); }) .on('error', reject); }); }); if (result.stdout.trim() === "true") { yield new Promise((resolve, reject) => { remoteSSH.exec(`rmdir /s /q "${pluginPath}"`, (error, stream) => { if (error) { reject(error); return; } stream .on('end', () => resolve()) .on('error', reject); }); }); } else { remoteSSH.end(); throw new LeviLaminaPluginNotFoundError_1.LeviLaminaPluginNotFoundError(pluginName); } } finally { remoteSSH.end(); } } }); } importPlugin(pluginPackage) { return __awaiter(this, void 0, void 0, function* () { if (this.remoteHost !== "localhost") { const remoteSSH = new ssh2_1.Client(); try { yield new Promise((resolve, reject) => { remoteSSH .on('ready', () => resolve()) .on('error', (error) => reject(new RemoteSSHConnectionError_1.RemoteSSHConnectionError(this))) .connect({ host: this.remoteHost, port: this.remotePort, username: this.remoteUsername, password: this.remotePassword }); }); } catch (error) { throw new RemoteSSHConnectionError_1.RemoteSSHConnectionError(this); } const remotePluginPackagePath = Path.join(this.pluginDirectory, `${pluginPackage.getName()}.zip`); try { yield new Promise((resolve, reject) => { remoteSSH.sftp((error, sftp) => { if (error) { reject(error); return; } sftp.fastPut(pluginPackage.getPath(), remotePluginPackagePath, (error) => { if (error) { reject(new RemoteSSHFileUploadError_1.RemoteSSHFileUploadError(pluginPackage.getPath(), this)); } else { sftp.end(); resolve(); } }); }); }); yield new Promise((resolve, reject) => { remoteSSH.exec(`powershell -command "Expand-Archive -Path ${remotePluginPackagePath} -DestinationPath ${Path.join(this.pluginDirectory, pluginPackage.getName())}" && del ${remotePluginPackagePath}`, (error, stream) => { if (error) { reject(new RemotePluginInstallationError_1.RemotePluginInstallationError(this)); return; } stream .on('end', () => resolve()) .on('close', () => resolve()) .on('error', (error) => reject(new RemotePluginInstallationError_1.RemotePluginInstallationError(this))); // Workaround for SSH channel not receiving execution completion signals. setTimeout(() => resolve(), 3000); }); }); } finally { remoteSSH.end(); } } else { yield pluginPackage.expand(this.pluginDirectory); } return `The plugin has been imported to LeviLamina ${this.getRootPath()}${this.remoteHost === "localhost" ? "" : " in " + this.getRemoteAddress(false)}.`; }); } getRootPath() { return this.rootPath; } getRemoteAddress(isIncludePort) { return `${this.remoteUsername}@${this.remoteHost}${isIncludePort ? ":" + this.remotePort : ""}`; } } exports.LeviLaminaServer = LeviLaminaServer;