Sync engine (#298)

Fixes #261
This commit is contained in:
Zef Hemel
2023-01-13 15:41:29 +01:00
committed by GitHub
parent de6f531e91
commit a56e14bff1
51 changed files with 1033 additions and 1418 deletions
+2 -2
View File
@@ -136,8 +136,8 @@ export async function readFileCollab(
const text = `---\n$share: ${collabUri}\n---\n`;
return {
// encoding === "arraybuffer" is not an option, so either it's "string" or "dataurl"
data: encoding === "string" ? text : base64EncodedDataUrl(
// encoding === "arraybuffer" is not an option, so either it's "utf8" or "dataurl"
data: encoding === "utf8" ? text : base64EncodedDataUrl(
"text/markdown",
new TextEncoder().encode(text),
),
+1 -1
View File
@@ -45,7 +45,7 @@ export async function readFileCloud(
`${pagePrefix}${originalUrl.split("/")[0]}/`,
);
return {
data: encoding === "string" ? text : base64EncodedDataUrl(
data: encoding === "utf8" ? text : base64EncodedDataUrl(
"text/markdown",
new TextEncoder().encode(text),
),
+1 -3
View File
@@ -1,9 +1,7 @@
import { events } from "$sb/plugos-syscall/mod.ts";
import type { Manifest } from "../../common/manifest.ts";
import { editor, space, system } from "$sb/silverbullet-syscall/mod.ts";
import { readYamlPage } from "$sb/lib/yaml_page.ts";
import { writePage } from "$sb/silverbullet-syscall/space.ts";
const plugsPrelude =
"This file lists all plugs that SilverBullet will load. Run the {[Plugs: Update]} command to update and reload this list of plugs.\n\n";
@@ -82,7 +80,7 @@ export async function updatePlugs() {
// console.log("Writing", `_plug/${manifest.name}`);
await space.writeAttachment(
`_plug/${manifest.name}.plug.json`,
"string",
"utf8",
JSON.stringify(manifest),
);
}
+2 -2
View File
@@ -85,8 +85,8 @@ export async function readFileSearch(
`;
return {
// encoding === "arraybuffer" is not an option, so either it's "string" or "dataurl"
data: encoding === "string" ? text : base64EncodedDataUrl(
// encoding === "arraybuffer" is not an option, so either it's "utf8" or "dataurl"
data: encoding === "utf8" ? text : base64EncodedDataUrl(
"text/markdown",
new TextEncoder().encode(text),
),
+3 -3
View File
@@ -24,14 +24,14 @@ functions:
path: "./preview.ts:previewClickHandler"
env: client
events:
- preview:click
- preview:click
# $share: file:* publisher for markdown files
sharePublisher:
path: ./share.ts:sharePublisher
events:
- share:file
- share:file
markdownWidget:
path: ./widget.ts:markdownWidget
codeWidget: markdown
codeWidget: markdown
+4 -2
View File
@@ -1,5 +1,5 @@
import { markdown, space } from "$sb/silverbullet-syscall/mod.ts";
import { fs } from "$sb/plugos-syscall/mod.ts";
import { LocalFileSystem } from "$sb/plugos-syscall/mod.ts";
import { asset } from "$sb/plugos-syscall/mod.ts";
import { renderMarkdownToHtml } from "./markdown_render.ts";
import { PublishEvent } from "$sb/app_event.ts";
@@ -10,12 +10,14 @@ export async function sharePublisher(event: PublishEvent) {
const text = await space.readPage(pageName);
const tree = await markdown.parseMarkdown(text);
const rootFS = new LocalFileSystem("");
const css = await asset.readAsset("assets/styles.css");
const markdownHtml = renderMarkdownToHtml(tree, {
smartHardBreak: true,
});
const html =
`<html><head><style>${css}</style></head><body><div id="root">${markdownHtml}</div></body></html>`;
await fs.writeFile(path, html, "utf8");
await rootFS.writeFile(path, html, "utf8");
return true;
}
+19
View File
@@ -0,0 +1,19 @@
name: sync
functions:
configureCommand:
path: sync.ts:configureCommand
command:
name: "Sync: Configure"
syncCommand:
path: sync.ts:syncCommand
command:
name: "Sync: Sync"
check:
env: server
path: sync.ts:check
performSync:
env: server
path: sync.ts:performSync
+88
View File
@@ -0,0 +1,88 @@
import { store } from "$sb/plugos-syscall/mod.ts";
import { editor, sync, system } from "$sb/silverbullet-syscall/mod.ts";
import type { SyncEndpoint } from "$sb/silverbullet-syscall/sync.ts";
export async function configureCommand() {
const url = await editor.prompt(
"Enter the URL of the remote space to sync with",
"https://",
);
if (!url) {
return;
}
const user = await editor.prompt("Username (if any):");
let password = undefined;
if (user) {
password = await editor.prompt("Password:");
}
const syncConfig: SyncEndpoint = {
url,
user,
password,
};
try {
await system.invokeFunction("server", "check", syncConfig);
} catch (e: any) {
await editor.flashNotification(
`Sync configuration failed: ${e.message}`,
"error",
);
return;
}
await store.batchSet([
{ key: "sync.config", value: syncConfig },
// Empty initial snapshot
{ key: "sync.snapshot", value: {} },
]);
await editor.flashNotification("Sync configuration saved.");
return syncConfig;
}
export async function syncCommand() {
let config: SyncEndpoint | undefined = await store.get("sync.config");
if (!config) {
config = await configureCommand();
if (!config) {
return;
}
}
await editor.flashNotification("Starting sync...");
try {
const operations = await system.invokeFunction("server", "performSync");
await editor.flashNotification(
`Sync complete. Performed ${operations} operations.`,
);
} catch (e: any) {
await editor.flashNotification(
`Sync failed: ${e.message}`,
"error",
);
}
}
// Run on server
export function check(config: SyncEndpoint) {
return sync.check(config);
}
// Run on server
export async function performSync() {
const config: SyncEndpoint = await store.get("sync.config");
const snapshot = await store.get("sync.snapshot");
const { snapshot: newSnapshot, operations, error } = await sync.sync(
config,
snapshot,
);
await store.set("sync.snapshot", newSnapshot);
if (error) {
console.error("Sync error", error);
throw new Error(error);
}
return operations;
}