1
0

Cleanup and federation prep

This commit is contained in:
Zef Hemel 2023-07-30 08:56:44 +02:00
parent fe4887dc78
commit afa160d2c2
7 changed files with 98 additions and 32 deletions

View File

@ -22,15 +22,19 @@ export class FallbackSpacePrimitives implements SpacePrimitives {
try { try {
return await this.primary.readFile(name); return await this.primary.readFile(name);
} catch (e) { } catch (e) {
// console.info( if (e.message === "Not found") {
// `Could not read file ${name} from primary, trying fallback, primary read error:`, console.info("Reading file content from fallback for", name);
// e.message, } else {
// ); console.warn(
`Could not read file ${name} from primary, trying fallback, primary read error`,
e.message,
);
}
try { try {
const result = await this.fallback.readFile(name); const result = await this.fallback.readFile(name);
return { return {
data: result.data, data: result.data,
meta: { ...result.meta, neverSync: true }, meta: { ...result.meta, noSync: true },
}; };
} catch (fallbackError: any) { } catch (fallbackError: any) {
console.error("Error during readFile fallback", fallbackError.message); console.error("Error during readFile fallback", fallbackError.message);
@ -42,14 +46,18 @@ export class FallbackSpacePrimitives implements SpacePrimitives {
async getFileMeta(name: string): Promise<FileMeta> { async getFileMeta(name: string): Promise<FileMeta> {
try { try {
return await this.primary.getFileMeta(name); return await this.primary.getFileMeta(name);
} catch (e) { } catch (e: any) {
// console.info( if (e.message === "Not found") {
// `Could not fetch file ${name} metadata from primary, trying fallback, primary read error`, console.info("Fetching file meta from fallback for", name);
// e.message, } else {
// ); console.warn(
`Could not fetch file ${name} metadata from primary, trying fallback, primary read error`,
e.message,
);
}
try { try {
const meta = await this.fallback.getFileMeta(name); const meta = await this.fallback.getFileMeta(name);
return { ...meta, neverSync: true }; return { ...meta, noSync: true };
} catch (fallbackError) { } catch (fallbackError) {
console.error( console.error(
"Error during getFileMeta fallback", "Error during getFileMeta fallback",

View File

@ -6,5 +6,5 @@ export type FileMeta = {
contentType: string; contentType: string;
size: number; size: number;
perm: "ro" | "rw"; perm: "ro" | "rw";
neverSync?: boolean; noSync?: boolean;
} & Record<string, any>; } & Record<string, any>;

View File

@ -3,7 +3,7 @@ export function resolvePath(
pathToResolve: string, pathToResolve: string,
fullUrl = false, fullUrl = false,
): string { ): string {
if (currentPage.startsWith("!") && !pathToResolve.startsWith("!")) { if (isFederationPath(currentPage) && !isFederationPath(pathToResolve)) {
let domainPart = currentPage.split("/")[0]; let domainPart = currentPage.split("/")[0];
if (fullUrl) { if (fullUrl) {
domainPart = domainPart.substring(1); domainPart = domainPart.substring(1);
@ -18,3 +18,7 @@ export function resolvePath(
return pathToResolve; return pathToResolve;
} }
} }
export function isFederationPath(path: string) {
return path.startsWith("!");
}

View File

@ -1,4 +1,4 @@
import { editor, markdown, space } from "$sb/silverbullet-syscall/mod.ts"; import { editor, markdown, space, sync } from "$sb/silverbullet-syscall/mod.ts";
import { import {
removeParentPointers, removeParentPointers,
renderToText, renderToText,
@ -7,15 +7,29 @@ import {
import { renderDirectives } from "./directives.ts"; import { renderDirectives } from "./directives.ts";
import { extractFrontmatter } from "$sb/lib/frontmatter.ts"; import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { PageMeta } from "../../web/types.ts"; import { PageMeta } from "../../web/types.ts";
import { isFederationPath } from "$sb/lib/resolve.ts";
export async function updateDirectivesOnPageCommand() { export async function updateDirectivesOnPageCommand() {
// If `arg` is a string, it's triggered automatically via an event, not explicitly via a command // If `arg` is a string, it's triggered automatically via an event, not explicitly via a command
const pageMeta = await space.getPageMeta(await editor.getCurrentPage()); const currentPage = await editor.getCurrentPage();
const pageMeta = await space.getPageMeta(currentPage);
const text = await editor.getText(); const text = await editor.getText();
const tree = await markdown.parseMarkdown(text); const tree = await markdown.parseMarkdown(text);
const metaData = await extractFrontmatter(tree, ["$disableDirectives"]); const metaData = await extractFrontmatter(tree, ["$disableDirectives"]);
if (isFederationPath(currentPage)) {
console.info("Current page is a federation page, not updating directives.");
}
if (metaData.$disableDirectives) { if (metaData.$disableDirectives) {
// Not updating, directives disabled console.info("Directives disabled in page meta, not updating them.");
return;
}
if (!(await sync.hasInitialSyncCompleted())) {
console.info(
"Initial sync hasn't completed yet, not updating directives.",
);
return; return;
} }
@ -96,7 +110,6 @@ export async function updateDirectivesOnPageCommand() {
} }
} }
// Pure server driven implementation of directive updating
export async function updateDirectives( export async function updateDirectives(
pageMeta: PageMeta, pageMeta: PageMeta,
text: string, text: string,

View File

@ -35,14 +35,6 @@ export async function directiveDispatcher(
const directiveStartText = renderToText(directiveStart).trim(); const directiveStartText = renderToText(directiveStart).trim();
const directiveEndText = renderToText(directiveEnd).trim(); const directiveEndText = renderToText(directiveEnd).trim();
if (!(await sync.hasInitialSyncCompleted())) {
console.info(
"Initial sync hasn't completed yet, not updating directives.",
);
// Render the query directive as-is
return renderToText(directiveTree);
}
if (directiveStart.children!.length === 1) { if (directiveStart.children!.length === 1) {
// Everything not #query // Everything not #query
const match = directiveStartRegex.exec(directiveStart.children![0].text!); const match = directiveStartRegex.exec(directiveStart.children![0].text!);

View File

@ -1,5 +1,10 @@
import { queryRegex } from "$sb/lib/query.ts"; import { queryRegex } from "$sb/lib/query.ts";
import { ParseTree, renderToText } from "$sb/lib/tree.ts"; import {
findNodeOfType,
ParseTree,
renderToText,
traverseTree,
} from "$sb/lib/tree.ts";
import { markdown, space } from "$sb/silverbullet-syscall/mod.ts"; import { markdown, space } from "$sb/silverbullet-syscall/mod.ts";
import Handlebars from "handlebars"; import Handlebars from "handlebars";
@ -9,6 +14,7 @@ import { directiveRegex } from "./directives.ts";
import { updateDirectives } from "./command.ts"; import { updateDirectives } from "./command.ts";
import { buildHandebarOptions } from "./util.ts"; import { buildHandebarOptions } from "./util.ts";
import { PageMeta } from "../../web/types.ts"; import { PageMeta } from "../../web/types.ts";
import { resolvePath } from "$sb/lib/resolve.ts";
const templateRegex = /\[\[([^\]]+)\]\]\s*(.*)\s*/; const templateRegex = /\[\[([^\]]+)\]\]\s*(.*)\s*/;
@ -24,7 +30,7 @@ export async function templateDirectiveRenderer(
if (!match) { if (!match) {
throw new Error(`Invalid template directive: ${arg}`); throw new Error(`Invalid template directive: ${arg}`);
} }
const template = match[1]; let templatePath = match[1];
const args = match[2]; const args = match[2];
let parsedArgs = {}; let parsedArgs = {};
if (args) { if (args) {
@ -39,20 +45,29 @@ export async function templateDirectiveRenderer(
} }
} }
let templateText = ""; let templateText = "";
if (template.startsWith("http://") || template.startsWith("https://")) { if (
templatePath.startsWith("http://") || templatePath.startsWith("https://")
) {
try { try {
const req = await fetch(template); const req = await fetch(templatePath);
templateText = await req.text(); templateText = await req.text();
} catch (e: any) { } catch (e: any) {
templateText = `ERROR: ${e.message}`; templateText = `ERROR: ${e.message}`;
} }
} else { } else {
templateText = await space.readPage(template); templatePath = resolvePath(pageMeta.name, templatePath);
templateText = await space.readPage(templatePath);
} }
const tree = await markdown.parseMarkdown(templateText); const tree = await markdown.parseMarkdown(templateText);
await extractFrontmatter(tree, [], true); // Remove entire frontmatter section, if any await extractFrontmatter(tree, [], true); // Remove entire frontmatter section, if any
// Resolve paths in the template
rewritePageRefs(tree, templatePath);
let newBody = renderToText(tree); let newBody = renderToText(tree);
// console.log("Rewritten template:", newBody);
// if it's a template injection (not a literal "include") // if it's a template injection (not a literal "include")
if (directive === "use") { if (directive === "use") {
const templateFn = Handlebars.compile( const templateFn = Handlebars.compile(
@ -67,6 +82,40 @@ export async function templateDirectiveRenderer(
return newBody.trim(); return newBody.trim();
} }
function rewritePageRefs(tree: ParseTree, templatePath: string) {
traverseTree(tree, (n): boolean => {
if (n.type === "DirectiveStart") {
const pageRef = findNodeOfType(n, "PageRef")!;
if (pageRef) {
const pageRefName = pageRef.children![0].text!.slice(2, -2);
pageRef.children![0].text = `[[${
resolvePath(templatePath, pageRefName)
}]]`;
}
const directiveText = n.children![0].text;
// #use or #import
if (directiveText) {
const match = /\[\[(.+)\]\]/.exec(directiveText);
if (match) {
const pageRefName = match[1];
n.children![0].text = directiveText.replace(
match[0],
`[[${resolvePath(templatePath, pageRefName)}]]`,
);
}
}
return true;
}
if (n.type === "WikiLinkPage") {
n.children![0].text = resolvePath(templatePath, n.children![0].text!);
return true;
}
return false;
});
}
export function cleanTemplateInstantiations(text: string) { export function cleanTemplateInstantiations(text: string) {
return text.replaceAll(directiveRegex, ( return text.replaceAll(directiveRegex, (
_fullMatch, _fullMatch,

View File

@ -192,9 +192,9 @@ export class SyncService {
let remoteHash: number | undefined; let remoteHash: number | undefined;
try { try {
const localMeta = await this.localSpacePrimitives.getFileMeta(name); const localMeta = await this.localSpacePrimitives.getFileMeta(name);
if (localMeta.neverSync) { if (localMeta.noSync) {
console.info( console.info(
"File marked as neverSync, skipping sync in this cycle", "File marked as no sync, skipping sync in this cycle",
name, name,
); );
await this.registerSyncStop(); await this.registerSyncStop();