import { Client } from "minio"; if (!process.env.MINIO_BUCKET) { throw Error("Require MinIO bucket."); } const MINIO_BUCKET = process.env.MINIO_BUCKET; const minio = new Client({ endPoint: process.env.MINIO_HOST ?? "localhost", port: process.env.MINIO_PORT ? +process.env.MINIO_PORT : undefined, useSSL: /true/.test(process.env.MINIO_SSL || "false"), accessKey: process.env.MINIO_ACCESS_KEY ?? "", secretKey: process.env.MINIO_SECRET_KEY ?? "", }); export default minio; function exception(e: any): never { console.error(e); throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์"); } export async function listFile(path: string) { return await new Promise((resolve, reject) => { const item: string[] = []; const stream = minio.listObjectsV2(MINIO_BUCKET, path); stream.on("data", (v) => v && v.name && item.push(v.name.split("/").at(-1) || "")); stream.on("end", () => resolve(item)); stream.on("error", (e) => { console.error(e); reject(new Error("MinIO error.")); }); }); } export async function getPresigned(method: string, path: string, exp = 60 * 60) { return await minio.presignedUrl(method, MINIO_BUCKET, path, exp); } export async function getFile(path: string, exp = 60 * 60) { return await minio.presignedGetObject(MINIO_BUCKET, path, exp); } export async function setFile(path: string, exp = 6 * 60 * 60) { return await minio.presignedPutObject(MINIO_BUCKET, path, exp); } export async function s3DeleteFile(path: string) { await minio.removeObject(MINIO_BUCKET, path, { forceDelete: true }); } export async function s3DeleteFolder(path: string) { new Promise((resolve, reject) => { const item: string[] = []; const stream = minio.listObjectsV2(MINIO_BUCKET, path, true); stream.on("data", (v) => v && v.name && item.push(v.name)); stream.on("end", () => resolve(item)); stream.on("error", (e) => { console.error(e); reject(new Error("MinIO error.")); }); }).then((list) => { list.map(async (v) => { await minio.removeObject(MINIO_BUCKET, v, { forceDelete: true }); }); }); } export async function s3UploadFile(replace: boolean, ...pathname: string[]) { if (!pathname.length) return; if (!replace) { const list = await s3ListFile(...pathname.slice(0, -1)).catch(exception); const fileName = pathname.at(-1) as string; const dot = fileName.lastIndexOf("."); const name = dot !== -1 && !fileName.startsWith(".") ? fileName.slice(0, dot) : fileName; const ext = dot !== -1 && !fileName.startsWith(".") ? fileName.slice(dot) : ""; let copy = 0; let copyFileName = fileName; while (list.findIndex((v) => v.fileName === copyFileName) !== -1) { copyFileName = `${name} (${++copy})${ext}`.trim(); } if (copy > 0) { await s3UpdateFile(pathname, pathname.slice(0, -1).concat(copyFileName)); } } const data = { path: pathname.slice(0, -1).join("/"), pathname: pathname.join("/"), fileName: pathname.at(-1), title: pathname.at(-1), uploadUrl: await setFile(fileLocation(...pathname)).catch(exception), }; return data; } export async function s3UpdateFile(from: string[], to: string[], upload?: boolean) { await minio .copyObject(MINIO_BUCKET, to.join("/"), [MINIO_BUCKET].concat(from).join("/")) .catch(exception); await minio.removeObject(MINIO_BUCKET, from.join("/")).catch(exception); const data = { path: to.slice(0, -1).join("/"), pathname: to.join("/"), fileName: to.at(-1), title: to.at(-1), uploadUrl: upload ? await setFile(fileLocation(...to)).catch(exception) : undefined, }; return data; } export async function s3ListFile(...path: string[]) { const list = await listFile(fileLocation(...path) + "/").catch(exception); return list.map((name) => ({ path: path.join("/"), pathname: path.concat(name).join("/"), fileName: name, title: name, })); } export async function s3DownloadFile(...pathname: string[]) { const downloadUrl = await getFile(fileLocation(...pathname)).catch(exception); return { path: pathname.slice(0, -1).join("/"), pathname: pathname.join("/"), fileName: pathname.at(-1), title: pathname.at(-1), downloadUrl, }; } export const fileLocation = (...path: string[]) => path.join("/");