Wrap the assertion

This commit is contained in:
Manav Rathi 2024-04-09 12:30:01 +05:30
parent c729516faf
commit 4aa3d68e36
No known key found for this signature in database
9 changed files with 94 additions and 88 deletions

View file

@ -1,4 +1,4 @@
import ElectronAPIs from "@/next/electron";
import { ensureElectron } from "@/next/electron";
import log from "@/next/log";
import LinkButton from "@ente/shared/components/LinkButton";
import { Tooltip } from "@mui/material";
@ -19,7 +19,7 @@ const DirectoryPathContainer = styled(LinkButton)(
export const DirectoryPath = ({ width, path }) => {
const handleClick = async () => {
try {
await ElectronAPIs.openDirectory(path);
await ensureElectron().openDirectory(path);
} catch (e) {
log.error("openDirectory failed", e);
}

View file

@ -1,4 +1,4 @@
import ElectronAPIs from "@/next/electron";
import { ensureElectron } from "@/next/electron";
import log from "@/next/log";
import ComlinkCryptoWorker from "@ente/shared/crypto";
import { CustomError } from "@ente/shared/error";
@ -157,7 +157,7 @@ class ClipServiceImpl {
model: Model = Model.ONNX_CLIP,
): Promise<Float32Array> => {
try {
return ElectronAPIs.computeTextEmbedding(model, text);
return ensureElectron().computeTextEmbedding(model, text);
} catch (e) {
if (e?.message?.includes(CustomError.UNSUPPORTED_PLATFORM)) {
this.unsupportedPlatform = true;
@ -304,7 +304,10 @@ class ClipServiceImpl {
const file = await localFile
.arrayBuffer()
.then((buffer) => new Uint8Array(buffer));
const embedding = await ElectronAPIs.computeImageEmbedding(model, file);
const embedding = await ensureElectron().computeImageEmbedding(
model,
file,
);
return embedding;
};
@ -344,7 +347,7 @@ class ClipServiceImpl {
file: EnteFile,
) => {
const thumb = await downloadManager.getThumbnail(file);
const embedding = await ElectronAPIs.computeImageEmbedding(
const embedding = await ensureElectron().computeImageEmbedding(
model,
thumb,
);

View file

@ -57,7 +57,6 @@ import downloadManager from "../download";
import { getAllLocalFiles } from "../fileService";
import { decodeLivePhoto } from "../livePhotoService";
import { migrateExport } from "./migration";
import type { Electron } from "@/next/types/ipc";
const EXPORT_RECORD_FILE_NAME = "export_status.json";
@ -71,15 +70,6 @@ export const NULL_EXPORT_RECORD: ExportRecord = {
collectionExportNames: {},
};
const electron = (): Electron => {
const et = globalThis.electron;
if (!et)
throw new Error(
"Attempting to use ExportService in an unsupported non-electron context",
);
return et;
};
class ExportService {
private exportSettings: ExportSettings;
private exportInProgress: RequestCanceller = null;
@ -166,12 +156,12 @@ class ExportService {
async changeExportDirectory() {
try {
const newRootDir = await electron().selectDirectory();
const newRootDir = await ensureElectron().selectDirectory();
if (!newRootDir) {
throw Error(CustomError.SELECT_FOLDER_ABORTED);
}
const newExportDir = `${newRootDir}/${ENTE_EXPORT_DIRECTORY}`;
await electron().checkExistsAndCreateDir(newExportDir);
await ensureElectron().checkExistsAndCreateDir(newExportDir);
return newExportDir;
} catch (e) {
if (e.message !== CustomError.SELECT_FOLDER_ABORTED) {
@ -521,7 +511,7 @@ class ExportService {
newCollectionExportName,
);
try {
await electron().rename(
await ensureElectron().rename(
oldCollectionExportPath,
newCollectionExportPath,
);
@ -606,11 +596,13 @@ class ExportService {
);
try {
// delete the collection metadata folder
await electron().deleteFolder(
await ensureElectron().deleteFolder(
getMetadataFolderExportPath(collectionExportPath),
);
// delete the collection folder
await electron().deleteFolder(collectionExportPath);
await ensureElectron().deleteFolder(
collectionExportPath,
);
} catch (e) {
await this.addCollectionExportedRecord(
exportFolder,
@ -693,10 +685,10 @@ class ExportService {
exportDir,
collectionExportName,
);
await electron().checkExistsAndCreateDir(
await ensureElectron().checkExistsAndCreateDir(
collectionExportPath,
);
await electron().checkExistsAndCreateDir(
await ensureElectron().checkExistsAndCreateDir(
getMetadataFolderExportPath(collectionExportPath),
);
await this.downloadAndSave(
@ -776,7 +768,7 @@ class ExportService {
`moving image file ${imageExportPath} to trash folder`,
);
if (await this.exists(imageExportPath)) {
await electron().moveFile(
await ensureElectron().moveFile(
imageExportPath,
await getTrashedFileExportPath(
exportDir,
@ -791,7 +783,7 @@ class ExportService {
if (
await this.exists(imageMetadataFileExportPath)
) {
await electron().moveFile(
await ensureElectron().moveFile(
imageMetadataFileExportPath,
await getTrashedFileExportPath(
exportDir,
@ -808,7 +800,7 @@ class ExportService {
`moving video file ${videoExportPath} to trash folder`,
);
if (await this.exists(videoExportPath)) {
await electron().moveFile(
await ensureElectron().moveFile(
videoExportPath,
await getTrashedFileExportPath(
exportDir,
@ -821,7 +813,7 @@ class ExportService {
if (
await this.exists(videoMetadataFileExportPath)
) {
await electron().moveFile(
await ensureElectron().moveFile(
videoMetadataFileExportPath,
await getTrashedFileExportPath(
exportDir,
@ -843,7 +835,7 @@ class ExportService {
`moving file ${fileExportPath} to ${trashedFilePath} trash folder`,
);
if (await this.exists(fileExportPath)) {
await electron().moveFile(
await ensureElectron().moveFile(
fileExportPath,
trashedFilePath,
);
@ -851,7 +843,7 @@ class ExportService {
const metadataFileExportPath =
getMetadataFileExportPath(fileExportPath);
if (await this.exists(metadataFileExportPath)) {
await electron().moveFile(
await ensureElectron().moveFile(
metadataFileExportPath,
await getTrashedFileExportPath(
exportDir,
@ -990,7 +982,7 @@ class ExportService {
try {
const exportRecord = await this.getExportRecord(folder);
const newRecord: ExportRecord = { ...exportRecord, ...newData };
await electron().saveFileToDisk(
await ensureElectron().saveFileToDisk(
`${folder}/${EXPORT_RECORD_FILE_NAME}`,
JSON.stringify(newRecord, null, 2),
);
@ -1012,7 +1004,7 @@ class ExportService {
return this.createEmptyExportRecord(exportRecordJSONPath);
}
const recordFile =
await electron().readTextFile(exportRecordJSONPath);
await ensureElectron().readTextFile(exportRecordJSONPath);
try {
return JSON.parse(recordFile);
} catch (e) {
@ -1048,8 +1040,8 @@ class ExportService {
exportFolder,
collectionExportName,
);
await electron().checkExistsAndCreateDir(collectionExportPath);
await electron().checkExistsAndCreateDir(
await ensureElectron().checkExistsAndCreateDir(collectionExportPath);
await ensureElectron().checkExistsAndCreateDir(
getMetadataFolderExportPath(collectionExportPath),
);
@ -1096,7 +1088,7 @@ class ExportService {
fileExportName,
file,
);
await electron().saveStreamToDisk(
await ensureElectron().saveStreamToDisk(
getFileExportPath(collectionExportPath, fileExportName),
updatedFileStream,
);
@ -1144,7 +1136,7 @@ class ExportService {
imageExportName,
file,
);
await electron().saveStreamToDisk(
await ensureElectron().saveStreamToDisk(
getFileExportPath(collectionExportPath, imageExportName),
imageStream,
);
@ -1156,12 +1148,12 @@ class ExportService {
file,
);
try {
await electron().saveStreamToDisk(
await ensureElectron().saveStreamToDisk(
getFileExportPath(collectionExportPath, videoExportName),
videoStream,
);
} catch (e) {
await electron().deleteFile(
await ensureElectron().deleteFile(
getFileExportPath(collectionExportPath, imageExportName),
);
throw e;
@ -1177,7 +1169,7 @@ class ExportService {
fileExportName: string,
file: EnteFile,
) {
await electron().saveFileToDisk(
await ensureElectron().saveFileToDisk(
getFileMetadataExportPath(collectionExportPath, fileExportName),
getGoogleLikeMetadataFile(fileExportName, file),
);
@ -1188,15 +1180,15 @@ class ExportService {
};
exists = (path: string) => {
return electron().fs.exists(path);
return ensureElectron().fs.exists(path);
};
rename = (oldPath: string, newPath: string) => {
return electron().rename(oldPath, newPath);
return ensureElectron().rename(oldPath, newPath);
};
checkExistsAndCreateDir = (path: string) => {
return electron().checkExistsAndCreateDir(path);
return ensureElectron().checkExistsAndCreateDir(path);
};
exportFolderExists = async (exportFolder: string) => {
@ -1218,7 +1210,7 @@ class ExportService {
private createEmptyExportRecord = async (exportRecordJSONPath: string) => {
const exportRecord: ExportRecord = NULL_EXPORT_RECORD;
await electron().saveFileToDisk(
await ensureElectron().saveFileToDisk(
exportRecordJSONPath,
JSON.stringify(exportRecord, null, 2),
);

View file

@ -1,5 +1,5 @@
import { ensureElectron } from "@/next/electron";
import log from "@/next/log";
import type { Electron } from "@/next/types/ipc";
import { PICKED_UPLOAD_TYPE } from "constants/upload";
import { Collection } from "types/collection";
import { ElectronFile, FileWithCollection } from "types/upload";
@ -10,20 +10,11 @@ interface PendingUploads {
type: PICKED_UPLOAD_TYPE;
}
const electron = (): Electron => {
const et = globalThis.electron;
if (!et)
throw new Error(
"Attempting to use ExportService in an unsupported non-electron context",
);
return et;
};
class ImportService {
async getPendingUploads(): Promise<PendingUploads> {
try {
const pendingUploads =
(await electron().getPendingUploads()) as PendingUploads;
(await ensureElectron().getPendingUploads()) as PendingUploads;
return pendingUploads;
} catch (e) {
if (e?.message?.includes("ENOENT: no such file or directory")) {
@ -49,7 +40,7 @@ class ImportService {
if (collections.length === 1) {
collectionName = collections[0].name;
}
await electron().setToUploadCollection(collectionName);
await ensureElectron().setToUploadCollection(collectionName);
}
async updatePendingUploads(files: FileWithCollection[]) {
@ -66,13 +57,17 @@ class ImportService {
filePaths.push((fileWithCollection.file as ElectronFile).path);
}
}
await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, filePaths);
await ensureElectron().setToUploadFiles(
PICKED_UPLOAD_TYPE.FILES,
filePaths,
);
}
async cancelRemainingUploads() {
await electron().setToUploadCollection(null);
await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.ZIPS, []);
await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, []);
const electron = ensureElectron();
await electron.setToUploadCollection(null);
await electron.setToUploadFiles(PICKED_UPLOAD_TYPE.ZIPS, []);
await electron.setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, []);
}
}

View file

@ -1,4 +1,4 @@
import ElectronAPIs from "@/next/electron";
import { ensureElectron } from "@/next/electron";
import { convertBytesToHumanReadable, getFileNameSize } from "@/next/file";
import log from "@/next/log";
import { CustomError } from "@ente/shared/error";
@ -98,7 +98,7 @@ const generateImageThumbnailInElectron = async (
): Promise<Uint8Array> => {
try {
const startTime = Date.now();
const thumb = await ElectronAPIs.generateImageThumbnail(
const thumb = await ensureElectron().generateImageThumbnail(
inputFile,
maxDimension,
maxSize,

View file

@ -1,5 +1,5 @@
import { ensureElectron } from "@/next/electron";
import log from "@/next/log";
import type { Electron } from "@/next/types/ipc";
import { UPLOAD_RESULT, UPLOAD_STRATEGY } from "constants/upload";
import debounce from "debounce";
import uploadManager from "services/upload/uploadManager";
@ -22,15 +22,6 @@ import {
diskFolderRemovedCallback,
} from "./watchFolderEventHandlers";
const electron = (): Electron => {
const et = globalThis.electron;
if (!et)
throw new Error(
"Attempting to use ExportService in an unsupported non-electron context",
);
return et;
};
class watchFolderService {
private eventQueue: EventQueueItem[] = [];
private currentEvent: EventQueueItem;
@ -92,7 +83,7 @@ class watchFolderService {
for (const mapping of mappings) {
const filesOnDisk: ElectronFile[] =
await electron().getDirFiles(mapping.folderPath);
await ensureElectron().getDirFiles(mapping.folderPath);
this.uploadDiffOfFiles(mapping, filesOnDisk);
this.trashDiffOfFiles(mapping, filesOnDisk);
@ -159,9 +150,11 @@ class watchFolderService {
): Promise<WatchMapping[]> {
const notDeletedMappings = [];
for (const mapping of mappings) {
const mappingExists = await electron().isFolder(mapping.folderPath);
const mappingExists = await ensureElectron().isFolder(
mapping.folderPath,
);
if (!mappingExists) {
electron().removeWatchMapping(mapping.folderPath);
ensureElectron().removeWatchMapping(mapping.folderPath);
} else {
notDeletedMappings.push(mapping);
}
@ -179,7 +172,7 @@ class watchFolderService {
}
private setupWatcherFunctions() {
electron().registerWatcherFunctions(
ensureElectron().registerWatcherFunctions(
diskFileAddedCallback,
diskFileRemovedCallback,
diskFolderRemovedCallback,
@ -192,7 +185,7 @@ class watchFolderService {
uploadStrategy: UPLOAD_STRATEGY,
) {
try {
await electron().addWatchMapping(
await ensureElectron().addWatchMapping(
rootFolderName,
folderPath,
uploadStrategy,
@ -205,7 +198,7 @@ class watchFolderService {
async removeWatchMapping(folderPath: string) {
try {
await electron().removeWatchMapping(folderPath);
await ensureElectron().removeWatchMapping(folderPath);
} catch (e) {
log.error("error while removing watch mapping", e);
}
@ -213,7 +206,7 @@ class watchFolderService {
async getWatchMappings(): Promise<WatchMapping[]> {
try {
return (await electron().getWatchMappings()) ?? [];
return (await ensureElectron().getWatchMappings()) ?? [];
} catch (e) {
log.error("error while getting watch mappings", e);
return [];
@ -385,7 +378,7 @@ class watchFolderService {
...this.currentlySyncedMapping.syncedFiles,
...syncedFiles,
];
await electron().updateWatchMappingSyncedFiles(
await ensureElectron().updateWatchMappingSyncedFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.syncedFiles,
);
@ -395,7 +388,7 @@ class watchFolderService {
...this.currentlySyncedMapping.ignoredFiles,
...ignoredFiles,
];
await electron().updateWatchMappingIgnoredFiles(
await ensureElectron().updateWatchMappingIgnoredFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.ignoredFiles,
);
@ -510,7 +503,7 @@ class watchFolderService {
this.currentlySyncedMapping.syncedFiles.filter(
(file) => !filePathsToRemove.has(file.path),
);
await electron().updateWatchMappingSyncedFiles(
await ensureElectron().updateWatchMappingSyncedFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.syncedFiles,
);
@ -602,7 +595,7 @@ class watchFolderService {
async selectFolder(): Promise<string> {
try {
const folderPath = await electron().selectDirectory();
const folderPath = await ensureElectron().selectDirectory();
return folderPath;
} catch (e) {
log.error("error while selecting folder", e);
@ -630,7 +623,7 @@ class watchFolderService {
async isFolder(folderPath: string) {
try {
const isFolder = await electron().isFolder(folderPath);
const isFolder = await ensureElectron().isFolder(folderPath);
return isFolder;
} catch (e) {
log.error("error while checking if folder exists", e);

View file

@ -1,4 +1,3 @@
import ElectronAPIs from "@/next/electron";
import log from "@/next/log";
import { CustomError } from "@ente/shared/error";
import { getAlbumsURL } from "@ente/shared/network/api";
@ -17,7 +16,6 @@ import {
SYSTEM_COLLECTION_TYPES,
} from "constants/collection";
import { t } from "i18next";
import isElectron from "is-electron";
import {
addToCollection,
createAlbum,
@ -152,8 +150,9 @@ export async function downloadCollectionFiles(
return;
}
let downloadDirPath: string;
if (isElectron()) {
const selectedDir = await ElectronAPIs.selectDirectory();
const electron = globalThis.electron;
if (electron) {
const selectedDir = await electron.selectDirectory();
if (!selectedDir) {
return;
}

View file

@ -20,3 +20,27 @@ const ElectronAPIs = (globalThis as unknown as any)[
// export const globalElectron = globalThis.electron;
export default ElectronAPIs;
/**
* A wrapper over a non-null assertion of `globalThis.electron`.
*
* This is useful where we have previously verified that the code path in which
* we're running only executes when we're in electron (usually by directly
* checking that `globalThis.electron` is defined somewhere up the chain).
*
* Generally, this should not be required - the check and the use should be
* colocated, or the unwrapped non-null value saved somewhere. But sometimes
* doing so requires code refactoring, so as an escape hatch we provide this
* convenience function.
*
* It will throw if `globalThis.electron` is undefined.
*
* @see `global-electron.d.ts`.
*/
export const ensureElectron = (): Electron => {
const et = globalThis.electron;
if (et) return et;
throw new Error(
"Attempting to assert globalThis.electron in a non-electron context",
);
};

View file

@ -1,4 +1,4 @@
import ElectronAPIs from "@/next/electron";
import { ensureElectron } from "@/next/electron";
import log, { logToDisk } from "@/next/log";
import { expose, wrap, type Remote } from "comlink";
@ -45,7 +45,7 @@ export class ComlinkWorker<T extends new () => InstanceType<T>> {
const workerBridge = {
logToDisk,
convertToJPEG: (inputFileData: Uint8Array, filename: string) =>
ElectronAPIs.convertToJPEG(inputFileData, filename),
ensureElectron().convertToJPEG(inputFileData, filename),
};
export type WorkerBridge = typeof workerBridge;