Fixes & refactor

This commit is contained in:
Andras Schmelczer 2025-02-22 17:17:07 +00:00
parent e6eedab87d
commit f73b5ecb71
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
4 changed files with 54 additions and 43 deletions

View file

@ -120,7 +120,7 @@ export class FileOperations {
} }
public async remove(path: RelativePath): Promise<void> { public async remove(path: RelativePath): Promise<void> {
this.logger.debug(`Removing file: ${path}`); this.logger.debug(`Deleting file: ${path}`);
return this.fs.delete(path); return this.fs.delete(path);
} }

View file

@ -135,6 +135,7 @@ export class SyncClient {
public async reset(): Promise<void> { public async reset(): Promise<void> {
await this._syncer.reset(); await this._syncer.reset();
this._history.reset(); this._history.reset();
await this._database.resetSyncState();
this.logger.reset(); this.logger.reset();
} }

View file

@ -15,6 +15,7 @@ import type { components } from "src/services/types";
import { deserialize } from "src/utils/deserialize"; import { deserialize } from "src/utils/deserialize";
import type { Settings } from "src/persistence/settings"; import type { Settings } from "src/persistence/settings";
import { FileOperations } from "src/file-operations/file-operations"; import { FileOperations } from "src/file-operations/file-operations";
import { findMatchingFileBasedOnHash } from "src/utils/find-matching-file-based-on-hash";
export class Syncer { export class Syncer {
private readonly remainingOperationsListeners: (( private readonly remainingOperationsListeners: ((
@ -74,6 +75,10 @@ export class Syncer {
); );
} }
public waitForSyncQueue(): Promise<void> {
return this.syncQueue.onEmpty();
}
public async syncLocallyDeletedFile( public async syncLocallyDeletedFile(
relativePath: RelativePath relativePath: RelativePath
): Promise<void> { ): Promise<void> {
@ -136,11 +141,10 @@ export class Syncer {
await this.operations.read(relativePath); await this.operations.read(relativePath);
const contentHash = hash(contentBytes); const contentHash = hash(contentBytes);
const originalFile = const originalFile = findMatchingFileBasedOnHash(
await this.findMatchingFileBasedOnHash( contentHash,
contentHash, locallyDeletedFiles
locallyDeletedFiles );
);
if (originalFile !== undefined) { if (originalFile !== undefined) {
// `originalFile` hasn't been deleted but it got moved instead // `originalFile` hasn't been deleted but it got moved instead
locallyDeletedFiles = locallyDeletedFiles.filter( locallyDeletedFiles = locallyDeletedFiles.filter(
@ -202,7 +206,8 @@ export class Syncer {
return Promise.resolve(); return Promise.resolve();
} }
return this.internalSyncLocallyDeletedFile(relativePath); // We're outside of the pqueue, so we need to call the public wrapper
return this.syncLocallyDeletedFile(relativePath);
}) })
); );
} }
@ -265,8 +270,6 @@ export class Syncer {
public async reset(): Promise<void> { public async reset(): Promise<void> {
this.syncQueue.clear(); this.syncQueue.clear();
await this.syncQueue.onEmpty(); await this.syncQueue.onEmpty();
await this.database.resetSyncState();
this.history.reset();
this.remainingOperationsListeners.forEach((listener) => { this.remainingOperationsListeners.forEach((listener) => {
listener(0); listener(0);
}); });
@ -388,22 +391,9 @@ export class Syncer {
SyncType.UPDATE, SyncType.UPDATE,
SyncSource.PUSH, SyncSource.PUSH,
async () => { async () => {
if ( this.logger.debug(
(await this.operations.getFileSize(relativePath)) / `Renaming? oldPath ${oldPath} relativePath ${relativePath}`
1024 / );
1024 >
this.settings.getSettings().maxFileSizeMB
) {
this.history.addHistoryEntry({
status: SyncStatus.ERROR,
relativePath,
message: `File size exceeds the maximum file size limit of ${
this.settings.getSettings().maxFileSizeMB
}MB`,
type: SyncType.CREATE
});
return;
}
const localMetadata = this.database.getDocument( const localMetadata = this.database.getDocument(
oldPath ?? relativePath oldPath ?? relativePath
@ -420,9 +410,27 @@ export class Syncer {
return; return;
} }
throw new Error( this.logger.debug(
`Document metadata not found for ${relativePath}. This implies a corrupt local database. Consider resetting the plugin's sync history.` `Document metadata doesn't exist for ${relativePath}, it must have been already deleted`
); );
return;
}
if (
(await this.operations.getFileSize(relativePath)) /
1024 /
1024 >
this.settings.getSettings().maxFileSizeMB
) {
this.history.addHistoryEntry({
status: SyncStatus.ERROR,
relativePath,
message: `File size exceeds the maximum file size limit of ${
this.settings.getSettings().maxFileSizeMB
}MB`,
type: SyncType.CREATE
});
return;
} }
const contentBytes = const contentBytes =
@ -487,7 +495,7 @@ export class Syncer {
try { try {
if (response.relativePath != relativePath) { if (response.relativePath != relativePath) {
await this.operations.move( await this.operations.move(
oldPath ?? relativePath, relativePath,
response.relativePath response.relativePath
); );
} }
@ -616,7 +624,7 @@ export class Syncer {
status: SyncStatus.SUCCESS, status: SyncStatus.SUCCESS,
source: SyncSource.PULL, source: SyncSource.PULL,
relativePath: remoteVersion.relativePath, relativePath: remoteVersion.relativePath,
message: `Successfully downloaded remote file which hasn't existed locally`, message: `Successfully downloaded remote file which hadn't existed locally`,
type: SyncType.CREATE type: SyncType.CREATE
}); });
return; return;
@ -720,7 +728,9 @@ export class Syncer {
); );
return; return;
} }
this.logger.debug(`Syncing ${relativePath}`); this.logger.debug(
`Syncing ${relativePath} (${syncSource} - ${syncType})`
);
await waitForDocumentLock(relativePath); await waitForDocumentLock(relativePath);
try { try {
@ -752,17 +762,4 @@ export class Syncer {
await this.database.setLastSeenUpdateId(responseVaultUpdateId); await this.database.setLastSeenUpdateId(responseVaultUpdateId);
} }
} }
private async findMatchingFileBasedOnHash(
contentHash: string,
candidates: [RelativePath, DocumentMetadata][]
): Promise<[RelativePath, DocumentMetadata] | undefined> {
if (contentHash != EMPTY_HASH) {
return undefined;
}
return candidates.find(
([_, document]) => document.hash === contentHash
);
}
} }

View file

@ -0,0 +1,13 @@
import { DocumentMetadata, RelativePath } from "src/persistence/database";
import { EMPTY_HASH } from "./hash";
export function findMatchingFileBasedOnHash(
contentHash: string,
candidates: [RelativePath, DocumentMetadata][]
): [RelativePath, DocumentMetadata] | undefined {
if (contentHash != EMPTY_HASH) {
return undefined;
}
return candidates.find(([_, document]) => document.hash === contentHash);
}