70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
// Draft implementation for Gateway media upload (Fastify-style)
|
||
// Adjust to the actual server framework (Fastify/Express) used by clawdbot gateway.
|
||
|
||
import path from 'node:path'
|
||
import fs from 'node:fs/promises'
|
||
import { randomUUID } from 'node:crypto'
|
||
|
||
// Pseudo helpers – replace with gateway's real config/log/auth utilities
|
||
const CONFIG = {
|
||
uploads: {
|
||
maxItemBytes: 25 * 1024 * 1024,
|
||
accept: [ 'image/', 'application/pdf', 'text/plain', 'application/zip' ],
|
||
},
|
||
mediaDir: path.resolve(process.env.CLAWDBOT_MEDIA_DIR || path.join(process.env.HOME || process.cwd(), '.clawdbot', 'media', 'inbound')),
|
||
}
|
||
|
||
function ensureDir(p: string) {
|
||
return fs.mkdir(p, { recursive: true })
|
||
}
|
||
|
||
function inferExt(mime: string, name?: string) {
|
||
const fromName = name && path.extname(name)
|
||
if (fromName) return fromName
|
||
if (mime.startsWith('image/')) return '.png'
|
||
if (mime === 'application/pdf') return '.pdf'
|
||
return ''
|
||
}
|
||
|
||
function allowed(mime: string) {
|
||
return CONFIG.uploads.accept.some(a => a.endsWith('/*') ? mime.startsWith(a.slice(0, -1)) : mime === a)
|
||
}
|
||
|
||
export async function registerMediaUploadRoute(fastify: any) {
|
||
await ensureDir(CONFIG.mediaDir)
|
||
|
||
fastify.register(import('@fastify/multipart'), { limits: { fileSize: CONFIG.uploads.maxItemBytes } })
|
||
|
||
fastify.post('/api/media/upload', async (req: any, reply: any) => {
|
||
const mp = await req.parts()
|
||
const files: any[] = []
|
||
|
||
for await (const part of mp) {
|
||
if (part.type !== 'file') continue
|
||
const { filename, mimetype } = part
|
||
if (!allowed(mimetype)) {
|
||
await part.file?.resume()
|
||
return reply.code(415).send({ error: 'unsupported_type', mimetype })
|
||
}
|
||
const id = randomUUID()
|
||
const ext = inferExt(mimetype, filename)
|
||
const outPath = path.join(CONFIG.mediaDir, `${id}${ext}`)
|
||
const chunks: Buffer[] = []
|
||
let size = 0
|
||
for await (const chunk of part.file) {
|
||
size += chunk.length
|
||
if (size > CONFIG.uploads.maxItemBytes) {
|
||
return reply.code(413).send({ error: 'file_too_large' })
|
||
}
|
||
chunks.push(chunk)
|
||
}
|
||
const buf = Buffer.concat(chunks)
|
||
await fs.writeFile(outPath, buf)
|
||
const mediaPath = `MEDIA:${outPath}`
|
||
files.push({ path: mediaPath, mime: mimetype, name: filename, size })
|
||
}
|
||
|
||
return reply.send({ files })
|
||
})
|
||
}
|