add oss for download

This commit is contained in:
2025-03-23 16:47:25 +08:00
parent 5563ded0a1
commit 68332c9c8d
11 changed files with 410 additions and 26 deletions

74
src/util/download.ts Normal file
View File

@@ -0,0 +1,74 @@
import { ServerResponse } from 'http';
import { BucketItemStat } from 'minio';
import fs from 'fs';
import path from 'path';
const viewableExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'mp4', 'webm', 'mp3', 'wav', 'ogg', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
import { OssBase } from '../index.ts';
/**
* 过滤 metaData 中的 key, 去除 password, accesskey, secretkey
* 并返回过滤后的 metaData
* @param metaData
* @returns
*/
export const filterMetaDataKeys = (metaData: Record<string, string>, clearKeys: string[] = []) => {
const keys = Object.keys(metaData);
// remove X-Amz- meta data
const removeKeys = ['password', 'accesskey', 'secretkey', ...clearKeys];
const filteredKeys = keys.filter((key) => !removeKeys.includes(key));
return filteredKeys.reduce((acc, key) => {
acc[key] = metaData[key];
return acc;
}, {} as Record<string, string>);
};
type SendObjectOptions = {
res: ServerResponse;
client: OssBase;
objectName: string;
isDownload?: boolean;
};
export const NotFoundFile = (res: ServerResponse, msg?: string, code = 404) => {
res.writeHead(code, { 'Content-Type': 'text/plain' });
res.end(msg || 'Not Found File');
return;
};
export const sendObject = async ({ res, objectName, client, isDownload = false }: SendObjectOptions) => {
let stat: BucketItemStat;
try {
stat = await client.statObject(objectName);
} catch (e) {
} finally {
if (!stat || stat.size === 0) {
return NotFoundFile(res);
}
const contentLength = stat.size;
const etag = stat.etag;
const lastModified = stat.lastModified.toISOString();
const filename = objectName.split('/').pop() || 'no-file-name-download'; // Extract filename from objectName
const fileExtension = filename.split('.').pop()?.toLowerCase() || '';
const filteredMetaData = filterMetaDataKeys(stat.metaData, ['size', 'etag', 'last-modified']);
const contentDisposition = viewableExtensions.includes(fileExtension) && !isDownload ? 'inline' : `attachment; filename="${filename}"`;
res.writeHead(200, {
'Content-Length': contentLength,
etag,
'last-modified': lastModified,
'Content-Disposition': contentDisposition,
'file-name': filename,
...filteredMetaData,
});
const objectStream = await client.getObject(objectName);
objectStream.pipe(res, { end: true });
}
};
export const downloadObject = async ({ objectName, client, filePath }: Pick<SendObjectOptions, 'objectName' | 'client'> & { filePath: string }) => {
const objectStream = await client.getObject(objectName);
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
objectStream.pipe(fs.createWriteStream(filePath));
return objectStream;
};

24
src/util/hash.ts Normal file
View File

@@ -0,0 +1,24 @@
import crypto from 'crypto';
// 582af9ef5cdc53d6628f45cb842f874a
// const hashStr = '{"a":"a"}';
// const hash = crypto.createHash('md5').update(hashStr).digest('hex');
// console.log(hash);
/**
* 计算字符串的md5值
* @param str
* @returns
*/
export const hash = (str: string | Buffer | Object) => {
let hashStr: string | Buffer;
if (typeof str === 'object') {
hashStr = JSON.stringify(str, null, 2);
} else {
hashStr = str;
}
return crypto.createHash('md5').update(hashStr).digest('hex');
};
export const hashSringify = (str: Object) => {
return JSON.stringify(str, null, 2);
};

1
src/util/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './hash.ts';