53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
const crypto = require('crypto')
|
|||
|
|
const fs = require('fs')
|
||
|
|
const path = require('path')
|
||
|
|
const multer = require('multer')
|
||
|
|
const { ok, fail } = require('./http')
|
||
|
|
|
||
|
|
const uploadDir = process.env.UPLOAD_DIR
|
||
|
|
? path.resolve(process.env.UPLOAD_DIR)
|
||
|
|
: path.join(__dirname, '..', 'public', 'uploads')
|
||
|
|
|
||
|
|
const IMAGE_RE = /^image\/(png|jpe?g|webp)$/i
|
||
|
|
const VIDEO_RE = /^video\/(mp4|quicktime|webm)$/i
|
||
|
|
|
||
|
|
const storage = multer.diskStorage({
|
||
|
|
destination(req, file, cb) {
|
||
|
|
fs.mkdirSync(uploadDir, { recursive: true })
|
||
|
|
cb(null, uploadDir)
|
||
|
|
},
|
||
|
|
filename(req, file, cb) {
|
||
|
|
const ext = path.extname(file.originalname || '').toLowerCase() || '.bin'
|
||
|
|
cb(null, `${Date.now().toString(36)}${crypto.randomBytes(3).toString('hex')}${ext}`)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
function uploader(options) {
|
||
|
|
const imagesOnly = !!(options && options.imagesOnly)
|
||
|
|
const middleware = multer({
|
||
|
|
storage,
|
||
|
|
limits: { fileSize: imagesOnly ? 5 * 1024 * 1024 : 80 * 1024 * 1024 },
|
||
|
|
fileFilter(req, file, cb) {
|
||
|
|
const mime = file.mimetype || ''
|
||
|
|
const allowed = IMAGE_RE.test(mime) || (!imagesOnly && VIDEO_RE.test(mime))
|
||
|
|
cb(null, allowed)
|
||
|
|
}
|
||
|
|
}).single('file')
|
||
|
|
|
||
|
|
return (req, res) => {
|
||
|
|
middleware(req, res, (error) => {
|
||
|
|
if (error) {
|
||
|
|
const tooLarge = error.code === 'LIMIT_FILE_SIZE'
|
||
|
|
return fail(res, 400, tooLarge ? (imagesOnly ? '图片需小于 5MB' : '文件需小于 80MB') : '上传失败')
|
||
|
|
}
|
||
|
|
if (!req.file) {
|
||
|
|
return fail(res, 400, imagesOnly ? '仅支持 png/jpg/webp 图片' : '仅支持 png/jpg/webp 图片或 mp4/mov/webm 视频')
|
||
|
|
}
|
||
|
|
const type = VIDEO_RE.test(req.file.mimetype) ? 'video' : 'image'
|
||
|
|
ok(res, { url: `/static/uploads/${req.file.filename}`, type })
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = { uploader, uploadDir }
|