vault-link/plugin/src/sync-operations/apply-local-changes-remotely.ts

131 lines
3.1 KiB
TypeScript

import { Database } from "../database/database";
import { SyncService } from "../services/sync_service";
import { Logger } from "../logger";
import { FileOperations } from "../file-operations/file-operations";
import { syncLocallyCreatedFile } from "./sync-locally-created-file";
import { EMPTY_HASH, hash } from "src/utils/hash";
import { syncLocallyUpdatedFile } from "./sync-locally-updated-file";
import { syncLocallyDeletedFile } from "./sync-locally-deleted-file";
import { Notice } from "obsidian";
import PQueue from "p-queue";
let isRunning = false;
export interface Progress {
processedFiles: number;
totalFiles: number;
}
export async function applyLocalChangesRemotely(
database: Database,
syncServer: SyncService,
operations: FileOperations
) {
console.log("applyLocalChangesRemotely");
if (isRunning) {
Logger.getInstance().info("Push sync already in progress, skipping");
return;
}
let tasks: Promise<void>[] = [];
const allLocalFiles = await operations.listAllFiles();
console.log(allLocalFiles);
const deletedFiles = [...database.getDocuments().entries()].filter(
([path, _]) => !allLocalFiles.includes(path)
);
console.log(deletedFiles);
const promiseQueue = new PQueue({
concurrency: 1,
});
await Promise.all(
allLocalFiles.map((path) =>
promiseQueue.add(async () => {
const syncedState = database.getDocument(path);
if (!syncedState) {
Logger.getInstance().info(
`Document ${path} not found in database`
);
const contentHash = hash(await operations.read(path));
if (contentHash != EMPTY_HASH) {
const match = deletedFiles.find(
([path, doc]) => doc.hash === contentHash
);
if (match) {
const oldPath = match[0];
Logger.getInstance().info(
`Document ${path} found remotely under a different path (${oldPath}), moving`
);
tasks.push(
syncLocallyUpdatedFile({
database,
syncServer,
operations,
oldPath,
filePath: path,
updateTime:
await operations.getModificationTime(
path
),
})
);
deletedFiles.remove(match);
return;
}
}
tasks.push(
syncLocallyCreatedFile({
database,
syncServer,
operations,
updateTime: await operations.getModificationTime(
path
),
filePath: path,
})
);
return;
}
const content = await operations.read(path);
if (syncedState.hash !== hash(content)) {
Logger.getInstance().info(
`Document ${path} has local changes, updating`
);
tasks.push(
syncLocallyUpdatedFile({
database,
syncServer,
operations,
filePath: path,
updateTime: await operations.getModificationTime(
path
),
})
);
return;
}
})
)
);
deletedFiles.forEach(([relativePath, _]) => {
Logger.getInstance().info(
`Document ${relativePath} deleted locally, deleting`
);
tasks.push(
syncLocallyDeletedFile({
database,
syncServer,
relativePath,
})
);
});
await Promise.all(tasks);
new Notice("Local changes synced remotely");
}