- Removed MinIO client and related imports from various modules. - Introduced S3 client and OSS integration for object storage. - Updated all references to MinIO methods with corresponding S3 methods. - Added new flowme table schema to the database. - Adjusted upload and download routes to utilize S3 for file operations. - Removed obsolete MinIO-related files and routes. - Ensured compatibility with existing application logic while transitioning to S3.
184 lines
5.3 KiB
TypeScript
184 lines
5.3 KiB
TypeScript
import dayjs from 'dayjs';
|
||
import { oss } from '@/app.ts';
|
||
import { StatObjectResult } from '@kevisual/oss';
|
||
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 <IS_FILE extends boolean>(opts: MinioListOpt): Promise<IS_FILE extends true ? MinioFile[] : MinioDirectory[]> => {
|
||
const prefix = opts.prefix;
|
||
const recursive = opts.recursive ?? false;
|
||
const res = await oss.listObjects(prefix, { recursive });
|
||
return res as IS_FILE extends true ? MinioFile[] : MinioDirectory[];
|
||
};
|
||
export const getFileStat = async (prefix: string, isFile?: boolean): Promise<StatObjectResult | null> => {
|
||
try {
|
||
const obj = await oss.statObject(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 oss.deleteObject(prefix);
|
||
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<any> => {
|
||
try {
|
||
for (const prefix of prefixs) {
|
||
await oss.deleteObject(prefix);
|
||
}
|
||
return true;
|
||
} catch (e) {
|
||
console.error('delete Files Error not handle', e);
|
||
return false;
|
||
}
|
||
};
|
||
export const deleteFileByPrefix = async (prefix: string): Promise<any> => {
|
||
try {
|
||
const allFiles = await getMinioList<true>({ prefix, recursive: true });
|
||
const files = allFiles.filter((item) => item.name.startsWith(prefix));
|
||
await deleteFiles(files.map((item) => item.name));
|
||
return true;
|
||
} catch (e) {
|
||
console.error('delete File 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<string, string>,
|
||
): Promise<{
|
||
code: number;
|
||
data: any;
|
||
message?: string;
|
||
}> => {
|
||
try {
|
||
const copyResult = await oss.replaceObject(prefix, {
|
||
...newMetadata
|
||
});
|
||
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}`,
|
||
};
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 将用户A的文件移动到用户B
|
||
* @param usernameA
|
||
* @param usernameB
|
||
* @param clearOldUser 是否清除用户A的文件
|
||
*/
|
||
export const mvUserAToUserB = async (usernameA: string, usernameB: string, clearOldUser = false) => {
|
||
const oldPrefix = `${usernameA}/`;
|
||
const newPrefix = `${usernameB}/`;
|
||
const listSource = await getMinioList<true>({ prefix: oldPrefix, recursive: true });
|
||
for (const item of listSource) {
|
||
const newName = item.name.slice(oldPrefix.length);
|
||
await oss.copyObject(item.name, `${newPrefix}${newName}`);
|
||
}
|
||
if (clearOldUser) {
|
||
const files = await getMinioList<true>({ prefix: oldPrefix, recursive: true });
|
||
for (const file of files) {
|
||
await oss.deleteObject(file.name);
|
||
}
|
||
}
|
||
};
|
||
export const backupUserA = async (usernameA: string, id: string, backName?: string) => {
|
||
const today = backName || dayjs().format('YYYY-MM-DD-HH-mm');
|
||
const backupAllPrefix = `private/backup/${id}/`;
|
||
const backupPrefix = `private/backup/${id}/${today}`;
|
||
const backupList = await getMinioList<false>({ prefix: backupAllPrefix });
|
||
const backupListSort = backupList.sort((a, b) => -a.prefix.localeCompare(b.prefix));
|
||
if (backupListSort.length > 2) {
|
||
const deleteBackup = backupListSort.slice(2);
|
||
for (const item of deleteBackup) {
|
||
const files = await getMinioList<true>({ prefix: item.prefix, recursive: true });
|
||
for (const file of files) {
|
||
await oss.deleteObject(file.name);
|
||
}
|
||
}
|
||
}
|
||
await mvUserAToUserB(usernameA, backupPrefix, false);
|
||
};
|
||
/**
|
||
* 删除用户
|
||
* @param username
|
||
*/
|
||
export const deleteUser = async (username: string) => {
|
||
const list = await getMinioList<true>({ prefix: `${username}/`, recursive: true });
|
||
for (const item of list) {
|
||
await oss.deleteObject(item.name);
|
||
}
|
||
};
|