Barazo AppView backend barazo.forum
at main 48 lines 1.5 kB view raw
1import { randomUUID } from 'node:crypto' 2import { mkdir, writeFile, unlink } from 'node:fs/promises' 3import { join } from 'node:path' 4import type { Logger } from './logger.js' 5 6export interface StorageService { 7 store(data: Buffer, mimeType: string, prefix: string): Promise<string> 8 delete(url: string): Promise<void> 9} 10 11const MIME_TO_EXT: Record<string, string> = { 12 'image/jpeg': '.jpg', 13 'image/png': '.png', 14 'image/webp': '.webp', 15 'image/gif': '.gif', 16} 17 18export function createLocalStorage( 19 uploadDir: string, 20 baseUrl: string, 21 logger: Logger 22): StorageService { 23 return { 24 async store(data: Buffer, mimeType: string, prefix: string): Promise<string> { 25 const ext = MIME_TO_EXT[mimeType] ?? '.bin' 26 const filename = `${prefix}-${randomUUID()}${ext}` 27 const dir = join(uploadDir, prefix) 28 await mkdir(dir, { recursive: true }) 29 const filepath = join(dir, filename) 30 await writeFile(filepath, data) 31 logger.debug({ filepath, size: data.length }, 'File stored') 32 return `${baseUrl}/uploads/${prefix}/${filename}` 33 }, 34 35 async delete(url: string): Promise<void> { 36 try { 37 const uploadsIdx = url.indexOf('/uploads/') 38 if (uploadsIdx === -1) return 39 const relativePath = url.slice(uploadsIdx + '/uploads/'.length) 40 const filepath = join(uploadDir, relativePath) 41 await unlink(filepath) 42 logger.debug({ filepath }, 'File deleted') 43 } catch { 44 // Best-effort deletion 45 } 46 }, 47 } 48}