Inner types

This commit is contained in:
Manav Rathi 2024-04-26 10:17:06 +05:30
parent a7f5061eb6
commit 879f3389d1
No known key found for this signature in database
5 changed files with 97 additions and 125 deletions

View file

@ -3,7 +3,7 @@ import { CustomError, handleUploadError } from "@ente/shared/error";
import HTTPService from "@ente/shared/network/HTTPService"; import HTTPService from "@ente/shared/network/HTTPService";
import { getEndpoint } from "@ente/shared/network/api"; import { getEndpoint } from "@ente/shared/network/api";
import { EnteFile } from "types/file"; import { EnteFile } from "types/file";
import { MultipartUploadURLs, UploadFile, UploadURL } from "types/upload"; import { MultipartUploadURLs, UploadFile, UploadURL } from "./uploadService";
import { retryHTTPCall } from "utils/upload/uploadRetrier"; import { retryHTTPCall } from "utils/upload/uploadRetrier";
const ENDPOINT = getEndpoint(); const ENDPOINT = getEndpoint();

View file

@ -4,8 +4,8 @@ import HTTPService from "@ente/shared/network/HTTPService";
import { getEndpoint, getUploadEndpoint } from "@ente/shared/network/api"; import { getEndpoint, getUploadEndpoint } from "@ente/shared/network/api";
import { getToken } from "@ente/shared/storage/localStorage/helpers"; import { getToken } from "@ente/shared/storage/localStorage/helpers";
import { EnteFile } from "types/file"; import { EnteFile } from "types/file";
import { MultipartUploadURLs, UploadFile, UploadURL } from "types/upload";
import { retryHTTPCall } from "utils/upload/uploadRetrier"; import { retryHTTPCall } from "utils/upload/uploadRetrier";
import { MultipartUploadURLs, UploadFile, UploadURL } from "./uploadService";
const ENDPOINT = getEndpoint(); const ENDPOINT = getEndpoint();
const UPLOAD_ENDPOINT = getUploadEndpoint(); const UPLOAD_ENDPOINT = getUploadEndpoint();

View file

