Fix file download

This commit is contained in:
Neeraj Gupta 2024-01-29 10:40:31 +05:30
parent 68bfe9118a
commit 7cd7676cb0
5 changed files with 83 additions and 100 deletions

View file

@ -4,8 +4,11 @@ import Theatre from 'components/Theatre';
import { FILE_TYPE } from 'constants/file';
import { useRouter } from 'next/router';
import { createContext, useEffect, useState } from 'react';
import { getCollectionWithKey } from 'services/collectionService';
import { syncFiles } from 'services/fileService';
import {
getCastCollection,
getLocalFiles,
syncPublicFiles,
} from 'services/cast/castService';
import { EnteFile } from 'types/file';
import { downloadFileAsBlob, isRawFileFromFileName } from 'utils/file';
@ -22,6 +25,7 @@ export default function Slideshow() {
const [nextFile, setNextFile] = useState<EnteFile | undefined>(undefined);
const [loading, setLoading] = useState(true);
const [castToken, setCastToken] = useState<string>('');
const [renderableFileURLCache, setRenderableFileURLCache] = useState<
Record<string, string>
@ -29,28 +33,21 @@ export default function Slideshow() {
const init = async () => {
try {
// get requested collection id from localStorage
const requestedCollectionID =
window.localStorage.getItem('collectionID');
const requestedCollectionKey =
window.localStorage.getItem('collectionKey');
const castToken = window.localStorage.getItem('castToken');
setCastToken(castToken);
const collection = await getCollectionWithKey(
Number(requestedCollectionID),
requestedCollectionKey,
'cast',
castToken
const collection = await getCastCollection(
castToken,
requestedCollectionKey
);
const files = await syncFiles('normal', [collection], () => {});
if (requestedCollectionID) {
setCollectionFiles(
files.filter((file) => isFileEligibleForCast(file))
);
}
await syncPublicFiles(castToken, collection, () => {});
const files = await getLocalFiles(String(collection.id));
setCollectionFiles(
files.filter((file) => isFileEligibleForCast(file))
);
} catch (e) {
logError(e, 'error during sync');
alert('error, redirect to home' + e);
@ -122,7 +119,10 @@ export default function Slideshow() {
}
try {
const blob = await downloadFileAsBlob(currentFile as EnteFile);
const blob = await downloadFileAsBlob(
currentFile as EnteFile,
castToken
);
const url = URL.createObjectURL(blob);

View file

@ -1,24 +1,22 @@
import { getEndpoint } from '@ente/shared/network/api';
import localForage from '@ente/shared/storage/localForage';
import { Collection, CollectionPublicMagicMetadata } from 'types/collection';
import HTTPService from '@ente/shared/network/HTTPService';
import { logError } from '@ente/shared/sentry';
import { decryptFile, mergeMetadata, sortFiles } from 'utils/file';
import { EncryptedEnteFile, EnteFile } from 'types/file';
import { CustomError, parseSharingErrorCodes } from '@ente/shared/error';
import ComlinkCryptoWorker from '@ente/shared/crypto';
import { Collection, CollectionPublicMagicMetadata } from 'types/collection';
import { EncryptedEnteFile, EnteFile } from 'types/file';
import { decryptFile, mergeMetadata, sortFiles } from 'utils/file';
export interface SavedCollectionFiles {
collectionUID: string;
collectionLocalID: string;
files: EnteFile[];
}
const ENDPOINT = getEndpoint();
const COLLECTION_FILES_TABLE = 'collection-files';
const COLLECTIONS_TABLE = 'collections';
export const getPublicCollectionUID = (token: string) => `${token}`;
const getLastSyncKey = (collectionUID: string) => `${collectionUID}-time`;
export const getLocalFiles = async (
@ -29,11 +27,12 @@ export const getLocalFiles = async (
COLLECTION_FILES_TABLE
)) || [];
const matchedCollection = localSavedcollectionFiles.find(
(item) => item.collectionUID === collectionUID
(item) => item.collectionLocalID === collectionUID
);
return matchedCollection?.files || [];
};
export const savecollectionFiles = async (
const savecollectionFiles = async (
collectionUID: string,
files: EnteFile[]
) => {
@ -43,7 +42,10 @@ export const savecollectionFiles = async (
)) || [];
await localForage.setItem(
COLLECTION_FILES_TABLE,
dedupeCollectionFiles([{ collectionUID, files }, ...collectionFiles])
dedupeCollectionFiles([
{ collectionLocalID: collectionUID, files },
...collectionFiles,
])
);
};
@ -58,7 +60,7 @@ export const getLocalCollections = async (collectionKey: string) => {
return collection;
};
export const saveCollection = async (collection: Collection) => {
const saveCollection = async (collection: Collection) => {
const collections =
(await localForage.getItem<Collection[]>(COLLECTIONS_TABLE)) ?? [];
await localForage.setItem(
@ -81,7 +83,7 @@ const dedupeCollections = (collections: Collection[]) => {
const dedupeCollectionFiles = (collectionFiles: SavedCollectionFiles[]) => {
const keySet = new Set([]);
return collectionFiles.filter(({ collectionUID }) => {
return collectionFiles.filter(({ collectionLocalID: collectionUID }) => {
if (!keySet.has(collectionUID)) {
keySet.add(collectionUID);
return true;
@ -108,14 +110,11 @@ export const syncPublicFiles = async (
try {
let files: EnteFile[] = [];
const sortAsc = collection?.pubMagicMetadata?.data.asc ?? false;
const collectionUID = getPublicCollectionUID(token);
const collectionUID = String(collection.id);
const localFiles = await getLocalFiles(collectionUID);
files = [...files, ...localFiles];
console.log('found local files', files);
try {
if (!token) {
return sortFiles(files, sortAsc);
}
const lastSyncTime = await getSyncTime(collectionUID);
if (collection.updationTime === lastSyncTime) {
return sortFiles(files, sortAsc);
@ -165,7 +164,7 @@ export const syncPublicFiles = async (
};
const fetchFiles = async (
token: string,
castToken: string,
collection: Collection,
sinceTime: number,
files: EnteFile[],
@ -177,17 +176,17 @@ const fetchFiles = async (
let resp;
const sortAsc = collection?.pubMagicMetadata?.data.asc ?? false;
do {
if (!token) {
if (!castToken) {
break;
}
resp = await HTTPService.get(
`${ENDPOINT}/public-collection/diff`,
`${ENDPOINT}/cast/diff`,
{
sinceTime: time,
},
{
'Cache-Control': 'no-cache',
'X-Auth-Access-Token': token,
'X-Cast-Access-Token': castToken,
}
);
decryptedFiles = [
@ -225,18 +224,14 @@ const fetchFiles = async (
};
export const getCastCollection = async (
token: string,
castToken: string,
collectionKey: string
): Promise<[Collection]> => {
): Promise<Collection> => {
try {
if (!token) {
return;
}
const resp = await HTTPService.get(
`${ENDPOINT}/public-collection/info`,
null,
{ 'Cache-Control': 'no-cache', 'X-Auth-Access-Token': token }
);
const resp = await HTTPService.get(`${ENDPOINT}/cast/info`, null, {
'Cache-Control': 'no-cache',
'X-Cast-Access-Token': castToken,
});
const fetchedCollection = resp.data.collection;
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
@ -268,9 +263,9 @@ export const getCastCollection = async (
pubMagicMetadata: collectionPublicMagicMetadata,
};
await saveCollection(collection);
return [collection];
return collection;
} catch (e) {
logError(e, 'failed to get public collection');
logError(e, 'failed to get cast collection');
throw e;
}
};
@ -297,7 +292,8 @@ export const removeCollectionFiles = async (collectionUID: string) => {
await localForage.setItem(
COLLECTION_FILES_TABLE,
collectionFiles.filter(
(collectionFiles) => collectionFiles.collectionUID !== collectionUID
(collectionFiles) =>
collectionFiles.collectionLocalID !== collectionUID
)
);
};

View file

@ -12,7 +12,7 @@ import { CACHES } from 'constants/cache';
import { CacheStorageService } from './cache/cacheStorageService';
import { LimitedCache } from 'types/cache';
import {
getPublicCollectionFileURL,
getCastFileURL,
getPublicCollectionThumbnailURL,
} from '@ente/shared/network/api';
import HTTPService from '@ente/shared/network/HTTPService';
@ -185,11 +185,8 @@ class CastDownloadManager {
return await this.fileObjectURLPromise.get(file.id.toString());
}
async downloadFile(token: string, passwordToken: string, file: EnteFile) {
async downloadFile(castToken: string, file: EnteFile) {
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
if (!token) {
return null;
}
const onDownloadProgress = this.trackDownloadProgress(file.id);
if (
@ -197,14 +194,10 @@ class CastDownloadManager {
file.metadata.fileType === FILE_TYPE.LIVE_PHOTO
) {
const resp = await HTTPService.get(
getPublicCollectionFileURL(file.id),
getCastFileURL(file.id),
null,
{
'X-Auth-Access-Token': token,
...(passwordToken && {
'X-Auth-Access-Token-JWT': passwordToken,
onDownloadProgress,
}),
'X-Cast-Access-Token': castToken,
},
{ responseType: 'arraybuffer' }
);
@ -218,12 +211,9 @@ class CastDownloadManager {
);
return generateStreamFromArrayBuffer(decrypted);
}
const resp = await fetch(getPublicCollectionFileURL(file.id), {
const resp = await fetch(getCastFileURL(file.id), {
headers: {
'X-Auth-Access-Token': token,
...(passwordToken && {
'X-Auth-Access-Token-JWT': passwordToken,
}),
'X-Cast-Access-Token': castToken,
},
});
const reader = resp.body.getReader();

View file

@ -9,7 +9,6 @@ import {
} from 'types/file';
import { decodeLivePhoto } from 'services/livePhotoService';
import { getFileType } from 'services/typeDetectionService';
import DownloadManager from 'services/downloadManager';
import { logError } from '@ente/shared/sentry';
import { updateFileCreationDateInEXIF } from 'services/upload/exifService';
import {
@ -88,39 +87,25 @@ export async function getUpdatedEXIFFileForDownload(
export async function downloadFile(
file: EnteFile,
accessedThroughSharedURL: boolean,
token?: string,
passwordToken?: string
) {
try {
let fileBlob: Blob;
const fileReader = new FileReader();
if (accessedThroughSharedURL) {
const fileURL = await CastDownloadManager.getCachedOriginalFile(
file
)[0];
if (!fileURL) {
fileBlob = await new Response(
await CastDownloadManager.downloadFile(
token,
passwordToken,
file
)
).blob();
} else {
fileBlob = await (await fetch(fileURL)).blob();
}
const fileURL = await CastDownloadManager.getCachedOriginalFile(
file
)[0];
if (!fileURL) {
fileBlob = await new Response(
await CastDownloadManager.downloadFile(
token,
passwordToken,
file
)
).blob();
} else {
const fileURL = await DownloadManager.getCachedOriginalFile(
file
)[0];
if (!fileURL) {
fileBlob = await new Response(
await DownloadManager.downloadFile(file)
).blob();
} else {
fileBlob = await (await fetch(fileURL)).blob();
}
fileBlob = await (await fetch(fileURL)).blob();
}
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
@ -844,14 +829,18 @@ const deleteFileHelper = async (
}
};
export const downloadFileAsBlob = async (file: EnteFile): Promise<Blob> => {
export const downloadFileAsBlob = async (
file: EnteFile,
castToken: string
): Promise<Blob> => {
try {
let fileBlob: Blob;
// const fileReader = new FileReader();
const fileURL = await DownloadManager.getCachedOriginalFile(file)[0];
const fileURL = await CastDownloadManager.getCachedOriginalFile(
file
)[0];
if (!fileURL) {
fileBlob = await new Response(
await DownloadManager.downloadFile(file)
await CastDownloadManager.downloadFile(castToken, file)
).blob();
} else {
fileBlob = await (await fetch(fileURL)).blob();

View file

@ -28,6 +28,14 @@ export const getPublicCollectionFileURL = (id: number) => {
return `https://public-albums.ente.io/download/?fileID=${id}`;
};
export const getCastFileURL = (id: number) => {
const endpoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT;
if (isDevDeployment() && endpoint) {
return `${endpoint}/cast/files/download/${id}`;
}
return `https://cast-albums.ente.io/download/?fileID=${id}`;
};
export const getThumbnailURL = (id: number) => {
const endpoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT;
if (isDevDeployment() && endpoint) {