import ftp from "basic-ftp"; import { ERR } from "../util/logging.js"; import { getServerAssets } from "./k8s-server-control.js"; import ExpressClientError from "../util/ExpressClientError.js"; import { Readable, Writable, Transform } from "node:stream"; const namespace = process.env.MCL_SERVER_NAMESPACE; const pathSecurityCheck = (path) => { if (!path.startsWith(".")) throw new ExpressClientError({ m: "Only relative directories can be created", c: 409, }); }; const handleError = (e) => { ERR("SERVER FILES", "Error occurred while preforming FTP operation!", e); throw new ExpressClientError({ c: 500, m: "Error occurred while performing FTP operation!", }); }; export async function getFtpClient(serverService) { const { name } = serverService.metadata; const client = new ftp.Client(); await client.access({ host: `${name}.${namespace}.svc.cluster.local`, user: "minecluster", password: "minecluster", }); return client; } export async function useServerFtp(serverSpec, fn) { const { id } = serverSpec; const server = await getServerAssets(id); if (!server) throw new ExpressClientError({ c: 404, m: "No resources for that server were found!", }); if (!server.service) throw new ExpressClientError({ c: 409, m: "Service doesn't exist, please contact your hosting provider!", }); const client = await getFtpClient(server.service); const result = await fn(client); client.close(); return result; } export async function listServerFiles(serverSpec) { const { path } = serverSpec; const files = useServerFtp(serverSpec, async (c) => await c.list(path)).catch( handleError, ); return files; } export async function createServerFolder(serverSpec) { const { path } = serverSpec; pathSecurityCheck(path); await useServerFtp(serverSpec, async (c) => c.ensureDir(path)).catch( handleError, ); } export async function removeServerItem(serverSpec) { const { path, isDir } = serverSpec; pathSecurityCheck(path); await useServerFtp(serverSpec, async (c) => { if (isDir) await c.removeDir(path); else await c.remove(path); }).catch(handleError); } export async function uploadServerItem(serverSpec, file) { const fileStream = Readable.from(file.buffer); const { path } = serverSpec; pathSecurityCheck(path); await useServerFtp(serverSpec, async (c) => { await c.uploadFrom(fileStream, path); }).catch(handleError); } export async function getServerItem(serverSpec, writableStream) { const { path } = serverSpec; const ds = new Transform({ transform: (c, e, cb) => cb(null, c) }); pathSecurityCheck(path); const ftpTransfer = useServerFtp(serverSpec, async (c) => { await c.downloadTo(ds, path); }).catch(handleError); return { ds, ftpTransfer }; }