UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

112 lines (110 loc) 3.4 kB
import { FILE_UPLOADS, RESUMABLE_UPLOADS } from "../../constants.js"; import { getStorage } from "../../storage/index.js"; import database_default from "../../database/index.js"; import emitter_default from "../../emitter.js"; import { extractMetadata } from "../files/lib/extract-metadata.js"; import { ItemsService } from "../items.js"; import { getSchema } from "../../utils/get-schema.js"; import "../index.js"; import { TusDataStore } from "./data-store.js"; import { getTusLocker } from "./lockers.js"; import { useEnv } from "@directus/env"; import { isDirectusError } from "@directus/errors"; import { toArray } from "@directus/utils"; import { pick } from "lodash-es"; import { supportsTus } from "@directus/storage"; import { Server } from "@tus/server"; //#region src/services/tus/server.ts async function createTusStore(context) { const env = useEnv(); const storage = await getStorage(); const location = toArray(env["STORAGE_LOCATIONS"])[0]; const driver = storage.location(location); if (!supportsTus(driver)) throw new Error(`Storage location ${location} does not support the TUS protocol`); return new TusDataStore({ constants: RESUMABLE_UPLOADS, accountability: context.accountability, schema: context.schema, location, driver }); } async function createTusServer(context) { const env = useEnv(); const server = new Server({ path: "/files/tus", datastore: await createTusStore(context), locker: getTusLocker(), ...FILE_UPLOADS.MAX_SIZE !== null && { maxSize: FILE_UPLOADS.MAX_SIZE }, async onUploadFinish(_req, upload) { const schema = await getSchema(); const service = new ItemsService("directus_files", { schema }); const file = (await service.readByQuery({ filter: { tus_id: { _eq: upload.id } }, limit: 1 }))[0]; if (!file) return {}; const targetId = upload.metadata["id"]; const isReplacement = targetId !== file.id; let targetFile; let uploadFields; if (isReplacement) { targetFile = await service.readOne(targetId); uploadFields = pick(file, [ "filename_download", "filesize", "type" ]); } else { targetFile = file; uploadFields = { tus_id: null, tus_data: null }; } const metadata = await extractMetadata(targetFile.storage, { ...targetFile, ...uploadFields }); await service.updateOne(targetId, { ...uploadFields, ...metadata }); if (isReplacement) await service.deleteOne(file.id); const fileData = { ...targetFile, ...uploadFields, ...metadata, id: targetId }; emitter_default.emitAction("files.upload", { payload: fileData, key: fileData.id, collection: "directus_files" }, { schema, database: database_default(), accountability: context.accountability ?? null }); return { headers: { "Directus-File-Id": upload.metadata["id"] } }; }, onResponseError(_req, err) { if (isDirectusError(err)) return { status_code: err.status, body: err.message + "\n" }; }, generateUrl(_req, opts) { return env["PUBLIC_URL"] + "/files/tus/" + opts.id; }, allowedHeaders: env["CORS_ALLOWED_HEADERS"], exposedHeaders: env["CORS_EXPOSED_HEADERS"], relativeLocation: String(env["PUBLIC_URL"]).startsWith("http") }); return [server, cleanup]; function cleanup() { server.removeAllListeners(); } } //#endregion export { createTusServer };