From 791c0e8df63a689745b4d205ebadfc5b3cf4d7cd Mon Sep 17 00:00:00 2001 From: fyears <1142836+fyears@users.noreply.github.com> Date: Sat, 30 Mar 2024 03:30:18 +0800 Subject: [PATCH] very basic synthesizedFolder --- src/baseTypes.ts | 1 + src/remote.ts | 6 ++++-- src/remoteForS3.ts | 12 +++++++++-- src/sync.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/baseTypes.ts b/src/baseTypes.ts index c119edd..b609ed2 100644 --- a/src/baseTypes.ts +++ b/src/baseTypes.ts @@ -204,6 +204,7 @@ export interface Entity { sizeRaw: number; hash?: string; etag?: string; + synthesizedFolder?: boolean; } export interface UploadedType { diff --git a/src/remote.ts b/src/remote.ts index 2048b65..c642cca 100644 --- a/src/remote.ts +++ b/src/remote.ts @@ -239,7 +239,8 @@ export class RemoteClient { deleteFromRemote = async ( fileOrFolderPath: string, cipher: Cipher, - remoteEncryptedKey: string = "" + remoteEncryptedKey: string = "", + synthesizedFolder: boolean = false ) => { if (this.serviceType === "s3") { return await s3.deleteFromRemote( @@ -247,7 +248,8 @@ export class RemoteClient { this.s3Config!, fileOrFolderPath, cipher, - remoteEncryptedKey + remoteEncryptedKey, + synthesizedFolder ); } else if (this.serviceType === "webdav") { return await webdav.deleteFromRemote( diff --git a/src/remoteForS3.ts b/src/remoteForS3.ts index 5d85750..2be87c9 100644 --- a/src/remoteForS3.ts +++ b/src/remoteForS3.ts @@ -250,6 +250,7 @@ const fromS3ObjectToEntity = ( mtimeCli: mtimeCli, sizeRaw: x.Size!, etag: x.ETag, + synthesizedFolder: false, }; return r; }; @@ -599,7 +600,10 @@ export const listAllFromRemote = async ( s3Client: S3Client, s3Config: S3Config ) => { - return await listFromRemoteRaw(s3Client, s3Config, s3Config.remotePrefix); + const res = ( + await listFromRemoteRaw(s3Client, s3Config, s3Config.remotePrefix) + ).filter((x) => x.keyRaw !== "" && x.keyRaw !== "/"); + return res; }; /** @@ -715,11 +719,15 @@ export const deleteFromRemote = async ( s3Config: S3Config, fileOrFolderPath: string, cipher: Cipher, - remoteEncryptedKey: string = "" + remoteEncryptedKey: string = "", + synthesizedFolder: boolean = false ) => { if (fileOrFolderPath === "/") { return; } + if (synthesizedFolder) { + return; + } let remoteFileName = fileOrFolderPath; if (!cipher.isPasswordEmpty()) { remoteFileName = remoteEncryptedKey; diff --git a/src/sync.ts b/src/sync.ts index 297778c..6e50440 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -18,6 +18,7 @@ import { isVaildText, atWhichLevel, mkdirpInVault, + getFolderLevels, } from "./misc"; import { DEFAULT_FILE_NAME_FOR_METADATAONREMOTE, @@ -326,7 +327,10 @@ export const ensembleMixedEnties = async ( ): Promise => { const finalMappings: SyncPlanType = {}; + const synthFolders: Record = {}; + // remote has to be first + // we also have to synthesize folders here for (const remote of remoteEntityList) { const remoteCopied = ensureMTimeOfRemoteEntityValid( await decryptRemoteEntityInplace( @@ -352,6 +356,42 @@ export const ensembleMixedEnties = async ( key: key, remote: remoteCopied, }; + + for (const f of getFolderLevels(key, true)) { + if (finalMappings.hasOwnProperty(f)) { + delete synthFolders[f]; + continue; + } + if ( + !synthFolders.hasOwnProperty(f) || + remoteCopied.mtimeSvr! >= synthFolders[f].mtimeSvr! + ) { + synthFolders[f] = { + key: f, + keyRaw: ``, + keyEnc: ``, + size: 0, + sizeRaw: 0, + sizeEnc: 0, + mtimeSvr: remoteCopied.mtimeSvr, + mtimeSvrFmt: remoteCopied.mtimeSvrFmt, + mtimeCli: remoteCopied.mtimeCli, + mtimeCliFmt: remoteCopied.mtimeCliFmt, + synthesizedFolder: true, + }; + } + } + } + + console.debug(`synthFolders:`); + console.debug(synthFolders); + + // special: add synth folders + for (const key of Object.keys(synthFolders)) { + finalMappings[key] = { + key: key, + remote: synthFolders[key], + }; } if (Object.keys(finalMappings).length === 0 || localEntityList.length === 0) { @@ -1074,7 +1114,12 @@ const dispatchOperationToActualV3 = async ( ); } else if (r.decision === "local_is_deleted_thus_also_delete_remote") { // local is deleted, we need to delete remote now - await client.deleteFromRemote(r.key, cipher, r.remote!.keyEnc); + await client.deleteFromRemote( + r.key, + cipher, + r.remote!.keyEnc, + r.remote!.synthesizedFolder + ); await clearPrevSyncRecordByVaultAndProfile( db, vaultRandomID, @@ -1128,7 +1173,12 @@ const dispatchOperationToActualV3 = async ( r.decision === "folder_to_be_deleted_on_both" || r.decision === "folder_to_be_deleted_on_remote" ) { - await client.deleteFromRemote(r.key, cipher, r.remote!.keyEnc); + await client.deleteFromRemote( + r.key, + cipher, + r.remote!.keyEnc, + r.remote!.synthesizedFolder + ); } await clearPrevSyncRecordByVaultAndProfile( db,