perf
This commit is contained in:
parent
1a2201cdc6
commit
bcb8ea1f30
18
package.json
18
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/oss",
|
"name": "@kevisual/oss",
|
||||||
"version": "0.0.1",
|
"version": "0.0.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -16,13 +16,23 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.5.0",
|
||||||
"minio": "^8.0.5",
|
"minio": "^8.0.5",
|
||||||
"tsup": "^8.4.0"
|
"tsup": "^8.4.0"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./*": "./dist/*.js",
|
".": {
|
||||||
"./services": "./dist/services/index.js"
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
},
|
||||||
|
"./config": {
|
||||||
|
"import": "./dist/services/config.js",
|
||||||
|
"types": "./dist/services/config.d.ts"
|
||||||
|
},
|
||||||
|
"./services": {
|
||||||
|
"import": "./dist/services/index.js",
|
||||||
|
"types": "./dist/services/index.d.ts"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
@ -3,7 +3,7 @@ import { Client, CopyDestinationOptions, CopySourceOptions } from 'minio';
|
|||||||
type CopyObjectOpts = {
|
type CopyObjectOpts = {
|
||||||
bucketName: string;
|
bucketName: string;
|
||||||
newMetadata: Record<string, string>;
|
newMetadata: Record<string, string>;
|
||||||
prefix: string;
|
objectName: string;
|
||||||
client: Client;
|
client: Client;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -11,12 +11,14 @@ type CopyObjectOpts = {
|
|||||||
* @param param0
|
* @param param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const copyObject = async ({ bucketName, newMetadata, prefix, client }: CopyObjectOpts) => {
|
export const copyObject = async ({ bucketName, newMetadata, objectName, client }: CopyObjectOpts) => {
|
||||||
const source = new CopySourceOptions({ Bucket: bucketName, Object: prefix });
|
const source = new CopySourceOptions({ Bucket: bucketName, Object: objectName });
|
||||||
|
const stat = await client.statObject(bucketName, objectName);
|
||||||
|
const sourceMetadata = stat.metaData;
|
||||||
const destination = new CopyDestinationOptions({
|
const destination = new CopyDestinationOptions({
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
Object: prefix,
|
Object: objectName,
|
||||||
UserMetadata: newMetadata,
|
UserMetadata: { ...sourceMetadata, ...newMetadata },
|
||||||
MetadataDirective: 'REPLACE',
|
MetadataDirective: 'REPLACE',
|
||||||
});
|
});
|
||||||
const copyResult = await client.copyObject(source, destination);
|
const copyResult = await client.copyObject(source, destination);
|
||||||
|
55
src/index.ts
55
src/index.ts
@ -1,12 +1,13 @@
|
|||||||
import { Client, ItemBucketMetadata } from 'minio';
|
import { Client, ItemBucketMetadata } from 'minio';
|
||||||
import { ListFileObject, ListObjectResult, OssBaseOperation } from './core/type.ts';
|
import { ListFileObject, ListObjectResult, OssBaseOperation } from './core/type.ts';
|
||||||
import { hash } from './util/hash.ts';
|
import { hash } from './util/hash.ts';
|
||||||
|
import { copyObject } from './core/copy-object.ts';
|
||||||
|
|
||||||
export type OssBaseOptions<T = { [key: string]: any }> = {
|
export type OssBaseOptions<T = { [key: string]: any }> = {
|
||||||
/**
|
/**
|
||||||
* 已经初始化好的minio client
|
* 已经初始化好的minio client
|
||||||
*/
|
*/
|
||||||
client?: Client;
|
client: Client;
|
||||||
/**
|
/**
|
||||||
* 桶名
|
* 桶名
|
||||||
*/
|
*/
|
||||||
@ -31,7 +32,7 @@ export class OssBase implements OssBaseOperation {
|
|||||||
}
|
}
|
||||||
this.bucketName = opts.bucketName;
|
this.bucketName = opts.bucketName;
|
||||||
this.client = opts.client;
|
this.client = opts.client;
|
||||||
this.prefix = opts.prefix;
|
this.prefix = opts?.prefix ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrefix(prefix: string) {
|
setPrefix(prefix: string) {
|
||||||
@ -64,15 +65,36 @@ export class OssBase implements OssBaseOperation {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
async putObject(objectName: string, data: Buffer | string | Object, metaData?: ItemBucketMetadata) {
|
* 上传文件,
|
||||||
|
* @param objectName
|
||||||
|
* @param data
|
||||||
|
* @param metaData
|
||||||
|
* @param options 如果文件本身存在,则复制原有的meta的内容
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async putObject(objectName: string, data: Buffer | string | Object, metaData: ItemBucketMetadata = {}, options?: { check?: boolean }) {
|
||||||
let putData: Buffer | string;
|
let putData: Buffer | string;
|
||||||
|
let size: number;
|
||||||
if (typeof data === 'object') {
|
if (typeof data === 'object') {
|
||||||
putData = JSON.stringify(data);
|
putData = JSON.stringify(data);
|
||||||
|
size = putData.length;
|
||||||
|
} else if (typeof data === 'string') {
|
||||||
|
putData = data;
|
||||||
|
size = putData.length;
|
||||||
} else {
|
} else {
|
||||||
putData = data;
|
putData = data;
|
||||||
}
|
}
|
||||||
const size = putData.length;
|
if (options?.check) {
|
||||||
|
const obj = await this.statObject(objectName, true);
|
||||||
|
if (obj) {
|
||||||
|
metaData = {
|
||||||
|
...obj.metaData,
|
||||||
|
...metaData,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bucketName = this.bucketName;
|
const bucketName = this.bucketName;
|
||||||
const obj = await this.client.putObject(bucketName, `${this.prefix}${objectName}`, putData, size, metaData);
|
const obj = await this.client.putObject(bucketName, `${this.prefix}${objectName}`, putData, size, metaData);
|
||||||
return obj;
|
return obj;
|
||||||
@ -117,10 +139,13 @@ export class OssBase implements OssBaseOperation {
|
|||||||
return obj as any;
|
return obj as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
async statObject(objectName: string) {
|
async statObject(objectName: string, checkFile = true) {
|
||||||
const bucketName = this.bucketName;
|
const bucketName = this.bucketName;
|
||||||
try {
|
try {
|
||||||
const obj = await this.client.statObject(bucketName, `${this.prefix}${objectName}`);
|
const obj = await this.client.statObject(bucketName, `${this.prefix}${objectName}`);
|
||||||
|
if (obj && checkFile && obj.size === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return obj;
|
return obj;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 'NotFound') {
|
if (e.code === 'NotFound') {
|
||||||
@ -129,13 +154,29 @@ export class OssBase implements OssBaseOperation {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 检查文件hash是否一致
|
||||||
|
* @param objectName
|
||||||
|
* @param hash
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async checkObjectHash(objectName: string, hash: string) {
|
||||||
|
const obj = await this.statObject(`${this.prefix}${objectName}`, true);
|
||||||
|
if (!obj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return obj.etag === hash;
|
||||||
|
}
|
||||||
|
|
||||||
async copyObject(sourceObject: any, targetObject: any) {
|
async copyObject(sourceObject: any, targetObject: any) {
|
||||||
const bucketName = this.bucketName;
|
const bucketName = this.bucketName;
|
||||||
const obj = await this.client.copyObject(bucketName, sourceObject, targetObject);
|
const obj = await this.client.copyObject(bucketName, sourceObject, targetObject);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
async replaceObject(objectName: string, meta: { [key: string]: string }) {
|
||||||
|
const { bucketName, client } = this;
|
||||||
|
return copyObject({ bucketName, client, objectName: `${this.prefix}${objectName}`, newMetadata: meta });
|
||||||
|
}
|
||||||
static create<T extends OssBase, U>(this: new (opts: OssBaseOptions<U>) => T, opts: OssBaseOptions<U>): T {
|
static create<T extends OssBase, U>(this: new (opts: OssBaseOptions<U>) => T, opts: OssBaseOptions<U>): T {
|
||||||
return new this(opts);
|
return new this(opts);
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,9 @@
|
|||||||
export { OssBase, OssBaseOptions } from '../index.ts';
|
export { OssBase } from '../index.ts';
|
||||||
|
export type { OssBaseOptions } from '../index.ts';
|
||||||
export { ConfigOssService } from './config.ts';
|
export { ConfigOssService } from './config.ts';
|
||||||
|
|
||||||
|
export * from '../util/download.ts';
|
||||||
|
|
||||||
|
export * from '../util/index.ts';
|
||||||
|
|
||||||
|
export * from '../core/type.ts';
|
||||||
|
@ -4,9 +4,16 @@ import { Client } from 'minio';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { downloadObject } from '../util/download.ts';
|
import { downloadObject } from '../util/download.ts';
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
dotenv.config({ path: path.resolve(cwd, '..', '..', '.env') });
|
dotenv.config({ path: path.resolve(cwd, '..', '..', '.env.dev') });
|
||||||
|
|
||||||
console.log(process.env.MINIO_ENDPOINT, process.env.MINIO_USE_SSL, process.env.MINIO_ACCESS_KEY, process.env.MINIO_SECRET_KEY, process.env.MINIO_BUCKET_NAME);
|
console.log(
|
||||||
|
'config',
|
||||||
|
process.env.MINIO_ENDPOINT,
|
||||||
|
process.env.MINIO_USE_SSL,
|
||||||
|
process.env.MINIO_ACCESS_KEY,
|
||||||
|
process.env.MINIO_SECRET_KEY,
|
||||||
|
process.env.MINIO_BUCKET_NAME,
|
||||||
|
);
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
endPoint: process.env.MINIO_ENDPOINT,
|
endPoint: process.env.MINIO_ENDPOINT,
|
||||||
useSSL: process.env.MINIO_USE_SSL === 'true',
|
useSSL: process.env.MINIO_USE_SSL === 'true',
|
||||||
@ -25,7 +32,7 @@ const main = async () => {
|
|||||||
console.log(config);
|
console.log(config);
|
||||||
};
|
};
|
||||||
|
|
||||||
// main();
|
main();
|
||||||
const putJson = async () => {
|
const putJson = async () => {
|
||||||
const config = await configOssService.putObject(
|
const config = await configOssService.putObject(
|
||||||
'a.json',
|
'a.json',
|
||||||
@ -50,7 +57,7 @@ const downloadMain = async () => {
|
|||||||
});
|
});
|
||||||
// console.log(objectStream);
|
// console.log(objectStream);
|
||||||
};
|
};
|
||||||
downloadMain();
|
// downloadMain();
|
||||||
|
|
||||||
const statInfo = async () => {
|
const statInfo = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ServerResponse } from 'http';
|
import { ServerResponse } from 'node:http';
|
||||||
import { BucketItemStat } from 'minio';
|
import { BucketItemStat } from 'minio';
|
||||||
import fs from 'fs';
|
import fs from 'node:fs';
|
||||||
import path from 'path';
|
import path from 'node:path';
|
||||||
|
|
||||||
const viewableExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'mp4', 'webm', 'mp3', 'wav', 'ogg', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
|
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';
|
import { OssBase } from '../index.ts';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import crypto from 'crypto';
|
import crypto from 'node:crypto';
|
||||||
// 582af9ef5cdc53d6628f45cb842f874a
|
// 582af9ef5cdc53d6628f45cb842f874a
|
||||||
// const hashStr = '{"a":"a"}';
|
// const hashStr = '{"a":"a"}';
|
||||||
// const hash = crypto.createHash('md5').update(hashStr).digest('hex');
|
// const hash = crypto.createHash('md5').update(hashStr).digest('hex');
|
||||||
|
@ -4,7 +4,7 @@ const services = glob.sync('src/services/*.ts');
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
entry: ['src/index.ts', ...services],
|
entry: ['src/index.ts', ...services],
|
||||||
|
target: 'node22',
|
||||||
splitting: false,
|
splitting: false,
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
clean: true,
|
clean: true,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user