lin-mizar
Version:
The core library of Lin CMS
154 lines (153 loc) • 5.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.multipart = void 0;
const tslib_1 = require("tslib");
const async_busboy_1 = tslib_1.__importDefault(require("./async-busboy"));
const exception_1 = require("../exception/");
const path_1 = require("path");
const config_1 = require("../config");
const CodeMessage = config_1.config.getItem('codeMessage', {});
/**
* 解析上传文件
* @param app app实例
*/
exports.multipart = (app) => {
app.context.multipart = async function (opts) {
// multipart/form-data
if (!this.is('multipart')) {
throw new Error('Content-Type must be multipart/*');
}
let filePromises = [];
const { fields } = await async_busboy_1.default(this.req, {
onFile: async function (fieldName, file, filename, encoding, mimeType) {
const filePromise = new Promise((resolve, reject) => {
let buffers = [];
file
.on('error', err => {
file.resume();
reject(err);
})
.on('data', (d) => {
buffers.push(d);
})
.on('end', () => {
const buf = Buffer.concat(buffers);
resolve({
size: buf.length,
encoding: encoding,
fieldName: fieldName,
filename: filename,
mimeType: mimeType,
data: buf
});
});
});
filePromises.push(filePromise);
}
});
let files = [];
let totalSize = 0;
for (const filePromise of filePromises) {
let file;
try {
file = await filePromise;
}
catch (error) {
throw new exception_1.HttpException({ code: 10210 });
}
const ext = path_1.extname(file.filename);
if (!checkFileExtension(ext, opts && opts.include, opts && opts.exclude)) {
throw new exception_1.FileExtensionException({
code: 10130,
message: CodeMessage.getMessage(10130).replace('{ext}', ext)
});
}
const { valid, conf } = checkSingleFileSize(file.size, opts && opts.singleLimit);
if (!valid) {
throw new exception_1.FileTooLargeException({
code: 10110,
message: CodeMessage.getMessage(10110)
.replace('{name}', file.filename)
.replace('{size}', conf)
});
}
// 计算总大小
totalSize += file.size;
files.push(file);
}
const { valid, conf } = checkFileNums(files.length, opts && opts.fileNums);
if (!valid) {
throw new exception_1.FileTooManyException({
code: 10121,
message: CodeMessage.getMessage(10121).replace('{num}', conf)
});
}
const { valid: totalValid, conf: totalConf } = checkTotalFileSize(totalSize, opts && opts.totalLimit);
if (!totalValid) {
throw new exception_1.FileTooLargeException({
code: 10111,
message: CodeMessage.getMessage(10111).replace('{size}', totalConf)
});
}
this.request.fields = fields;
return files;
};
};
function checkSingleFileSize(size, singleLimit) {
// file_include,file_exclude,file_single_limit,file_total_limit,file_store_dir
// 默认 2M
const confSize = singleLimit
? singleLimit
: config_1.config.getItem('file.singleLimit', 1024 * 1024 * 2);
return {
valid: confSize > size,
conf: confSize
};
}
function checkTotalFileSize(size, totalLimit) {
// 默认 20M
const confSize = totalLimit
? totalLimit
: config_1.config.getItem('file.totalLimit', 1024 * 1024 * 20);
return {
valid: confSize > size,
conf: confSize
};
}
function checkFileNums(nums, fileNums) {
// 默认 10
const confNums = fileNums ? fileNums : config_1.config.getItem('file.nums', 10);
return {
valid: confNums > nums,
conf: confNums
};
}
function checkFileExtension(ext, include, exclude) {
const fileInclude = include ? include : config_1.config.getItem('file.include');
const fileExclude = exclude ? exclude : config_1.config.getItem('file.exclude');
// 如果两者都有取fileInclude,有一者则用一者
if (fileInclude && fileExclude) {
if (!Array.isArray(fileInclude)) {
throw new Error('file_include must an array!');
}
return fileInclude.includes(ext);
}
else if (fileInclude && !fileExclude) {
// 有include,无exclude
if (!Array.isArray(fileInclude)) {
throw new Error('file_include must an array!');
}
return fileInclude.includes(ext);
}
else if (fileExclude && !fileInclude) {
// 有exclude,无include
if (!Array.isArray(fileExclude)) {
throw new Error('file_exclude must an array!');
}
return !fileExclude.includes(ext);
}
else {
// 二者都没有
return true;
}
}