Add push operations to plugin

This commit is contained in:
Andras Schmelczer 2024-12-12 22:17:59 +00:00
parent a2066cfc1c
commit 9ce8245abc
No known key found for this signature in database
GPG key ID: FC8F2C3D3D1A718C
7 changed files with 78 additions and 53 deletions

View file

@ -90,14 +90,17 @@ export class Database {
relativePath, relativePath,
documentId, documentId,
parentVersionId, parentVersionId,
hash,
}: { }: {
relativePath: RelativePath; relativePath: RelativePath;
documentId: DocumentId; documentId: DocumentId;
parentVersionId: DocumentVersionId; parentVersionId: DocumentVersionId;
hash: string;
}): Promise<void> { }): Promise<void> {
this._documents.set(relativePath, { this._documents.set(relativePath, {
documentId, documentId,
parentVersionId, parentVersionId,
hash,
}); });
await this.save(); await this.save();
} }
@ -107,16 +110,19 @@ export class Database {
relativePath, relativePath,
documentId, documentId,
parentVersionId, parentVersionId,
hash,
}: { }: {
oldRelativePath: RelativePath; oldRelativePath: RelativePath;
relativePath: RelativePath; relativePath: RelativePath;
documentId: DocumentId; documentId: DocumentId;
parentVersionId: DocumentVersionId; parentVersionId: DocumentVersionId;
hash: string;
}): Promise<void> { }): Promise<void> {
this._documents.delete(oldRelativePath); this._documents.delete(oldRelativePath);
this._documents.set(relativePath, { this._documents.set(relativePath, {
documentId, documentId,
parentVersionId, parentVersionId,
hash,
}); });
await this.save(); await this.save();
} }

View file

@ -5,4 +5,5 @@ export type RelativePath = string;
export interface DocumentMetadata { export interface DocumentMetadata {
documentId: DocumentId; documentId: DocumentId;
parentVersionId: DocumentVersionId; parentVersionId: DocumentVersionId;
hash: string;
} }

View file

