Dedup
This commit is contained in:
parent
0fdb2fb357
commit
d297465ea6
9 changed files with 32 additions and 274 deletions
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
);
|
||||
}
|
|
@ -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 };
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue