mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
229 lines
6.9 KiB
JavaScript
Executable File
229 lines
6.9 KiB
JavaScript
Executable File
import path from "path"
|
|
import fs from "fs"
|
|
import { videoTranscode } from "../../../lib/videoTranscode"
|
|
import { nanoid } from "nanoid"
|
|
import Jimp from "jimp"
|
|
|
|
import pmap from "../../../utils/pMap"
|
|
|
|
const formidable = require("formidable")
|
|
|
|
const maximuns = {
|
|
imageResolution: {
|
|
width: 3840,
|
|
height: 2160,
|
|
},
|
|
imageQuality: 80,
|
|
}
|
|
|
|
const handleUploadVideo = async (file, params) => {
|
|
file.filepath = await videoTranscode(file.filepath, global.uploadCachePath)
|
|
file.newFilename = path.basename(file.filepath)
|
|
|
|
return file
|
|
}
|
|
|
|
const handleImage = async (file, params) => {
|
|
const { width, height } = await new Promise((resolve, reject) => {
|
|
Jimp.read(file.filepath)
|
|
.then((image) => {
|
|
resolve({
|
|
width: image.bitmap.width,
|
|
height: image.bitmap.height,
|
|
})
|
|
})
|
|
.catch((err) => {
|
|
reject(err)
|
|
})
|
|
})
|
|
|
|
if (width > maximuns.imageResolution.width || height > maximuns.imageResolution.height) {
|
|
await new Promise((resolve, reject) => {
|
|
Jimp.read(file.filepath)
|
|
.then((image) => {
|
|
image
|
|
.resize(maximuns.imageResolution.width, maximuns.imageResolution.height)
|
|
.quality(maximuns.imageQuality)
|
|
.write(file.filepath, resolve)
|
|
})
|
|
.catch((err) => {
|
|
reject(err)
|
|
})
|
|
})
|
|
}
|
|
|
|
file.newFilename = path.basename(file.filepath)
|
|
|
|
return file
|
|
}
|
|
|
|
export default async (payload) => {
|
|
if (!payload) {
|
|
throw new Error("Missing payload")
|
|
}
|
|
|
|
const { req } = payload
|
|
|
|
let params = {
|
|
cacheUploadDir: global.uploadCachePath,
|
|
maxFileSize: global.DEFAULT_POSTING_POLICY.maximumFileSize,
|
|
maxFields: global.DEFAULT_POSTING_POLICY.maximunFilesPerRequest,
|
|
acceptedMimeTypes: global.DEFAULT_POSTING_POLICY.acceptedMimeTypes,
|
|
}
|
|
|
|
if (payload.params) {
|
|
params = {
|
|
...params,
|
|
...payload.params,
|
|
}
|
|
}
|
|
|
|
let failed = []
|
|
|
|
// check directories exist
|
|
if (!fs.existsSync(params.cacheUploadDir)) {
|
|
await fs.promises.mkdir(params.cacheUploadDir, { recursive: true })
|
|
}
|
|
|
|
// decode body form-data
|
|
const form = formidable({
|
|
multiples: true,
|
|
keepExtensions: true,
|
|
uploadDir: params.cacheUploadDir,
|
|
maxFileSize: params.maxFileSize,
|
|
maxFields: params.maxFields,
|
|
filename: (name, ext) => {
|
|
name = nanoid()
|
|
|
|
return name + ext
|
|
},
|
|
filter: (stream) => {
|
|
// check if is allowed mime type
|
|
if (!params.acceptedMimeTypes.includes(stream.mimetype)) {
|
|
failed.push({
|
|
fileName: file.originalFilename,
|
|
mimetype: file.mimetype,
|
|
error: "mimetype not allowed",
|
|
})
|
|
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
})
|
|
|
|
const results = await new Promise((resolve, reject) => {
|
|
const processedFiles = []
|
|
const failedFiles = []
|
|
|
|
let queuePromieses = []
|
|
|
|
// create a new thread for each file
|
|
form.parse(req, async (err, fields, data) => {
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
if (!Array.isArray(data.files)) {
|
|
data.files = [data.files]
|
|
}
|
|
|
|
for (let file of data.files) {
|
|
if (!file) continue
|
|
|
|
// create process queue
|
|
queuePromieses.push(async () => {
|
|
// check if is video need to transcode
|
|
switch (file.mimetype) {
|
|
case "video/quicktime": {
|
|
file = await handleUploadVideo(file, params)
|
|
break
|
|
}
|
|
case "image/jpeg": {
|
|
file = await handleImage(file, params)
|
|
break
|
|
}
|
|
case "image/png": {
|
|
file = await handleImage(file, params)
|
|
break
|
|
}
|
|
case "image/gif": {
|
|
file = await handleImage(file, params)
|
|
break
|
|
}
|
|
case "image/bmp": {
|
|
file = await handleImage(file, params)
|
|
break
|
|
}
|
|
case "image/tiff": {
|
|
file = await handleImage(file, params)
|
|
break
|
|
}
|
|
default: {
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
const metadata = {
|
|
mimetype: file.mimetype,
|
|
size: file.size,
|
|
filepath: file.filepath,
|
|
filename: file.newFilename,
|
|
}
|
|
|
|
// upload to s3
|
|
await new Promise((_resolve, _reject) => {
|
|
global.storage.fPutObject(global.storage.defaultBucket, file.newFilename, file.filepath, metadata, (err, etag) => {
|
|
if (err) {
|
|
return _reject(new Error(`Failed to upload file to storage server > ${err.message}`))
|
|
}
|
|
|
|
return _resolve()
|
|
})
|
|
}).catch((err) => {
|
|
return reject(err)
|
|
})
|
|
|
|
// remove file from cache
|
|
await fs.promises.unlink(file.filepath)
|
|
|
|
// get url location
|
|
const remoteUrlObj = global.storage.composeRemoteURL(file.newFilename)
|
|
|
|
// push final filepath to urls
|
|
return {
|
|
name: file.originalFilename,
|
|
id: file.newFilename,
|
|
url: remoteUrlObj,
|
|
}
|
|
})
|
|
}
|
|
|
|
// wait for all files to be processed
|
|
await pmap(
|
|
queuePromieses,
|
|
async (fn) => {
|
|
const result = await fn().catch((err) => {
|
|
console.error(err)
|
|
failedFiles.push(err)
|
|
|
|
return null
|
|
})
|
|
|
|
if (result) {
|
|
processedFiles.push(result)
|
|
}
|
|
},
|
|
{ concurrency: 5 }
|
|
)
|
|
|
|
return resolve({
|
|
files: processedFiles,
|
|
failed: failedFiles,
|
|
})
|
|
})
|
|
})
|
|
|
|
return results
|
|
} |