[photos-desktop] Disable node integration - Part x/x (#1181)

Continuing in the series of refactorings, working towards disabling node
integration in the photos desktop app.
This commit is contained in:
Manav Rathi 2024-03-22 21:06:01 +05:30 committed by GitHub
commit 2de4e51c7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 46 additions and 358 deletions

View file

@ -28,7 +28,7 @@ Install dependencies
yarn install
```
Run in development mode (with hot reload)
Run in development mode (supports hot reload for the renderer process)
```sh
yarn dev

View file

@ -4,14 +4,16 @@
### yarn dev
Launch the app in development mode
Launch the app in development mode:
- Runs a development server for the renderer, with HMR.
- Transpiles the files in `src/` and starts the main process.
- Runs a development server for the renderer (with hot module reload).
- Starts tsc in watch mode to recompile the JS files used by the main process.
- Starts the main process, reloading it on changes to the the TS files in
`src/`.
Note that the main process is not restarted on changes automatically, you'll
still need to restart the app manually  running tsc in watch mode is still
useful to notice any errors.
### yarn build

View file

@ -357,7 +357,7 @@ export async function computeONNXTextEmbedding(
}
async function getRGBData(inputFilePath: string) {
const jpegData = await readFile(inputFilePath);
const jpegData = await fs.readFile(inputFilePath);
let rawImageData;
try {
rawImageData = jpeg.decode(jpegData, {

View file

@ -25,16 +25,14 @@ export const getDirFilePaths = async (dirPath: string) => {
return files;
};
export const getFileStream = async (filePath: string) => {
const getFileStream = async (filePath: string) => {
const file = await fs.open(filePath, "r");
let offset = 0;
const readableStream = new ReadableStream<Uint8Array>({
async pull(controller) {
try {
const buff = new Uint8Array(FILE_STREAM_CHUNK_SIZE);
// original types were not working correctly
const bytesRead = (await fs.read(
file,
const bytesRead = (await file.read(
buff,
0,
FILE_STREAM_CHUNK_SIZE,
@ -43,16 +41,16 @@ export const getFileStream = async (filePath: string) => {
offset += bytesRead;
if (bytesRead === 0) {
controller.close();
await fs.close(file);
await file.close();
} else {
controller.enqueue(buff.slice(0, bytesRead));
}
} catch (e) {
await fs.close(file);
await file.close();
}
},
async cancel() {
await fs.close(file);
await file.close();
},
});
return readableStream;

View file

@ -56,38 +56,3 @@ async function* fileChunkReaderMaker(file: File, chunkSize: number) {
}
return null;
}
// depreciated
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function getUint8ArrayViewOld(
reader: FileReader,
file: Blob,
): Promise<Uint8Array> {
return await new Promise((resolve, reject) => {
reader.onabort = () =>
reject(
Error(
`file reading was aborted, file size= ${convertBytesToHumanReadable(
file.size,
)}`,
),
);
reader.onerror = () =>
reject(
Error(
`file reading has failed, file size= ${convertBytesToHumanReadable(
file.size,
)} , reason= ${reader.error}`,
),
);
reader.onload = () => {
// Do whatever you want with the file contents
const result =
typeof reader.result === "string"
? new TextEncoder().encode(reader.result)
: new Uint8Array(reader.result);
resolve(result);
};
reader.readAsArrayBuffer(file);
});
}

View file

@ -1,11 +1,11 @@
import { CustomError } from "@ente/shared/error";
import { addLogLine } from "@ente/shared/logging";
import { retryAsyncFunction } from "@ente/shared/promise";
import { logError } from "@ente/shared/sentry";
import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
import QueueProcessor from "services/queueProcessor";
import { getDedicatedConvertWorker } from "utils/comlink/ComlinkConvertWorker";
import { ComlinkWorker } from "utils/comlink/comlinkWorker";
import { retryAsyncFunction } from "utils/network";
import { DedicatedConvertWorker } from "worker/convert.worker";
const WORKER_POOL_SIZE = 2;

View file

@ -1,28 +0,0 @@
import { sleep } from "@ente/shared/sleep";
const waitTimeBeforeNextAttemptInMilliSeconds = [2000, 5000, 10000];
export async function retryAsyncFunction<T>(
request: (abort?: () => void) => Promise<T>,
waitTimeBeforeNextTry?: number[],
): Promise<T> {
if (!waitTimeBeforeNextTry) {
waitTimeBeforeNextTry = waitTimeBeforeNextAttemptInMilliSeconds;
}
for (
let attemptNumber = 0;
attemptNumber <= waitTimeBeforeNextTry.length;
attemptNumber++
) {
try {
const resp = await request();
return resp;
} catch (e) {
if (attemptNumber === waitTimeBeforeNextTry.length) {
throw e;
}
await sleep(waitTimeBeforeNextTry[attemptNumber]);
}
}
}

View file

@ -1,78 +0,0 @@
import i18n, { t } from "i18next";
const dateTimeFullFormatter1 = new Intl.DateTimeFormat(i18n.language, {
weekday: "short",
month: "short",
day: "numeric",
});
const dateTimeFullFormatter2 = new Intl.DateTimeFormat(i18n.language, {
year: "numeric",
});
const dateTimeShortFormatter = new Intl.DateTimeFormat(i18n.language, {
month: "short",
day: "numeric",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
const timeFormatter = new Intl.DateTimeFormat(i18n.language, {
timeStyle: "short",
});
export function formatDateFull(date: number | Date) {
return [dateTimeFullFormatter1, dateTimeFullFormatter2]
.map((f) => f.format(date))
.join(" ");
}
export function formatDate(date: number | Date) {
const withinYear =
new Date().getFullYear() === new Date(date).getFullYear();
const dateTimeFormat2 = !withinYear ? dateTimeFullFormatter2 : null;
return [dateTimeFullFormatter1, dateTimeFormat2]
.filter((f) => !!f)
.map((f) => f.format(date))
.join(" ");
}
export function formatDateTimeShort(date: number | Date) {
return dateTimeShortFormatter.format(date);
}
export function formatTime(date: number | Date) {
return timeFormatter.format(date).toUpperCase();
}
export function formatDateTimeFull(dateTime: number | Date): string {
return [formatDateFull(dateTime), t("at"), formatTime(dateTime)].join(" ");
}
export function formatDateTime(dateTime: number | Date): string {
return [formatDate(dateTime), t("at"), formatTime(dateTime)].join(" ");
}
export function formatDateRelative(date: number) {
const units = {
year: 24 * 60 * 60 * 1000 * 365,
month: (24 * 60 * 60 * 1000 * 365) / 12,
day: 24 * 60 * 60 * 1000,
hour: 60 * 60 * 1000,
minute: 60 * 1000,
second: 1000,
};
const relativeDateFormat = new Intl.RelativeTimeFormat(i18n.language, {
localeMatcher: "best fit",
numeric: "always",
style: "long",
});
const elapsed = date - Date.now(); // "Math.abs" accounts for both "past" & "future" scenarios
for (const u in units)
if (Math.abs(elapsed) > units[u] || u === "second")
return relativeDateFormat.format(
Math.round(elapsed / units[u]),
u as Intl.RelativeTimeFormatUnit,
);
}

View file

@ -1,136 +0,0 @@
export interface TimeDelta {
hours?: number;
days?: number;
months?: number;
years?: number;
}
interface DateComponent<T = number> {
year: T;
month: T;
day: T;
hour: T;
minute: T;
second: T;
}
export function validateAndGetCreationUnixTimeInMicroSeconds(dateTime: Date) {
if (!dateTime || isNaN(dateTime.getTime())) {
return null;
}
const unixTime = dateTime.getTime() * 1000;
//ignoring dateTimeString = "0000:00:00 00:00:00"
if (unixTime === Date.UTC(0, 0, 0, 0, 0, 0, 0) || unixTime === 0) {
return null;
} else if (unixTime > Date.now() * 1000) {
return null;
} else {
return unixTime;
}
}
/*
generates data component for date in format YYYYMMDD-HHMMSS
*/
export function parseDateFromFusedDateString(dateTime: string) {
const dateComponent: DateComponent<number> = convertDateComponentToNumber({
year: dateTime.slice(0, 4),
month: dateTime.slice(4, 6),
day: dateTime.slice(6, 8),
hour: dateTime.slice(9, 11),
minute: dateTime.slice(11, 13),
second: dateTime.slice(13, 15),
});
return validateAndGetDateFromComponents(dateComponent);
}
/* sample date format = 2018-08-19 12:34:45
the date has six symbol separated number values
which we would extract and use to form the date
*/
export function tryToParseDateTime(dateTime: string): Date {
const dateComponent = getDateComponentsFromSymbolJoinedString(dateTime);
if (dateComponent.year?.length === 8 && dateComponent.month?.length === 6) {
// the filename has size 8 consecutive and then 6 consecutive digits
// high possibility that the it is a date in format YYYYMMDD-HHMMSS
const possibleDateTime = dateComponent.year + "-" + dateComponent.month;
return parseDateFromFusedDateString(possibleDateTime);
}
return validateAndGetDateFromComponents(
convertDateComponentToNumber(dateComponent),
);
}
function getDateComponentsFromSymbolJoinedString(
dateTime: string,
): DateComponent<string> {
const [year, month, day, hour, minute, second] =
dateTime.match(/\d+/g) ?? [];
return { year, month, day, hour, minute, second };
}
function validateAndGetDateFromComponents(
dateComponent: DateComponent<number>,
) {
let date = getDateFromComponents(dateComponent);
if (hasTimeValues(dateComponent) && !isTimePartValid(date, dateComponent)) {
// if the date has time values but they are not valid
// then we remove the time values and try to validate the date
date = getDateFromComponents(removeTimeValues(dateComponent));
}
if (!isDatePartValid(date, dateComponent)) {
return null;
}
return date;
}
function isTimePartValid(date: Date, dateComponent: DateComponent<number>) {
return (
date.getHours() === dateComponent.hour &&
date.getMinutes() === dateComponent.minute &&
date.getSeconds() === dateComponent.second
);
}
function isDatePartValid(date: Date, dateComponent: DateComponent<number>) {
return (
date.getFullYear() === dateComponent.year &&
date.getMonth() === dateComponent.month &&
date.getDate() === dateComponent.day
);
}
function convertDateComponentToNumber(
dateComponent: DateComponent<string>,
): DateComponent<number> {
return {
year: Number(dateComponent.year),
// https://stackoverflow.com/questions/2552483/why-does-the-month-argument-range-from-0-to-11-in-javascripts-date-constructor
month: Number(dateComponent.month) - 1,
day: Number(dateComponent.day),
hour: Number(dateComponent.hour),
minute: Number(dateComponent.minute),
second: Number(dateComponent.second),
};
}
function getDateFromComponents(dateComponent: DateComponent<number>) {
const { year, month, day, hour, minute, second } = dateComponent;
if (hasTimeValues(dateComponent)) {
return new Date(year, month, day, hour, minute, second);
} else {
return new Date(year, month, day);
}
}
function hasTimeValues(dateComponent: DateComponent<number>) {
const { hour, minute, second } = dateComponent;
return !isNaN(hour) && !isNaN(minute) && !isNaN(second);
}
function removeTimeValues(
dateComponent: DateComponent<number>,
): DateComponent<number> {
return { ...dateComponent, hour: 0, minute: 0, second: 0 };
}

View file

@ -1,9 +1,9 @@
import { CustomError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService";
import { getFileURL, getThumbnailURL } from "@ente/shared/network/api";
import { retryAsyncFunction } from "@ente/shared/promise";
import { DownloadClient } from "services/download";
import { EnteFile } from "types/file";
import { retryAsyncFunction } from "utils/network";
export class PhotosDownloadClient implements DownloadClient {
constructor(

View file

@ -4,9 +4,9 @@ import {
getPublicCollectionFileURL,
getPublicCollectionThumbnailURL,
} from "@ente/shared/network/api";
import { retryAsyncFunction } from "@ente/shared/promise";
import { DownloadClient } from "services/download";
import { EnteFile } from "types/file";
import { retryAsyncFunction } from "utils/network";
export class PublicAlbumsDownloadClient implements DownloadClient {
constructor(

View file

@ -56,38 +56,3 @@ async function* fileChunkReaderMaker(file: File, chunkSize: number) {
}
return null;
}
// depreciated
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function getUint8ArrayViewOld(
reader: FileReader,
file: Blob,
): Promise<Uint8Array> {
return await new Promise((resolve, reject) => {
reader.onabort = () =>
reject(
Error(
`file reading was aborted, file size= ${convertBytesToHumanReadable(
file.size,
)}`,
),
);
reader.onerror = () =>
reject(
Error(
`file reading has failed, file size= ${convertBytesToHumanReadable(
file.size,
)} , reason= ${reader.error}`,
),
);
reader.onload = () => {
// Do whatever you want with the file contents
const result =
typeof reader.result === "string"
? new TextEncoder().encode(reader.result)
: new Uint8Array(reader.result);
resolve(result);
};
reader.readAsArrayBuffer(file);
});
}

View file

@ -1,11 +1,11 @@
import { CustomError } from "@ente/shared/error";
import { addLogLine } from "@ente/shared/logging";
import { retryAsyncFunction } from "@ente/shared/promise";
import { logError } from "@ente/shared/sentry";
import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
import { ComlinkWorker } from "@ente/shared/worker/comlinkWorker";
import QueueProcessor from "services/queueProcessor";
import { getDedicatedConvertWorker } from "utils/comlink/ComlinkConvertWorker";
import { retryAsyncFunction } from "utils/network";
import { DedicatedConvertWorker } from "worker/convert.worker";
const WORKER_POOL_SIZE = 2;

View file

@ -1,28 +0,0 @@
import { sleep } from "utils/common";
const waitTimeBeforeNextAttemptInMilliSeconds = [2000, 5000, 10000];
export async function retryAsyncFunction<T>(
request: (abort?: () => void) => Promise<T>,
waitTimeBeforeNextTry?: number[],
): Promise<T> {
if (!waitTimeBeforeNextTry) {
waitTimeBeforeNextTry = waitTimeBeforeNextAttemptInMilliSeconds;
}
for (
let attemptNumber = 0;
attemptNumber <= waitTimeBeforeNextTry.length;
attemptNumber++
) {
try {
const resp = await request();
return resp;
} catch (e) {
if (attemptNumber === waitTimeBeforeNextTry.length) {
throw e;
}
await sleep(waitTimeBeforeNextTry[attemptNumber]);
}
}
}

View file

@ -1,5 +1,33 @@
import { sleep } from "@ente/shared/sleep";
import { CustomError } from "../error";
const waitTimeBeforeNextAttemptInMilliSeconds = [2000, 5000, 10000];
export async function retryAsyncFunction<T>(
request: (abort?: () => void) => Promise<T>,
waitTimeBeforeNextTry?: number[],
): Promise<T> {
if (!waitTimeBeforeNextTry) {
waitTimeBeforeNextTry = waitTimeBeforeNextAttemptInMilliSeconds;
}
for (
let attemptNumber = 0;
attemptNumber <= waitTimeBeforeNextTry.length;
attemptNumber++
) {
try {
const resp = await request();
return resp;
} catch (e) {
if (attemptNumber === waitTimeBeforeNextTry.length) {
throw e;
}
await sleep(waitTimeBeforeNextTry[attemptNumber]);
}
}
}
export const promiseWithTimeout = async <T>(
request: Promise<T>,
timeout: number,