Files
crm/apps/api/src/storage/local-file.storage.ts
T

49 lines
1.4 KiB
TypeScript

import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { createReadStream, promises as fs } from 'fs';
import * as path from 'path';
import type { Readable } from 'stream';
@Injectable()
export class LocalFileStorage implements OnModuleInit {
private readonly root: string;
constructor(private readonly config: ConfigService) {
this.root =
this.config.get<string>('UPLOAD_DIR')?.trim() ||
path.join(process.cwd(), 'uploads');
}
async onModuleInit() {
await fs.mkdir(this.root, { recursive: true });
}
absolutePath(storageKey: string): string {
const resolved = path.resolve(this.root, storageKey);
if (!resolved.startsWith(path.resolve(this.root))) {
throw new Error('Invalid storage key');
}
return resolved;
}
async save(storageKey: string, buffer: Buffer): Promise<void> {
const abs = this.absolutePath(storageKey);
await fs.mkdir(path.dirname(abs), { recursive: true });
await fs.writeFile(abs, buffer);
}
async remove(storageKey: string): Promise<void> {
const abs = this.absolutePath(storageKey);
try {
await fs.unlink(abs);
} catch (err) {
const code = (err as NodeJS.ErrnoException).code;
if (code !== 'ENOENT') throw err;
}
}
openReadStream(storageKey: string): Readable {
return createReadStream(this.absolutePath(storageKey));
}
}