Switch to async fs.exists

We cannot expose the sync version over the context bridge - the node:fs module
is not available to the preload script under context isolation.
This commit is contained in:
Manav Rathi 2024-03-23 19:41:59 +05:30
parent b1d0909675
commit f21dc84840
No known key found for this signature in database
11 changed files with 97 additions and 77 deletions

View file

@ -168,8 +168,6 @@ const writeNodeStream = async (
// - Export
const exists = (path: string) => existsSync(path);
const checkExistsAndCreateDir = (dirPath: string) =>
fs.mkdir(dirPath, { recursive: true });
@ -442,7 +440,6 @@ contextBridge.exposeInMainWorld("ElectronAPIs", {
},
// - Export
exists,
checkExistsAndCreateDir,
saveStreamToDisk,
saveFileToDisk,

View file

@ -98,8 +98,8 @@ export default function ExportModal(props: Props) {
// HELPER FUNCTIONS
// =======================
const verifyExportFolderExists = () => {
if (!exportService.exportFolderExists(exportFolder)) {
const verifyExportFolderExists = async () => {
if (!(await exportService.exportFolderExists(exportFolder))) {
appContext.setDialogMessage(
getExportDirectoryDoesNotExistMessage(),
);
@ -109,7 +109,7 @@ export default function ExportModal(props: Props) {
const syncExportRecord = async (exportFolder: string): Promise<void> => {
try {
if (!exportService.exportFolderExists(exportFolder)) {
if (!(await exportService.exportFolderExists(exportFolder))) {
const pendingExports =
await exportService.getPendingExports(null);
setPendingExports(pendingExports);
@ -145,9 +145,9 @@ export default function ExportModal(props: Props) {
}
};
const toggleContinuousExport = () => {
const toggleContinuousExport = async () => {
try {
verifyExportFolderExists();
await verifyExportFolderExists();
const newContinuousExport = !continuousExport;
if (newContinuousExport) {
exportService.enableContinuousExport();
@ -162,7 +162,7 @@ export default function ExportModal(props: Props) {
const startExport = async () => {
try {
verifyExportFolderExists();
await verifyExportFolderExists();
await exportService.scheduleExport();
} catch (e) {
if (e.message !== CustomError.EXPORT_FOLDER_DOES_NOT_EXIST) {

View file

@ -241,7 +241,11 @@ export default function App(props: EnteAppProps) {
}
await DownloadManager.init(APPS.PHOTOS, { token });
const exportSettings = exportService.getExportSettings();
if (!exportService.exportFolderExists(exportSettings?.folder)) {
if (
!(await exportService.exportFolderExists(
exportSettings?.folder,
))
) {
return;
}
const exportRecord = await exportService.getExportRecord(

View file

@ -245,7 +245,7 @@ class ExportService {
};
async preExport(exportFolder: string) {
this.verifyExportFolderExists(exportFolder);
await this.verifyExportFolderExists(exportFolder);
const exportRecord = await this.getExportRecord(exportFolder);
await this.updateExportStage(ExportStage.MIGRATION);
await this.runMigration(
@ -259,7 +259,7 @@ class ExportService {
async postExport() {
try {
const exportFolder = this.getExportSettings()?.folder;
if (!this.exportFolderExists(exportFolder)) {
if (!(await this.exportFolderExists(exportFolder))) {
this.uiUpdater.setExportStage(ExportStage.INIT);
return;
}
@ -484,7 +484,7 @@ class ExportService {
if (isCanceled.status) {
throw Error(CustomError.EXPORT_STOPPED);
}
this.verifyExportFolderExists(exportFolder);
await this.verifyExportFolderExists(exportFolder);
const oldCollectionExportName =
collectionIDExportNameMap.get(collection.id);
const oldCollectionExportPath = getCollectionExportPath(
@ -493,7 +493,7 @@ class ExportService {
);
const newCollectionExportName =
getUniqueCollectionExportName(
await getUniqueCollectionExportName(
exportFolder,
getCollectionUserFacingName(collection),
);
@ -574,7 +574,7 @@ class ExportService {
if (isCanceled.status) {
throw Error(CustomError.EXPORT_STOPPED);
}
this.verifyExportFolderExists(exportFolder);
await this.verifyExportFolderExists(exportFolder);
addLogLine(
`removing collection with id ${collectionID} from export folder`,
);
@ -662,7 +662,7 @@ class ExportService {
throw Error(CustomError.EXPORT_STOPPED);
}
try {
this.verifyExportFolderExists(exportDir);
await this.verifyExportFolderExists(exportDir);
let collectionExportName = collectionIDFolderNameMap.get(
file.collectionID,
);
@ -743,7 +743,7 @@ class ExportService {
exportRecord.fileExportNames,
);
for (const fileUID of removedFileUIDs) {
this.verifyExportFolderExists(exportDir);
await this.verifyExportFolderExists(exportDir);
addLogLine(`trashing file with id ${fileUID}`);
if (isCanceled.status) {
throw Error(CustomError.EXPORT_STOPPED);
@ -769,10 +769,10 @@ class ExportService {
addLogLine(
`moving image file ${imageExportPath} to trash folder`,
);
if (this.exists(imageExportPath)) {
if (await this.exists(imageExportPath)) {
await ElectronAPIs.moveFile(
imageExportPath,
getTrashedFileExportPath(
await getTrashedFileExportPath(
exportDir,
imageExportPath,
),
@ -782,10 +782,12 @@ class ExportService {
const imageMetadataFileExportPath =
getMetadataFileExportPath(imageExportPath);
if (this.exists(imageMetadataFileExportPath)) {
if (
await this.exists(imageMetadataFileExportPath)
) {
await ElectronAPIs.moveFile(
imageMetadataFileExportPath,
getTrashedFileExportPath(
await getTrashedFileExportPath(
exportDir,
imageMetadataFileExportPath,
),
@ -799,10 +801,10 @@ class ExportService {
addLogLine(
`moving video file ${videoExportPath} to trash folder`,
);
if (this.exists(videoExportPath)) {
if (await this.exists(videoExportPath)) {
await ElectronAPIs.moveFile(
videoExportPath,
getTrashedFileExportPath(
await getTrashedFileExportPath(
exportDir,
videoExportPath,
),
@ -810,10 +812,12 @@ class ExportService {
}
const videoMetadataFileExportPath =
getMetadataFileExportPath(videoExportPath);
if (this.exists(videoMetadataFileExportPath)) {
if (
await this.exists(videoMetadataFileExportPath)
) {
await ElectronAPIs.moveFile(
videoMetadataFileExportPath,
getTrashedFileExportPath(
await getTrashedFileExportPath(
exportDir,
videoMetadataFileExportPath,
),
@ -824,14 +828,15 @@ class ExportService {
collectionExportPath,
fileExportName,
);
const trashedFilePath = getTrashedFileExportPath(
exportDir,
fileExportPath,
);
const trashedFilePath =
await getTrashedFileExportPath(
exportDir,
fileExportPath,
);
addLogLine(
`moving file ${fileExportPath} to ${trashedFilePath} trash folder`,
);
if (this.exists(fileExportPath)) {
if (await this.exists(fileExportPath)) {
await ElectronAPIs.moveFile(
fileExportPath,
trashedFilePath,
@ -839,10 +844,10 @@ class ExportService {
}
const metadataFileExportPath =
getMetadataFileExportPath(fileExportPath);
if (this.exists(metadataFileExportPath)) {
if (await this.exists(metadataFileExportPath)) {
await ElectronAPIs.moveFile(
metadataFileExportPath,
getTrashedFileExportPath(
await getTrashedFileExportPath(
exportDir,
metadataFileExportPath,
),
@ -995,9 +1000,9 @@ class ExportService {
async getExportRecord(folder: string, retry = true): Promise<ExportRecord> {
try {
this.verifyExportFolderExists(folder);
await this.verifyExportFolderExists(folder);
const exportRecordJSONPath = `${folder}/${EXPORT_RECORD_FILE_NAME}`;
if (!this.exists(exportRecordJSONPath)) {
if (!(await this.exists(exportRecordJSONPath))) {
return this.createEmptyExportRecord(exportRecordJSONPath);
}
const recordFile =
@ -1027,9 +1032,9 @@ class ExportService {
collectionID: number,
collectionIDNameMap: Map<number, string>,
) {
this.verifyExportFolderExists(exportFolder);
await this.verifyExportFolderExists(exportFolder);
const collectionName = collectionIDNameMap.get(collectionID);
const collectionExportName = getUniqueCollectionExportName(
const collectionExportName = await getUniqueCollectionExportName(
exportFolder,
collectionName,
);
@ -1070,7 +1075,7 @@ class ExportService {
file,
);
} else {
const fileExportName = getUniqueFileExportName(
const fileExportName = await getUniqueFileExportName(
collectionExportPath,
file.metadata.title,
);
@ -1109,11 +1114,11 @@ class ExportService {
) {
const fileBlob = await new Response(fileStream).blob();
const livePhoto = await decodeLivePhoto(file, fileBlob);
const imageExportName = getUniqueFileExportName(
const imageExportName = await getUniqueFileExportName(
collectionExportPath,
livePhoto.imageNameTitle,
);
const videoExportName = getUniqueFileExportName(
const videoExportName = await getUniqueFileExportName(
collectionExportPath,
livePhoto.videoNameTitle,
);
@ -1177,7 +1182,7 @@ class ExportService {
};
exists = (path: string) => {
return ElectronAPIs.exists(path);
return ElectronAPIs.fs.exists(path);
};
rename = (oldPath: string, newPath: string) => {
@ -1188,13 +1193,13 @@ class ExportService {
return ElectronAPIs.checkExistsAndCreateDir(path);
};
exportFolderExists = (exportFolder: string) => {
return exportFolder && this.exists(exportFolder);
exportFolderExists = async (exportFolder: string) => {
return exportFolder && (await this.exists(exportFolder));
};
private verifyExportFolderExists = (exportFolder: string) => {
private verifyExportFolderExists = async (exportFolder: string) => {
try {
if (!this.exportFolderExists(exportFolder)) {
if (!(await this.exportFolderExists(exportFolder))) {
throw Error(CustomError.EXPORT_FOLDER_DOES_NOT_EXIST);
}
} catch (e) {

View file

@ -195,7 +195,7 @@ async function migrationV4ToV5(exportDir: string, exportRecord: ExportRecord) {
}
/*
This updates the folder name of already exported folders from the earlier format of
This updates the folder name of already exported folders from the earlier format of
`collectionID_collectionName` to newer `collectionName(numbered)` format
*/
async function migrateCollectionFolders(
@ -209,12 +209,12 @@ async function migrateCollectionFolders(
collection.id,
collection.name,
);
const newCollectionExportPath = getUniqueCollectionFolderPath(
const newCollectionExportPath = await getUniqueCollectionFolderPath(
exportDir,
collection.name,
);
collectionIDPathMap.set(collection.id, newCollectionExportPath);
if (!exportService.exists(oldCollectionExportPath)) {
if (!(await exportService.exists(oldCollectionExportPath))) {
continue;
}
await exportService.rename(
@ -230,7 +230,7 @@ async function migrateCollectionFolders(
}
/*
This updates the file name of already exported files from the earlier format of
This updates the file name of already exported files from the earlier format of
`fileID_fileName` to newer `fileName(numbered)` format
*/
async function migrateFiles(
@ -246,7 +246,7 @@ async function migrateFiles(
collectionIDPathMap.get(file.collectionID),
file,
);
const newFileSaveName = getUniqueFileSaveName(
const newFileSaveName = await getUniqueFileSaveName(
collectionIDPathMap.get(file.collectionID),
file.metadata.title,
);
@ -260,7 +260,7 @@ async function migrateFiles(
collectionIDPathMap.get(file.collectionID),
newFileSaveName,
);
if (!exportService.exists(oldFileSavePath)) {
if (!(await exportService.exists(oldFileSavePath))) {
continue;
}
await exportService.rename(oldFileSavePath, newFileSavePath);
@ -306,7 +306,7 @@ async function getCollectionExportNamesFromExportedCollectionPaths(
return exportedCollectionNames;
}
/*
/*
Earlier the file were sorted by id,
which we can use to determine which file got which number suffix
this can be used to determine the filepaths of the those already exported files
@ -432,17 +432,27 @@ async function removeCollectionExportMissingMetadataFolder(
return;
}
const properlyExportedCollections = Object.entries(
const properlyExportedCollectionsAll = Object.entries(
exportRecord.collectionExportNames,
)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
.filter(([_, collectionExportName]) =>
exportService.exists(
);
const properlyExportedCollections = [];
for (const [
collectionID,
collectionExportName,
] of properlyExportedCollectionsAll) {
if (
await exportService.exists(
getMetadataFolderExportPath(
getCollectionExportPath(exportDir, collectionExportName),
),
),
);
)
) {
properlyExportedCollections.push([
collectionID,
collectionExportName,
]);
}
}
const properlyExportedCollectionIDs = properlyExportedCollections.map(
([collectionID]) => collectionID,

View file

@ -1,8 +1,8 @@
import { addLogLine } from "@ente/shared/logging";
import { logError } from "@ente/shared/sentry";
import QueueProcessor from "@ente/shared/utils/queueProcessor";
import { generateTempName } from "@ente/shared/utils/temp";
import { createFFmpeg, FFmpeg } from "ffmpeg-wasm";
import QueueProcessor from "@ente/shared/utils/queueProcessor";
import { getUint8ArrayView } from "services/readerService";
import { promiseWithTimeout } from "utils/common";

View file

@ -174,7 +174,7 @@ async function createCollectionDownloadFolder(
downloadDirPath: string,
collectionName: string,
) {
const collectionDownloadName = getUniqueCollectionExportName(
const collectionDownloadName = await getUniqueCollectionExportName(
downloadDirPath,
collectionName,
);

View file

@ -197,16 +197,16 @@ export const getGoogleLikeMetadataFile = (
export const sanitizeName = (name: string) =>
sanitize(name, { replacement: "_" });
export const getUniqueCollectionExportName = (
export const getUniqueCollectionExportName = async (
dir: string,
collectionName: string,
): string => {
): Promise<string> => {
let collectionExportName = sanitizeName(collectionName);
let count = 1;
while (
exportService.exists(
(await exportService.exists(
getCollectionExportPath(dir, collectionExportName),
) ||
)) ||
collectionExportName === ENTE_TRASH_FOLDER
) {
collectionExportName = `${sanitizeName(collectionName)}(${count})`;
@ -218,14 +218,14 @@ export const getUniqueCollectionExportName = (
export const getMetadataFolderExportPath = (collectionExportPath: string) =>
`${collectionExportPath}/${ENTE_METADATA_FOLDER}`;
export const getUniqueFileExportName = (
export const getUniqueFileExportName = async (
collectionExportPath: string,
filename: string,
) => {
let fileExportName = sanitizeName(filename);
let count = 1;
while (
exportService.exists(
await exportService.exists(
getFileExportPath(collectionExportPath, fileExportName),
)
) {
@ -255,11 +255,14 @@ export const getFileExportPath = (
fileExportName: string,
) => `${collectionExportPath}/${fileExportName}`;
export const getTrashedFileExportPath = (exportDir: string, path: string) => {
export const getTrashedFileExportPath = async (
exportDir: string,
path: string,
) => {
const fileRelativePath = path.replace(`${exportDir}/`, "");
let trashedFilePath = `${exportDir}/${ENTE_TRASH_FOLDER}/${fileRelativePath}`;
let count = 1;
while (exportService.exists(trashedFilePath)) {
while (await exportService.exists(trashedFilePath)) {
const trashedFilePathParts = splitFilenameAndExtension(trashedFilePath);
if (trashedFilePathParts[1]) {
trashedFilePath = `${trashedFilePathParts[0]}(${count}).${trashedFilePathParts[1]}`;

View file

@ -41,13 +41,13 @@ export const getExportedFiles = (
export const oldSanitizeName = (name: string) =>
name.replaceAll("/", "_").replaceAll(" ", "_");
export const getUniqueCollectionFolderPath = (
export const getUniqueCollectionFolderPath = async (
dir: string,
collectionName: string,
): string => {
): Promise<string> => {
let collectionFolderPath = `${dir}/${sanitizeName(collectionName)}`;
let count = 1;
while (exportService.exists(collectionFolderPath)) {
while (await exportService.exists(collectionFolderPath)) {
collectionFolderPath = `${dir}/${sanitizeName(
collectionName,
)}(${count})`;
@ -59,14 +59,16 @@ export const getUniqueCollectionFolderPath = (
export const getMetadataFolderPath = (collectionFolderPath: string) =>
`${collectionFolderPath}/${ENTE_METADATA_FOLDER}`;
export const getUniqueFileSaveName = (
export const getUniqueFileSaveName = async (
collectionPath: string,
filename: string,
) => {
let fileSaveName = sanitizeName(filename);
let count = 1;
while (
exportService.exists(getFileSavePath(collectionPath, fileSaveName))
await exportService.exists(
getFileSavePath(collectionPath, fileSaveName),
)
) {
const filenameParts = splitFilenameAndExtension(sanitizeName(filename));
if (filenameParts[1]) {

View file

@ -778,7 +778,7 @@ export async function downloadFileDesktop(
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
const fileBlob = await new Response(updatedFileStream).blob();
const livePhoto = await decodeLivePhoto(file, fileBlob);
const imageExportName = getUniqueFileExportName(
const imageExportName = await getUniqueFileExportName(
downloadPath,
livePhoto.imageNameTitle,
);
@ -788,7 +788,7 @@ export async function downloadFileDesktop(
imageStream,
);
try {
const videoExportName = getUniqueFileExportName(
const videoExportName = await getUniqueFileExportName(
downloadPath,
livePhoto.videoNameTitle,
);
@ -804,7 +804,7 @@ export async function downloadFileDesktop(
throw e;
}
} else {
const fileExportName = getUniqueFileExportName(
const fileExportName = await getUniqueFileExportName(
downloadPath,
file.metadata.title,
);

View file

@ -79,7 +79,6 @@ export interface ElectronAPIsType {
};
/** TODO: AUDIT below this */
exists: (path: string) => boolean;
checkExistsAndCreateDir: (dirPath: string) => Promise<void>;
saveStreamToDisk: (
path: string,