@ -1,4 +1,4 @@
import * as plugin from "../../../backend/sync_lib/pkg/sync_lib.js"; import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js";
import createClient, { Client } from "openapi-fetch"; import createClient, { Client } from "openapi-fetch";
import type { components, paths } from "./types"; // generated by openapi-typescript import type { components, paths } from "./types"; // generated by openapi-typescript
@ -48,14 +48,13 @@ export class SyncServer {
public async create({ public async create({
relativePath, relativePath,
content, contentBytes,
createdDate, createdDate,
}: { }: {
content: ArrayBuffer; contentBytes: Uint8Array;
relativePath: string; relativePath: string;
createdDate: Date; createdDate: Date;
}): Promise<components["schemas"]["DocumentVersion"]> { }): Promise<components["schemas"]["DocumentVersion"]> {
let contentBytes = new Uint8Array(content);
let response = await this.client.POST("/vaults/{vault_id}/documents", { let response = await this.client.POST("/vaults/{vault_id}/documents", {
params: { params: {
path: { vault_id: SyncServer.VAULT_ID }, path: { vault_id: SyncServer.VAULT_ID },
@ -65,9 +64,8 @@ export class SyncServer {
}, },
}, },
body: { body: {
contentBase64: plugin.bytes_to_base64(contentBytes), contentBase64: lib.bytes_to_base64(contentBytes),
createdDate: createdDate.toISOString(), createdDate: createdDate.toISOString(),
isBinary: plugin.is_binary(contentBytes),
relativePath, relativePath,
}, },
}); });
@ -87,17 +85,15 @@ export class SyncServer {
documentId, documentId,
parentVersionId, parentVersionId,
relativePath, relativePath,
content, contentBytes,
createdDate, createdDate,
}: { }: {
documentId: DocumentId; documentId: DocumentId;
parentVersionId: DocumentVersionId; parentVersionId: DocumentVersionId;
relativePath: string; relativePath: string;
content: ArrayBuffer; contentBytes: Uint8Array;
createdDate: Date; createdDate: Date;
}): Promise<components["schemas"]["DocumentVersion"]> { }): Promise<components["schemas"]["DocumentVersion"]> {
let contentBytes = new Uint8Array(content);
let response = await this.client.PUT( let response = await this.client.PUT(
"/vaults/{vault_id}/documents/{document_id}", "/vaults/{vault_id}/documents/{document_id}",
{ {
@ -113,9 +109,8 @@ export class SyncServer {
}, },
body: { body: {
parentVersionId, parentVersionId,
contentBase64: plugin.bytes_to_base64(contentBytes), contentBase64: lib.bytes_to_base64(contentBytes),
createdDate: createdDate.toISOString(), createdDate: createdDate.toISOString(),
isBinary: plugin.is_binary(contentBytes),
relativePath, relativePath,
}, },
} }

View file

@ -1,4 +1,3 @@
import { TFile } from "obsidian";
import { Database } from "src/database/database"; import { Database } from "src/database/database";
import { RelativePath } from "src/database/document-metadata"; import { RelativePath } from "src/database/document-metadata";
import { SyncServer } from "src/services/sync_service"; import { SyncServer } from "src/services/sync_service";
@ -15,7 +14,8 @@ export async function syncLocallyDeletedFile(
await syncServer.delete({ await syncServer.delete({
documentId: metadata.documentId, documentId: metadata.documentId,
createdDate: new Date(), // We got the event now, so it must have been deleted now // We got the event now, so it must have been deleted just now
createdDate: new Date(),
}); });
await database.removeDocument(path); await database.removeDocument(path);

View file

@ -1,6 +1,9 @@
import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js";
import { TFile } from "obsidian"; import { TFile } from "obsidian";
import { Database } from "src/database/database"; import { Database } from "src/database/database";
import { Logger } from "src/logger";
import { SyncServer } from "src/services/sync_service"; import { SyncServer } from "src/services/sync_service";
import { hash } from "src/utils";
export async function syncLocallyRenamedFile( export async function syncLocallyRenamedFile(
database: Database, database: Database,
@ -13,18 +16,42 @@ export async function syncLocallyRenamedFile(
throw `Document metadata not found for ${oldPath}`; throw `Document metadata not found for ${oldPath}`;
} }
const response = await syncServer.update({ const contentBytes = new Uint8Array(await file.vault.readBinary(file));
const responsePromise = syncServer.update({
documentId: metadata.documentId, documentId: metadata.documentId,
parentVersionId: metadata.parentVersionId, parentVersionId: metadata.parentVersionId,
relativePath: file.path, relativePath: file.path,
content: await file.vault.readBinary(file), contentBytes,
createdDate: new Date(file.stat.ctime), createdDate: new Date(file.stat.ctime),
}); });
await database.moveDocument({ const contentHash = hash(contentBytes);
const response = await responsePromise;
const localDbUpdatePromise = database.moveDocument({
oldRelativePath: oldPath, oldRelativePath: oldPath,
relativePath: file.path, relativePath: file.path,
documentId: response.documentId, documentId: response.documentId,
parentVersionId: response.versionId, parentVersionId: response.versionId,
hash: contentHash,
}); });
if (file.path !== response.relativePath) {
await file.vault.rename(file, response.relativePath);
}
const newContentBytes = new Uint8Array(await file.vault.readBinary(file));
const responseBytes = lib.base64_to_bytes(response.contentBase64);
if (contentBytes !== newContentBytes) {
Logger.getInstance().info(
`Content changed since sending original update request for ${file.path}`
);
const result = lib.merge(contentBytes, newContentBytes, responseBytes);
await file.vault.modifyBinary(file, result);
}
await localDbUpdatePromise;
} }

View file

@ -1,36 +1,13 @@
import { TFile } from "obsidian"; import { TFile } from "obsidian";
import { Database } from "src/database/database"; import { Database } from "src/database/database";
import { SyncServer } from "src/services/sync_service"; import { SyncServer } from "src/services/sync_service";
import { hash } from "src/utils";
import { syncLocallyRenamedFile } from "./sync-locally-renamed-file";
export async function syncLocallyUpdatedFile( export async function syncLocallyUpdatedFile(
database: Database, database: Database,
syncServer: SyncServer, syncServer: SyncServer,
file: TFile file: TFile
) { ) {
const metadata = database.getDocument(file.path); syncLocallyRenamedFile(database, syncServer, file, file.path);
if (!metadata) {
throw `Document metadata not found for ${file.path}`;
}
const response = await syncServer.update({
documentId: metadata.documentId,
parentVersionId: metadata.parentVersionId,
relativePath: file.path,
content: await file.vault.readBinary(file),
createdDate: new Date(file.stat.ctime),
});
if (file.path !== response.relativePath) {
file.vault.rename(file, response.relativePath);
}
if ((await file.vault.read(file)) !== response.contentBase64) {
// todo - reconcile
}
await database.setDocument({
relativePath: file.path,
documentId: response.documentId,
parentVersionId: response.versionId,
});
} }

View file

@ -1,29 +1,48 @@
import * as lib from "../../../backend/sync_lib/pkg/sync_lib.js";
import { TFile } from "obsidian"; import { TFile } from "obsidian";
import { Database } from "src/database/database"; import { Database } from "src/database/database";
import { Logger } from "src/logger.js";
import { SyncServer } from "src/services/sync_service"; import { SyncServer } from "src/services/sync_service";
import { hash } from "src/utils";
export async function syncNewLocalFile( export async function syncNewLocalFile(
database: Database, database: Database,
syncServer: SyncServer, syncServer: SyncServer,
file: TFile file: TFile
) { ) {
const response = await syncServer.create({ const contentBytes = new Uint8Array(await file.vault.readBinary(file));
const responsePromise = syncServer.create({
relativePath: file.path, relativePath: file.path,
content: await file.vault.readBinary(file), contentBytes,
createdDate: new Date(file.stat.ctime), createdDate: new Date(file.stat.ctime),
}); });
if (file.path !== response.relativePath) { const contentHash = hash(contentBytes);
file.vault.rename(file, response.relativePath); const response = await responsePromise;
}
if ((await file.vault.read(file)) !== response.contentBase64) { const localDbUpdatePromise = database.setDocument({
// todo - reconcile
}
await database.setDocument({
relativePath: response.relativePath, relativePath: response.relativePath,
documentId: response.documentId, documentId: response.documentId,
parentVersionId: response.versionId, parentVersionId: response.versionId,
hash: contentHash,
}); });
if (file.path !== response.relativePath) {
await file.vault.rename(file, response.relativePath);
}
const newContentBytes = new Uint8Array(await file.vault.readBinary(file));
const responseBytes = lib.base64_to_bytes(response.contentBase64);
if (contentBytes !== newContentBytes) {
Logger.getInstance().info(
`Content changed since sending original create request for ${file.path}`
);
const result = lib.merge(contentBytes, newContentBytes, responseBytes);
await file.vault.modifyBinary(file, result);
}
await localDbUpdatePromise;
} }