/** * Приватное объектное хранилище (S3-совместимое) для файлов чатов — общее для API и воркера. * Настройки — из S3_* в .env. */ import { randomUUID } from 'node:crypto'; import { GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; let client: S3Client | null = null; function s3() { client ??= new S3Client({ endpoint: process.env.S3_ENDPOINT ?? 'http://localhost:9000', region: process.env.S3_REGION ?? 'us-east-1', forcePathStyle: true, credentials: { accessKeyId: process.env.S3_ACCESS_KEY ?? '', secretAccessKey: process.env.S3_SECRET_KEY ?? '' }, }); return client; } const bucket = () => process.env.S3_BUCKET ?? 'barev-private'; /** Расширение из имени файла (только буквы/цифры), иначе bin */ function extOf(name: string | null | undefined) { const m = name?.match(/\.([a-z0-9]{1,8})$/i); return m ? m[1]!.toLowerCase() : 'bin'; } export async function putFile(prefix: string, body: Buffer, mime: string, fileName?: string | null) { const key = `${prefix}/${randomUUID()}.${extOf(fileName)}`; await s3().send( new PutObjectCommand({ Bucket: bucket(), Key: key, Body: body, ContentType: mime, ...(process.env.NODE_ENV === 'production' ? { ServerSideEncryption: 'AES256' as const } : {}), }), ); return key; } export async function getFile(key: string): Promise { const res = await s3().send(new GetObjectCommand({ Bucket: bucket(), Key: key })); return Buffer.from(await res.Body!.transformToByteArray()); }