-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
minio.ts
124 lines (117 loc) · 3.49 KB
/
minio.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* eslint-disable @typescript-eslint/naming-convention */
import type { Readable as ReadableStream } from 'node:stream';
import { join } from 'path';
import { BadRequestException, Injectable } from '@nestjs/common';
import { getRandomString } from '@teable/core';
import * as minio from 'minio';
import sharp from 'sharp';
import { IStorageConfig, StorageConfig } from '../../../configs/storage';
import { second } from '../../../utils/second';
import type StorageAdapter from './adapter';
import type { IPresignParams, IPresignRes, IRespHeaders } from './types';
@Injectable()
export class MinioStorage implements StorageAdapter {
minioClient: minio.Client;
constructor(@StorageConfig() readonly config: IStorageConfig) {
const { endPoint, port, useSSL, accessKey, secretKey } = this.config.minio;
this.minioClient = new minio.Client({
endPoint: endPoint!,
port: port!,
useSSL: useSSL!,
accessKey: accessKey!,
secretKey: secretKey!,
});
}
async presigned(
bucket: string,
dir: string,
presignedParams: IPresignParams
): Promise<IPresignRes> {
const { tokenExpireIn, uploadMethod } = this.config;
const { expiresIn, contentLength, contentType, hash } = presignedParams;
const token = getRandomString(12);
const filename = hash ?? token;
const path = join(dir, filename);
const requestHeaders = {
'Content-Type': contentType,
'Content-Length': contentLength,
};
try {
const url = await this.minioClient.presignedUrl(
uploadMethod,
bucket,
path,
expiresIn ?? second(tokenExpireIn),
requestHeaders
);
return {
url,
path,
token,
uploadMethod,
requestHeaders,
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
throw new BadRequestException(`Minio presigned error${e?.message ? `: ${e.message}` : ''}`);
}
}
async getObjectMeta(bucket: string, path: string, _token: string) {
const objectName = path;
const { metaData, size, etag: hash } = await this.minioClient.statObject(bucket, objectName);
const mimetype = metaData['content-type'] as string;
const url = `/${bucket}/${objectName}`;
if (!mimetype?.startsWith('image/')) {
return {
hash,
size,
mimetype,
url,
};
}
const stream = await this.minioClient.getObject(bucket, objectName);
const metaReader = sharp();
const sharpReader = stream.pipe(metaReader);
const { width, height } = await sharpReader.metadata();
return {
hash,
size,
mimetype,
width,
height,
url,
};
}
async getPreviewUrl(
bucket: string,
path: string,
expiresIn: number = second(this.config.urlExpireIn),
respHeaders?: IRespHeaders
) {
return this.minioClient.presignedGetObject(bucket, path, expiresIn, respHeaders);
}
async uploadFileWidthPath(
bucket: string,
path: string,
filePath: string,
metadata: Record<string, unknown>
) {
const { etag: hash } = await this.minioClient.fPutObject(bucket, path, filePath, metadata);
return {
hash,
url: `/${bucket}/${path}`,
};
}
async uploadFile(
bucket: string,
path: string,
stream: Buffer | ReadableStream,
metadata?: Record<string, unknown>
) {
const { etag: hash } = await this.minioClient.putObject(bucket, path, stream, metadata);
return {
hash,
url: `/${bucket}/${path}`,
};
}
}