session-desktop/ts/node/attachment_channel.ts

95 lines
3.1 KiB
TypeScript

import path from 'path';
import { ipcMain } from 'electron';
import { isString, map } from 'lodash';
import rimraf from 'rimraf';
import fse from 'fs-extra';
import pify from 'pify';
// eslint-disable-next-line import/no-named-default
import { default as glob } from 'glob';
import { sqlNode } from './sql'; // checked - only node
import { createDeleter, getAttachmentsPath } from '../shared/attachments/shared_attachments';
let initialized = false;
const ERASE_ATTACHMENTS_KEY = 'erase-attachments';
const CLEANUP_ORPHANED_ATTACHMENTS_KEY = 'cleanup-orphaned-attachments';
// ensureDirectory :: AbsolutePath -> IO Unit
const ensureDirectory = async (userDataPath: string) => {
if (!isString(userDataPath)) {
throw new TypeError("'userDataPath' must be a string");
}
await fse.ensureDir(getAttachmentsPath(userDataPath));
};
const deleteAll = async ({
userDataPath,
attachments,
}: {
userDataPath: string;
attachments: any;
}) => {
const deleteFromDisk = createDeleter(getAttachmentsPath(userDataPath));
for (let index = 0, max = attachments.length; index < max; index += 1) {
const file = attachments[index];
// eslint-disable-next-line no-await-in-loop
await deleteFromDisk(file);
}
console.log(`deleteAll: deleted ${attachments.length} files`);
};
const getAllAttachments = async (userDataPath: string) => {
const dir = getAttachmentsPath(userDataPath);
const pattern = path.join(dir, '**', '*');
const files = await pify(glob)(pattern, { nodir: true });
return map(files, file => path.relative(dir, file));
};
async function cleanupOrphanedAttachments(userDataPath: string) {
const allAttachments = await getAllAttachments(userDataPath);
const orphanedAttachments = sqlNode.removeKnownAttachments(allAttachments);
await deleteAll({
userDataPath,
attachments: orphanedAttachments,
});
}
export async function initAttachmentsChannel({ userDataPath }: { userDataPath: string }) {
if (initialized) {
throw new Error('initialze: Already initialized!');
}
initialized = true;
console.log('Ensure attachments directory exists');
await ensureDirectory(userDataPath);
const attachmentsDir = getAttachmentsPath(userDataPath);
ipcMain.on(ERASE_ATTACHMENTS_KEY, event => {
try {
rimraf.sync(attachmentsDir);
event.sender.send(`${ERASE_ATTACHMENTS_KEY}-done`);
} catch (error) {
const errorForDisplay = error && error.stack ? error.stack : error;
console.log(`erase attachments error: ${errorForDisplay}`);
event.sender.send(`${ERASE_ATTACHMENTS_KEY}-done`, error);
}
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
ipcMain.on(CLEANUP_ORPHANED_ATTACHMENTS_KEY, async event => {
try {
await cleanupOrphanedAttachments(userDataPath);
event.sender.send(`${CLEANUP_ORPHANED_ATTACHMENTS_KEY}-done`);
} catch (error) {
const errorForDisplay = error && error.stack ? error.stack : error;
console.log(`cleanup orphaned attachments error: ${errorForDisplay}`);
event.sender.send(`${CLEANUP_ORPHANED_ATTACHMENTS_KEY}-done`, error);
}
});
}