import { minioClient } from '@/app.ts'; import { bucketName } from '@/modules/minio.ts'; import { CopyDestinationOptions, CopySourceOptions } from 'minio'; type MinioListOpt = { prefix: string; recursive?: boolean; }; export type MinioFile = { name: string; size: number; lastModified: Date; etag: string; }; export type MinioDirectory = { prefix: string; size: number; }; export type MinioList = (MinioFile | MinioDirectory)[]; export const getMinioList = async (opts: MinioListOpt): Promise => { const prefix = opts.prefix; const recursive = opts.recursive ?? false; return await new Promise((resolve, reject) => { let res: any[] = []; let hasError = false; minioClient .listObjectsV2(bucketName, prefix, recursive) .on('data', (data) => { res.push(data); }) .on('error', (err) => { console.error('minio error', opts.prefix, err); hasError = true; }) .on('end', () => { if (hasError) { reject(); return; } else { resolve(res); } }); }); }; export const getFileStat = async (prefix: string, isFile?: boolean): Promise => { try { const obj = await minioClient.statObject(bucketName, prefix); if (isFile && obj.size === 0) { return null; } return obj; } catch (e) { if (e.code === 'NotFound') { return null; } console.error('get File Stat Error not handle', e); return null; } }; export const deleteFile = async (prefix: string): Promise<{ code: number; message: string }> => { try { const fileStat = await getFileStat(prefix); if (!fileStat) { console.warn(`File not found: ${prefix}`); return { code: 404, message: 'file not found', }; } await minioClient.removeObject(bucketName, prefix, { versionId: 'null', forceDelete: true, // 强制删除 }); return { code: 200, message: 'delete success', }; } catch (e) { console.error('delete File Error not handle', e); return { code: 500, message: 'delete failed', }; } }; // 批量删除文件 export const deleteFiles = async (prefixs: string[]): Promise => { try { await minioClient.removeObjects(bucketName, prefixs); return true; } catch (e) { console.error('delete Files Error not handle', e); return false; } }; type GetMinioListAndSetToAppListOpts = { username: string; appKey: string; version: string; }; // 批量列出文件,并设置到appList的files中 export const getMinioListAndSetToAppList = async (opts: GetMinioListAndSetToAppListOpts) => { const { username, appKey, version } = opts; const minioList = await getMinioList({ prefix: `${username}/${appKey}/${version}`, recursive: true }); const files = minioList; return files as MinioFile[]; }; /** * 更新文件的元数据 * @param prefix 文件前缀 * @param newMetadata 新的元数据 * @returns */ export const updateFileStat = async ( prefix: string, newMetadata: Record, ): Promise<{ code: number; data: any; message?: string; }> => { try { const source = new CopySourceOptions({ Bucket: bucketName, Object: prefix }); const destination = new CopyDestinationOptions({ Bucket: bucketName, Object: prefix, UserMetadata: newMetadata, MetadataDirective: 'REPLACE', }); const copyResult = await minioClient.copyObject(source, destination); console.log('copyResult', copyResult); console.log(`Metadata for ${prefix} updated successfully.`); return { code: 200, data: copyResult, message: 'update metadata success', }; } catch (e) { console.error('Error updating file stat', e); return { code: 500, data: null, message: `update metadata failed. ${e.message}`, }; } };