server: add ali-oss

pull/64/head
fantasticit 2022-06-04 19:48:43 +08:00
parent 757eac171a
commit ed03f1e90f
4 changed files with 159 additions and 2 deletions

View File

@ -10,7 +10,7 @@ interface AxiosInstance extends Axios {
export const HttpClient = axios.create({ export const HttpClient = axios.create({
baseURL: process.env.SERVER_API_URL, baseURL: process.env.SERVER_API_URL,
timeout: 10 * 1000, timeout: 10 * 60 * 1000,
withCredentials: true, withCredentials: true,
}) as AxiosInstance; }) as AxiosInstance;

View File

@ -0,0 +1,152 @@
import { FILE_CHUNK_SIZE } from '@think/domains';
import * as AliyunOSS from 'ali-oss';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { pipeWriteStream } from './local.client';
import { BaseOssClient, FileQuery } from './oss.client';
export class AliyunOssClient extends BaseOssClient {
private client: AliyunOSS | null;
/**
* ali-oss
* @returns
*/
private ensureAliyunOssClient(): AliyunOSS {
if (this.client) {
return this.client;
}
const config = this.configService.get('oss.aliyun.config');
try {
this.client = new AliyunOSS(config);
return this.client;
} catch (err) {
console.log('无法启动阿里云存储服务,请检查阿里云 OSS 配置是否正确');
}
}
/**
*
* @param md5
* @param filename
* @returns
*/
private getInOssFileName(md5, filename) {
return `/think/${md5}/${filename}`;
}
/**
* oss
* @param md5
* @param filename
* @returns
*/
private async checkIfAlreadyInOss(md5, filename) {
this.ensureAliyunOssClient();
const inOssFileName = this.getInOssFileName(md5, filename);
const ifExist = await this.client.head(inOssFileName).catch(() => false);
if (ifExist) {
return ifExist.res.requestUrls[0];
}
return false;
}
/**
*
* @param md5
* @returns
*/
private getStoreDir(md5: string) {
const tmpdir = os.tmpdir();
const dir = path.join(tmpdir, md5);
fs.ensureDirSync(dir);
return dir;
}
/**
*
* @param file
* @param query
* @returns
*/
async uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string> {
const client = this.ensureAliyunOssClient();
const { filename, md5 } = query;
const maybeOssURL = await this.checkIfAlreadyInOss(md5, filename);
if (maybeOssURL) {
return maybeOssURL;
}
const inOssFileName = this.getInOssFileName(md5, filename);
const res = await client.put(inOssFileName, file.buffer);
return res.url;
}
/**
*
* FIXME:
* @param file
* @param query
* @returns
*/
async uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<string | void> {
const { md5, filename, chunkIndex } = query;
if (!('chunkIndex' in query)) {
throw new Error('请指定 chunkIndex');
}
const maybeOssURL = await this.checkIfAlreadyInOss(md5, filename);
if (maybeOssURL) {
return maybeOssURL;
}
const dir = this.getStoreDir(md5);
const chunksDir = path.join(dir, 'chunks');
fs.ensureDirSync(chunksDir);
fs.writeFileSync(path.join(chunksDir, '' + chunkIndex), file.buffer);
}
/**
*
* FIXME:
* @param query
* @returns
*/
async mergeChunk(query: FileQuery): Promise<string> {
const { filename, md5 } = query;
this.ensureAliyunOssClient();
const inOssFileName = this.getInOssFileName(md5, filename);
const dir = this.getStoreDir(md5);
const absoluteFilepath = path.join(dir, filename);
const chunksDir = path.join(dir, 'chunks');
const chunks = fs.readdirSync(chunksDir);
chunks.sort((a, b) => Number(a) - Number(b));
await Promise.all(
chunks.map((chunk, index) => {
return pipeWriteStream(
path.join(chunksDir, chunk),
fs.createWriteStream(absoluteFilepath, {
start: index * FILE_CHUNK_SIZE,
end: (index + 1) * FILE_CHUNK_SIZE,
})
);
})
);
fs.removeSync(chunksDir);
const ret = await this.client.multipartUpload(inOssFileName, absoluteFilepath);
fs.removeSync(absoluteFilepath);
return ret.res.requestUrls[0];
}
}

View File

@ -1,11 +1,16 @@
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { AliyunOssClient } from './aliyun.client';
import { LocalOssClient } from './local.client'; import { LocalOssClient } from './local.client';
import { OssClient } from './oss.client'; import { OssClient } from './oss.client';
export { OssClient }; export { OssClient };
export const getOssClient = (configService: ConfigService): OssClient => { export const getOssClient = (configService: ConfigService): OssClient => {
if (configService.get('oss.aliyun.enable')) {
return new AliyunOssClient(configService);
}
if (configService.get('oss.local.enable')) { if (configService.get('oss.local.enable')) {
return new LocalOssClient(configService); return new LocalOssClient(configService);
} }

View File

@ -7,7 +7,7 @@ import { BaseOssClient, FileQuery } from './oss.client';
export const FILE_DEST = '/' + 'static'; export const FILE_DEST = '/' + 'static';
export const FILE_ROOT_PATH = path.join(__dirname, '../../../', FILE_DEST); export const FILE_ROOT_PATH = path.join(__dirname, '../../../', FILE_DEST);
const pipeWriteStream = (filepath, writeStream): Promise<void> => { export const pipeWriteStream = (filepath, writeStream): Promise<void> => {
return new Promise((resolve) => { return new Promise((resolve) => {
const readStream = fs.createReadStream(filepath); const readStream = fs.createReadStream(filepath);
readStream.on('end', () => { readStream.on('end', () => {