@ -47,12 +47,7 @@ import {
tryParseTakeoutMetadataJSON, tryParseTakeoutMetadataJSON,
type ParsedMetadataJSON, type ParsedMetadataJSON,
} from "./takeout"; } from "./takeout";
import UploadService, { import UploadService, { fopSize, getFileName, uploader } from "./uploadService";
assetName,
fopSize,
getFileName,
uploader,
} from "./uploadService";
/** The number of uploads to process in parallel. */ /** The number of uploads to process in parallel. */
const maxConcurrentUploads = 4; const maxConcurrentUploads = 4;
@ -837,24 +832,17 @@ const clusterLivePhotos = async (files: FileWithCollectionIDAndName[]) => {
fileOrPath: g.fileOrPath, fileOrPath: g.fileOrPath,
}; };
if (await areLivePhotoAssets(fa, ga)) { if (await areLivePhotoAssets(fa, ga)) {
const livePhoto = { const [image, video] =
fFileType == FILE_TYPE.IMAGE ? [f, g] : [g, f];
result.push({
localID: f.localID, localID: f.localID,
collectionID: f.collectionID, collectionID: f.collectionID,
fileName: image.fileName,
isLivePhoto: true, isLivePhoto: true,
livePhotoAssets: { livePhotoAssets: {
image: image: image.fileOrPath,
fFileType == FILE_TYPE.IMAGE video: video.fileOrPath,
? f.fileOrPath
: g.fileOrPath,
video:
fFileType == FILE_TYPE.IMAGE
? g.fileOrPath
: f.fileOrPath,
}, },
};
result.push({
...livePhoto,
fileName: assetName(livePhoto),
}); });
index += 2; index += 2;
} else { } else {

View file

@ -8,7 +8,11 @@ import { ElectronFile } from "@/next/types/file";
import { CustomErrorMessage } from "@/next/types/ipc"; import { CustomErrorMessage } from "@/next/types/ipc";
import { ensure } from "@/utils/ensure"; import { ensure } from "@/utils/ensure";
import { DedicatedCryptoWorker } from "@ente/shared/crypto/internal/crypto.worker"; import { DedicatedCryptoWorker } from "@ente/shared/crypto/internal/crypto.worker";
import { EncryptionResult } from "@ente/shared/crypto/types"; import {
B64EncryptionResult,
EncryptionResult,
LocalFileAttributes,
} from "@ente/shared/crypto/types";
import { CustomError, handleUploadError } from "@ente/shared/error"; import { CustomError, handleUploadError } from "@ente/shared/error";
import { isDataStream, type DataStream } from "@ente/shared/utils/data-stream"; import { isDataStream, type DataStream } from "@ente/shared/utils/data-stream";
import { Remote } from "comlink"; import { Remote } from "comlink";
@ -25,24 +29,18 @@ import { parseImageMetadata } from "services/exif";
import * as ffmpeg from "services/ffmpeg"; import * as ffmpeg from "services/ffmpeg";
import { import {
EnteFile, EnteFile,
MetadataFileAttributes,
S3FileAttributes,
type EncryptedEnteFile, type EncryptedEnteFile,
type FilePublicMagicMetadata, type FilePublicMagicMetadata,
type FilePublicMagicMetadataProps, type FilePublicMagicMetadataProps,
} from "types/file"; } from "types/file";
import { EncryptedMagicMetadata } from "types/magicMetadata"; import { EncryptedMagicMetadata } from "types/magicMetadata";
import { import {
BackupedFile,
EncryptedFile,
FileInMemory,
FileWithMetadata,
ParsedExtractedMetadata, ParsedExtractedMetadata,
ProcessedFile,
PublicUploadProps, PublicUploadProps,
UploadAsset, UploadAsset,
UploadFile,
UploadURL,
type LivePhotoAssets2, type LivePhotoAssets2,
type UploadAsset2,
} from "types/upload"; } from "types/upload";
import { import {
getNonEmptyMagicMetadataProps, getNonEmptyMagicMetadataProps,
@ -147,6 +145,68 @@ const uploadService = new UploadService();
export default uploadService; export default uploadService;
/* -- Various intermediate type used during upload -- */
interface UploadAsset2 {
isLivePhoto?: boolean;
fileOrPath?: File | string;
livePhotoAssets?: LivePhotoAssets2;
}
interface FileInMemory {
filedata: Uint8Array | DataStream;
/** The JPEG data of the generated thumbnail */
thumbnail: Uint8Array;
/**
* `true` if this is a fallback (all black) thumbnail we're returning since
* thumbnail generation failed for some reason.
*/
hasStaticThumbnail: boolean;
}
interface FileWithMetadata extends Omit<FileInMemory, "hasStaticThumbnail"> {
metadata: Metadata;
localID: number;
pubMagicMetadata: FilePublicMagicMetadata;
}
interface EncryptedFile {
file: ProcessedFile;
fileKey: B64EncryptionResult;
}
interface ProcessedFile {
file: LocalFileAttributes<Uint8Array | DataStream>;
thumbnail: LocalFileAttributes<Uint8Array>;
metadata: LocalFileAttributes<string>;
pubMagicMetadata: EncryptedMagicMetadata;
localID: number;
}
export interface BackupedFile {
file: S3FileAttributes;
thumbnail: S3FileAttributes;
metadata: MetadataFileAttributes;
pubMagicMetadata: EncryptedMagicMetadata;
}
export interface UploadFile extends BackupedFile {
collectionID: number;
encryptedKey: string;
keyDecryptionNonce: string;
}
export interface MultipartUploadURLs {
objectKey: string;
partURLs: string[];
completeURL: string;
}
export interface UploadURL {
url: string;
objectKey: string;
}
/** /**
* A function that can be called to obtain a "progressTracker" that then is * A function that can be called to obtain a "progressTracker" that then is
* directly fed to axios to both cancel the upload if needed, and update the * directly fed to axios to both cancel the upload if needed, and update the
@ -165,8 +225,15 @@ interface UploadResponse {
uploadedFile?: EncryptedEnteFile | EnteFile; uploadedFile?: EncryptedEnteFile | EnteFile;
} }
/**
* Upload the given {@link UploadableFile}
*
* This is lower layer implementation of the upload. It is invoked by
* {@link UploadManager} after it has assembled all the relevant bits we need to
* go forth and upload.
*/
export const uploader = async ( export const uploader = async (
fileWithCollection: UploadableFile, { collection, localID, fileName, ...uploadAsset }: UploadableFile,
uploaderName: string, uploaderName: string,
existingFiles: EnteFile[], existingFiles: EnteFile[],
parsedMetadataJSONMap: Map<string, ParsedMetadataJSON>, parsedMetadataJSONMap: Map<string, ParsedMetadataJSON>,
@ -175,10 +242,7 @@ export const uploader = async (
abortIfCancelled: () => void, abortIfCancelled: () => void,
makeProgessTracker: MakeProgressTracker, makeProgessTracker: MakeProgressTracker,
): Promise<UploadResponse> => { ): Promise<UploadResponse> => {
const { collection, localID, ...uploadAsset } = fileWithCollection; log.info(`Uploading ${fileName}`);
const name = assetName(uploadAsset);
log.info(`Uploading ${name}`);
try { try {
/* /*
* We read the file four times: * We read the file four times:
@ -295,11 +359,11 @@ export const uploader = async (
}; };
} catch (e) { } catch (e) {
if (e.message == CustomError.UPLOAD_CANCELLED) { if (e.message == CustomError.UPLOAD_CANCELLED) {
log.info(`Upload for ${name} cancelled`); log.info(`Upload for ${fileName} cancelled`);
} else if (e.message == CustomError.UNSUPPORTED_FILE_FORMAT) { } else if (e.message == CustomError.UNSUPPORTED_FILE_FORMAT) {
log.info(`Not uploading ${name}: unsupported file format`); log.info(`Not uploading ${fileName}: unsupported file format`);
} else { } else {
log.error(`Upload failed for ${name}`, e); log.error(`Upload failed for ${fileName}`, e);
} }
const error = handleUploadError(e); const error = handleUploadError(e);
@ -339,13 +403,6 @@ export const getAssetName = ({
}: UploadAsset) => }: UploadAsset) =>
isLivePhoto ? getFileName(livePhotoAssets.image) : getFileName(file); isLivePhoto ? getFileName(livePhotoAssets.image) : getFileName(file);
export const assetName = ({
isLivePhoto,
file,
livePhotoAssets,
}: UploadAsset2) =>
isLivePhoto ? getFileName(livePhotoAssets.image) : getFileName(file);
/** /**
* Read the given file or path into an in-memory representation. * Read the given file or path into an in-memory representation.
* *
@ -462,11 +519,11 @@ interface ReadAssetDetailsResult {
const readAssetDetails = async ({ const readAssetDetails = async ({
isLivePhoto, isLivePhoto,
livePhotoAssets, livePhotoAssets,
file, fileOrPath,
}: UploadAsset2): Promise<ReadAssetDetailsResult> => }: UploadAsset2): Promise<ReadAssetDetailsResult> =>
isLivePhoto isLivePhoto
? readLivePhotoDetails(livePhotoAssets) ? readLivePhotoDetails(livePhotoAssets)
: readImageOrVideoDetails(file); : readImageOrVideoDetails(fileOrPath);
const readLivePhotoDetails = async ({ image, video }: LivePhotoAssets2) => { const readLivePhotoDetails = async ({ image, video }: LivePhotoAssets2) => {
const img = await readImageOrVideoDetails(image); const img = await readImageOrVideoDetails(image);
@ -533,7 +590,7 @@ interface ExtractAssetMetadataResult {
* {@link parsedMetadataJSONMap} for the assets. Return the resultant metadatum. * {@link parsedMetadataJSONMap} for the assets. Return the resultant metadatum.
*/ */
const extractAssetMetadata = async ( const extractAssetMetadata = async (
{ isLivePhoto, file, livePhotoAssets }: UploadAsset2, { isLivePhoto, fileOrPath, livePhotoAssets }: UploadAsset2,
fileTypeInfo: FileTypeInfo, fileTypeInfo: FileTypeInfo,
lastModifiedMs: number, lastModifiedMs: number,
collectionID: number, collectionID: number,
@ -550,7 +607,7 @@ const extractAssetMetadata = async (
worker, worker,
) )
: await extractImageOrVideoMetadata( : await extractImageOrVideoMetadata(
file, fileOrPath,
fileTypeInfo, fileTypeInfo,
lastModifiedMs, lastModifiedMs,
collectionID, collectionID,
@ -774,11 +831,11 @@ const areFilesSameNoHash = (f: Metadata, g: Metadata) => {
const readAsset = async ( const readAsset = async (
fileTypeInfo: FileTypeInfo, fileTypeInfo: FileTypeInfo,
{ isLivePhoto, file, livePhotoAssets }: UploadAsset2, { isLivePhoto, fileOrPath, livePhotoAssets }: UploadAsset2,
) => ) =>
isLivePhoto isLivePhoto
? await readLivePhoto(livePhotoAssets, fileTypeInfo) ? await readLivePhoto(livePhotoAssets, fileTypeInfo)
: await readImageOrVideo(file, fileTypeInfo); : await readImageOrVideo(fileOrPath, fileTypeInfo);
const readLivePhoto = async ( const readLivePhoto = async (
livePhotoAssets: LivePhotoAssets2, livePhotoAssets: LivePhotoAssets2,

View file

@ -1,29 +1,11 @@
import type { Metadata } from "@/media/types/file";
import type { ElectronFile } from "@/next/types/file"; import type { ElectronFile } from "@/next/types/file";
import {
B64EncryptionResult,
LocalFileAttributes,
} from "@ente/shared/crypto/types";
import type { DataStream } from "@ente/shared/utils/data-stream";
import { Collection } from "types/collection"; import { Collection } from "types/collection";
import {
FilePublicMagicMetadata,
MetadataFileAttributes,
S3FileAttributes,
} from "types/file";
import { EncryptedMagicMetadata } from "types/magicMetadata";
export interface Location { export interface Location {
latitude: number; latitude: number;
longitude: number; longitude: number;
} }
export interface MultipartUploadURLs {
objectKey: string;
partURLs: string[];
completeURL: string;
}
export interface UploadAsset { export interface UploadAsset {
isLivePhoto?: boolean; isLivePhoto?: boolean;
file?: File | ElectronFile; file?: File | ElectronFile;
@ -42,72 +24,17 @@ export interface FileWithCollection extends UploadAsset {
collectionID?: number; collectionID?: number;
} }
export interface UploadAsset2 {
isLivePhoto?: boolean;
file?: File | string;
fileOrPath?: File | string;
livePhotoAssets?: LivePhotoAssets2;
}
export interface LivePhotoAssets2 { export interface LivePhotoAssets2 {
image: File | string; image: File | string;
video: File | string; video: File | string;
} }
export interface FileWithCollection2 extends UploadAsset2 { export interface FileWithCollection2 extends UploadAsset {
localID: number; localID: number;
collection?: Collection; collection?: Collection;
collectionID: number; collectionID: number;
} }
export interface UploadURL {
url: string;
objectKey: string;
}
export interface FileInMemory {
filedata: Uint8Array | DataStream;
/** The JPEG data of the generated thumbnail */
thumbnail: Uint8Array;
/**
* `true` if this is a fallback (all black) thumbnail we're returning since
* thumbnail generation failed for some reason.
*/
hasStaticThumbnail: boolean;
}
export interface FileWithMetadata
extends Omit<FileInMemory, "hasStaticThumbnail"> {
metadata: Metadata;
localID: number;
pubMagicMetadata: FilePublicMagicMetadata;
}
export interface EncryptedFile {
file: ProcessedFile;
fileKey: B64EncryptionResult;
}
export interface ProcessedFile {
file: LocalFileAttributes<Uint8Array | DataStream>;
thumbnail: LocalFileAttributes<Uint8Array>;
metadata: LocalFileAttributes<string>;
pubMagicMetadata: EncryptedMagicMetadata;
localID: number;
}
export interface BackupedFile {
file: S3FileAttributes;
thumbnail: S3FileAttributes;
metadata: MetadataFileAttributes;
pubMagicMetadata: EncryptedMagicMetadata;
}
export interface UploadFile extends BackupedFile {
collectionID: number;
encryptedKey: string;
keyDecryptionNonce: string;
}
export interface ParsedExtractedMetadata { export interface ParsedExtractedMetadata {
location: Location; location: Location;
creationTime: number; creationTime: number;