From d14217400af045657663eca8304fddfeee7620a3 Mon Sep 17 00:00:00 2001 From: abhinav-grd Date: Fri, 8 Oct 2021 19:56:49 +0530 Subject: [PATCH] added migrate service to update large thumbnails --- src/services/migrate/index.ts | 130 ++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/services/migrate/index.ts diff --git a/src/services/migrate/index.ts b/src/services/migrate/index.ts new file mode 100644 index 000000000..fc74535d4 --- /dev/null +++ b/src/services/migrate/index.ts @@ -0,0 +1,130 @@ +import downloadManager from 'services/downloadManager'; +import { File, fileAttribute, FILE_TYPE } from 'services/fileService'; +import { + generateThumbnail, + MAX_THUMBNAIL_SIZE, +} from 'services/upload/thumbnailService'; +import { getToken } from 'utils/common/key'; +import { logError } from 'utils/sentry'; +import { getEndpoint } from 'utils/common/apiUtil'; +import HTTPService from 'services/HTTPService'; +import CryptoWorker from 'utils/crypto'; +import { convertToHumanReadable } from 'utils/billingUtil'; +import uploadHttpClient from 'services/upload/uploadHttpClient'; +import { EncryptionResult, UploadURL } from 'services/upload/uploadService'; + +const ENDPOINT = getEndpoint(); + +export async function getLargeThumbnailFiles() { + try { + const token = getToken(); + if (!token) { + return; + } + const resp = await HTTPService.get( + `${ENDPOINT}/files/large-thumbnails`, + { + threshold: 2 * MAX_THUMBNAIL_SIZE, + }, + { + 'X-Auth-Token': token, + } + ); + return resp.data.largeThumbnailFiles as number[]; + } catch (e) { + logError(e, 'failed to get large thumbnail files'); + throw e; + } +} +export async function regenerateThumbnail(files: File[]) { + try { + const token = getToken(); + const worker = await new CryptoWorker(); + const largeThumbnailFileIDs = new Set( + (await getLargeThumbnailFiles()) ?? [] + ); + const largeThumbnailFiles = files.filter((file) => + largeThumbnailFileIDs.has(file.id) + ); + const uploadURLs: UploadURL[] = []; + uploadHttpClient.fetchUploadURLs( + largeThumbnailFiles.length, + uploadURLs + ); + for (const file of largeThumbnailFiles) { + const originalThumbnail = await downloadManager.getThumbnail( + token, + file + ); + const dummyImageFile = new globalThis.File( + [originalThumbnail], + file.metadata.title + ); + const { thumbnail: newThumbnail } = await generateThumbnail( + worker, + dummyImageFile, + FILE_TYPE.IMAGE, + false + ); + const newUploadedThumbnail = await uploadThumbnail( + worker, + file.key, + newThumbnail, + uploadURLs.pop() + ); + await updateThumbnail(file.id, newUploadedThumbnail); + console.log( + URL.createObjectURL(new Blob([newThumbnail])), + convertToHumanReadable(newThumbnail.length) + ); + } + } catch (e) { + logError(e, 'failed to regenerate thumbnail'); + } +} + +export async function uploadThumbnail( + worker, + fileKey: string, + updatedThumbnail: Uint8Array, + uploadURL: UploadURL +): Promise { + const { file: encryptedThumbnail }: EncryptionResult = + await worker.encryptThumbnail(updatedThumbnail, fileKey); + + const thumbnailObjectKey = await uploadHttpClient.putFile( + uploadURL, + encryptedThumbnail.encryptedData as Uint8Array, + () => {} + ); + return { + objectKey: thumbnailObjectKey, + decryptionHeader: encryptedThumbnail.decryptionHeader, + }; +} + +export async function updateThumbnail( + fileID: number, + newThumbnail: fileAttribute +) { + try { + const token = getToken(); + if (!token) { + return; + } + await HTTPService.put( + `${ENDPOINT}/files/thumbnail`, + { + fileID: fileID, + thumbnail: newThumbnail, + }, + null, + { + 'X-Auth-Token': token, + } + ); + } catch (e) { + logError(e, 'failed to update thumbnail'); + throw e; + } +}