|  |  |  | 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); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } |