mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
155 lines
3.8 KiB
TypeScript
155 lines
3.8 KiB
TypeScript
import fs from "node:fs"
|
|
import path from "node:path"
|
|
import { fileTypeFromBuffer } from "file-type"
|
|
|
|
import readChunk from "@shared-utils/readChunk"
|
|
import getFileHash from "@shared-utils/readFileHash"
|
|
|
|
import putObject from "./putObject"
|
|
import Transformation from "../Transformation"
|
|
|
|
export type FileHandlePayload = {
|
|
user_id: string
|
|
filePath: string
|
|
workPath: string
|
|
targetPath?: string // mostly provided by processed results
|
|
//uploadId?: string
|
|
transformations?: Array<string>
|
|
useCompression?: boolean
|
|
s3Provider?: string
|
|
onProgress?: Function
|
|
}
|
|
|
|
export type S3UploadPayload = {
|
|
filePath: string
|
|
basePath: string
|
|
targetPath?: string
|
|
s3Provider?: string
|
|
onProgress?: Function
|
|
}
|
|
|
|
export default class Upload {
|
|
static fileHandle = async (payload: FileHandlePayload) => {
|
|
if (!payload.transformations) {
|
|
payload.transformations = []
|
|
}
|
|
|
|
// if compression is enabled and no transformations are provided, add basic transformations for images or videos
|
|
if (
|
|
payload.useCompression === true &&
|
|
payload.transformations.length === 0
|
|
) {
|
|
payload.transformations.push("optimize")
|
|
}
|
|
|
|
// process file upload if transformations are provided
|
|
if (payload.transformations.length > 0) {
|
|
// process
|
|
const processed = await Upload.transform(payload)
|
|
|
|
// overwrite filePath
|
|
payload.filePath = processed.filePath
|
|
}
|
|
|
|
// upload
|
|
const result = await Upload.toS3({
|
|
filePath: payload.filePath,
|
|
targetPath: payload.targetPath,
|
|
basePath: payload.user_id,
|
|
onProgress: payload.onProgress,
|
|
s3Provider: payload.s3Provider,
|
|
})
|
|
|
|
// delete workpath
|
|
await fs.promises.rm(payload.workPath, { recursive: true, force: true })
|
|
|
|
return result
|
|
}
|
|
|
|
static transform = async (payload: FileHandlePayload) => {
|
|
if (Array.isArray(payload.transformations)) {
|
|
for await (const transformation of payload.transformations) {
|
|
const transformationResult = await Transformation.transform({
|
|
filePath: payload.filePath,
|
|
workPath: payload.workPath,
|
|
onProgress: payload.onProgress,
|
|
handler: transformation,
|
|
})
|
|
|
|
// if is a file, overwrite filePath
|
|
if (transformationResult.outputFile) {
|
|
payload.filePath = transformationResult.outputFile
|
|
}
|
|
|
|
// if is a directory, overwrite filePath to upload entire directory
|
|
if (transformationResult.outputPath) {
|
|
payload.filePath = transformationResult.outputPath
|
|
payload.targetPath = transformationResult.outputFile
|
|
//payload.isDirectory = true
|
|
}
|
|
}
|
|
}
|
|
|
|
return payload
|
|
}
|
|
|
|
static toS3 = async (payload: S3UploadPayload) => {
|
|
const { filePath, basePath, targetPath, s3Provider, onProgress } =
|
|
payload
|
|
|
|
// if targetPath is provided, means its a directory
|
|
const isDirectory = !!targetPath
|
|
|
|
const metadata = await this.buildFileMetadata(
|
|
isDirectory ? targetPath : filePath,
|
|
)
|
|
|
|
let uploadPath = path.join(basePath, metadata["File-Hash"])
|
|
|
|
if (isDirectory) {
|
|
uploadPath = path.join(basePath, global.nanoid())
|
|
}
|
|
|
|
if (typeof onProgress === "function") {
|
|
onProgress({
|
|
percent: 0,
|
|
state: "uploading_s3",
|
|
})
|
|
}
|
|
|
|
// console.log("Uploading to S3:", {
|
|
// filePath: filePath,
|
|
// basePath: basePath,
|
|
// uploadPath: uploadPath,
|
|
// targetPath: targetPath,
|
|
// metadata: metadata,
|
|
// s3Provider: s3Provider,
|
|
// })
|
|
|
|
const result = await putObject({
|
|
filePath: filePath,
|
|
uploadPath: uploadPath,
|
|
metadata: metadata,
|
|
targetFilename: isDirectory ? path.basename(targetPath) : null,
|
|
provider: s3Provider,
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
static async buildFileMetadata(filePath: string) {
|
|
const firstBuffer = await readChunk(filePath, {
|
|
length: 4100,
|
|
})
|
|
const fileHash = await getFileHash(fs.createReadStream(filePath))
|
|
const fileType = await fileTypeFromBuffer(firstBuffer)
|
|
|
|
const metadata = {
|
|
"File-Hash": fileHash,
|
|
"Content-Type": fileType?.mime ?? "application/octet-stream",
|
|
}
|
|
|
|
return metadata
|
|
}
|
|
}
|