waha / src /core /media /local /MediaLocalStorage.ts
NitinBot002's picture
Upload 384 files
4327358 verified
import { IMediaStorage, MediaData } from '@waha/core/media/IMediaStorage';
import { SECOND } from '@waha/structures/enums.dto';
import * as fsp from 'fs/promises';
import * as path from 'path';
import { Logger } from 'pino';
import fs = require('fs');
import { fileExists } from '@waha/utils/files';
import { deleteAsync } from 'del';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const writeFileAtomic = require('write-file-atomic');
/**
* Save files locally using the filesystem
*/
export class MediaLocalStorage implements IMediaStorage {
private readonly lifetimeMs: number;
constructor(
protected log: Logger,
private filesFolder: string,
private baseUrl: string,
lifetimeSeconds: number,
) {
this.lifetimeMs = lifetimeSeconds * SECOND;
if (this.lifetimeMs === 0) {
this.log.info('Files lifetime is 0, files will not be removed');
}
}
async init() {
return;
}
async exists(data: MediaData): Promise<boolean> {
const filepath = this.getFullPath(data);
return await fileExists(filepath);
}
public async save(buffer: Buffer, data: MediaData): Promise<boolean> {
const filepath = this.getFullPath(data);
const folder = path.dirname(filepath);
await fsp.mkdir(folder, { recursive: true });
await writeFileAtomic(filepath, buffer);
this.postponeRemoval(filepath);
return true;
}
public async getStorageData(data: MediaData) {
const filename = this.getKey(data);
const url = this.baseUrl + filename;
return { url };
}
async purge() {
if (this.lifetimeMs === 0) {
this.log.info('No need to purge files with lifetime 0');
return;
}
if (fs.existsSync(this.filesFolder)) {
deleteAsync([`${this.filesFolder}/*`], { force: true }).then((paths) => {
if (paths.length === 0) {
return;
}
this.log.info('Deleted files and directories:\n', paths.join('\n'));
});
} else {
fs.mkdirSync(this.filesFolder);
this.log.info(`Directory '${this.filesFolder}' created from scratch`);
}
}
private getKey(data: MediaData) {
return `${data.session}/${data.message.id}.${data.file.extension}`;
}
private getFullPath(data: MediaData) {
const filepath = this.getKey(data);
return path.resolve(`${this.filesFolder}/${filepath}`);
}
private postponeRemoval(filepath: string) {
if (this.lifetimeMs === 0) {
return;
}
setTimeout(
() =>
fs.unlink(filepath, () => {
this.log.info(`File ${filepath} was removed`);
}),
this.lifetimeMs,
);
}
async close() {
return;
}
}