diff --git a/README.md b/README.md index 77083aac..200d250b 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ pedantic = { level = "warn", priority = 0 } cargo = { level = "warn", priority = 0 } - +update card title max width reset should reset counters access logs retry diff --git a/plugin/src/file-operations/obsidian-file-operations.ts b/plugin/src/file-operations/obsidian-file-operations.ts index 28c044f0..7f9a47aa 100644 --- a/plugin/src/file-operations/obsidian-file-operations.ts +++ b/plugin/src/file-operations/obsidian-file-operations.ts @@ -33,6 +33,7 @@ export class ObsidianFileOperations implements FileOperations { newContent: Uint8Array ): Promise { if (!(await this.vault.adapter.exists(normalizePath(path)))) { + // The caller assumed the file exists, but it doesn't, let's not recreate it return new Uint8Array(0); } @@ -62,6 +63,7 @@ export class ObsidianFileOperations implements FileOperations { return; } + await this.createParentDirectories(normalizePath(path)); await this.vault.adapter.writeBinary(normalizePath(path), newContent); } @@ -84,4 +86,17 @@ export class ObsidianFileOperations implements FileOperations { normalizePath(newPath) ); } + + private async createParentDirectories(path: string): Promise { + const components = path.split("/"); + if (components.length === 1) { + return; + } + for (let i = 1; i < components.length; i++) { + const parentDir = components.slice(0, i).join("/"); + if (!(await this.vault.adapter.exists(parentDir))) { + await this.vault.adapter.mkdir(parentDir); + } + } + } } diff --git a/plugin/src/sync-operations/sync-locally-created-file.ts b/plugin/src/sync-operations/sync-locally-created-file.ts index 180bdf5c..0fa37fc2 100644 --- a/plugin/src/sync-operations/sync-locally-created-file.ts +++ b/plugin/src/sync-operations/sync-locally-created-file.ts @@ -37,18 +37,20 @@ export async function syncLocallyCreatedFile({ try { const metadata = database.getDocument(relativePath); if (metadata) { - throw new Error( - `Document metadata found for ${relativePath}, this is unexpected. Consider resetting the plugin's sync history.` + Logger.getInstance().debug( + `Document metadata already exists for ${relativePath}, it must have been downloaded from the server` ); } - const contentBytes = await operations.read(relativePath), - contentHash = hash(contentBytes), - response = await syncServer.create({ - relativePath, - contentBytes, - createdDate: updateTime, - }); + const contentBytes = await operations.read(relativePath); + const contentHash = hash(contentBytes); + + const response = await syncServer.create({ + relativePath, + contentBytes, + createdDate: updateTime, + }); + history.addHistoryEntry({ status: SyncStatus.SUCCESS, source: SyncSource.PUSH, @@ -57,8 +59,8 @@ export async function syncLocallyCreatedFile({ type: SyncType.CREATE, }); - const responseBytes = lib.base64_to_bytes(response.contentBase64), - responseHash = hash(responseBytes); + const responseBytes = lib.base64_to_bytes(response.contentBase64); + const responseHash = hash(responseBytes); if (contentHash !== responseHash) { await operations.write(relativePath, contentBytes, responseBytes); diff --git a/plugin/src/sync-operations/sync-locally-updated-file.ts b/plugin/src/sync-operations/sync-locally-updated-file.ts index 2049f0ae..f95e0fb7 100644 --- a/plugin/src/sync-operations/sync-locally-updated-file.ts +++ b/plugin/src/sync-operations/sync-locally-updated-file.ts @@ -45,8 +45,8 @@ export async function syncLocallyUpdatedFile({ ); } - const contentBytes = await operations.read(relativePath), - contentHash = hash(contentBytes); + const contentBytes = await operations.read(relativePath); + const contentHash = hash(contentBytes); if (metadata.hash === contentHash && oldPath !== undefined) { history.addHistoryEntry({ @@ -91,6 +91,7 @@ export async function syncLocallyUpdatedFile({ } const responseBytes = lib.base64_to_bytes(response.contentBase64); + const responseHash = hash(responseBytes); if (response.relativePath != relativePath) { await waitForDocumentLock(response.relativePath); @@ -116,7 +117,7 @@ export async function syncLocallyUpdatedFile({ } finally { unlockDocument(response.relativePath); } - } else { + } else if (contentHash !== responseHash) { await operations.write(relativePath, contentBytes, responseBytes); } @@ -125,7 +126,7 @@ export async function syncLocallyUpdatedFile({ oldRelativePath: oldPath ?? relativePath, relativePath: response.relativePath, parentVersionId: response.vaultUpdateId, - hash: contentHash, + hash: responseHash, }); } catch (e) { history.addHistoryEntry({ diff --git a/plugin/src/sync-operations/sync-remotely-updated-file.ts b/plugin/src/sync-operations/sync-remotely-updated-file.ts index 4311e519..9632a46f 100644 --- a/plugin/src/sync-operations/sync-remotely-updated-file.ts +++ b/plugin/src/sync-operations/sync-remotely-updated-file.ts @@ -26,15 +26,20 @@ export async function syncRemotelyUpdatedFile({ `Syncing remotely updated file ${remoteVersion.relativePath}` ); + const content = ( + await syncServer.get({ + documentId: remoteVersion.documentId, + }) + ).contentBase64; + const contentBytes = lib.base64_to_bytes(content); + const contentHash = hash(contentBytes); + + await waitForDocumentLock(remoteVersion.relativePath); + try { - const content = ( - await syncServer.get({ - documentId: remoteVersion.documentId, - }) - ).contentBase64, - currentVersion = database.getDocumentByDocumentId( - remoteVersion.documentId - ); + const currentVersion = database.getDocumentByDocumentId( + remoteVersion.documentId + ); if (!currentVersion) { if (remoteVersion.isDeleted) { @@ -48,35 +53,27 @@ export async function syncRemotelyUpdatedFile({ return; } - await waitForDocumentLock(remoteVersion.relativePath); - try { - const contentBytes = lib.base64_to_bytes(content); - await operations.create( - remoteVersion.relativePath, - contentBytes - ); - await database.setDocument({ - documentId: remoteVersion.documentId, - relativePath: remoteVersion.relativePath, - parentVersionId: remoteVersion.vaultUpdateId, - hash: hash(contentBytes), - }); - history.addHistoryEntry({ - status: SyncStatus.SUCCESS, - source: SyncSource.PULL, - relativePath: remoteVersion.relativePath, - message: `Successfully downloaded remote file which hasn't existed locally`, - type: SyncType.CREATE, - }); - } finally { - unlockDocument(remoteVersion.relativePath); - } + await operations.create(remoteVersion.relativePath, contentBytes); + await database.setDocument({ + documentId: remoteVersion.documentId, + relativePath: remoteVersion.relativePath, + parentVersionId: remoteVersion.vaultUpdateId, + hash: contentHash, + }); + history.addHistoryEntry({ + status: SyncStatus.SUCCESS, + source: SyncSource.PULL, + relativePath: remoteVersion.relativePath, + message: `Successfully downloaded remote file which hasn't existed locally`, + type: SyncType.CREATE, + }); return; } const [relativePath, metadata] = currentVersion; - await waitForDocumentLock(relativePath); - + if (relativePath !== remoteVersion.relativePath) { + await waitForDocumentLock(relativePath); + } try { if (remoteVersion.isDeleted) { await operations.remove(relativePath); @@ -90,13 +87,14 @@ export async function syncRemotelyUpdatedFile({ type: SyncType.DELETE, }); } else { - const currentContent = await operations.read(relativePath), - currentHash = hash(currentContent); + const currentContent = await operations.read(relativePath); + const currentHash = hash(currentContent); + if (currentHash !== metadata.hash) { Logger.getInstance().info( `Document ${relativePath} has been updated both remotely and locally, skipping until the event is processed` ); - } else { + } else if (contentHash !== metadata.hash) { if (relativePath !== remoteVersion.relativePath) { await operations.move( relativePath, @@ -104,7 +102,6 @@ export async function syncRemotelyUpdatedFile({ ); } - const contentBytes = lib.base64_to_bytes(content); await operations.write( remoteVersion.relativePath, currentContent, @@ -115,7 +112,7 @@ export async function syncRemotelyUpdatedFile({ oldRelativePath: relativePath, relativePath: remoteVersion.relativePath, parentVersionId: remoteVersion.vaultUpdateId, - hash: metadata.hash, + hash: contentHash, }); history.addHistoryEntry({ @@ -126,9 +123,16 @@ export async function syncRemotelyUpdatedFile({ type: SyncType.UPDATE, }); } + { + Logger.getInstance().debug( + `Document ${relativePath} is already up to date` + ); + } } } finally { - unlockDocument(relativePath); + if (relativePath !== remoteVersion.relativePath) { + unlockDocument(relativePath); + } } } catch (e) { history.addHistoryEntry({ @@ -138,5 +142,7 @@ export async function syncRemotelyUpdatedFile({ message: `Failed to reconcile remotely updated file: ${e}`, }); throw e; + } finally { + unlockDocument(remoteVersion.relativePath); } }