1
0

Completion for non-federation federation links

This commit is contained in:
Zef Hemel 2023-08-17 21:58:05 +02:00
parent b043ffaee0
commit 75bdd6390b
2 changed files with 85 additions and 55 deletions

View File

@ -16,6 +16,8 @@ import { applyQuery } from "$sb/lib/query.ts";
import { invokeFunction } from "$sb/silverbullet-syscall/system.ts"; import { invokeFunction } from "$sb/silverbullet-syscall/system.ts";
import type { Message } from "$sb/types.ts"; import type { Message } from "$sb/types.ts";
import { sleep } from "../../common/async_util.ts"; import { sleep } from "../../common/async_util.ts";
import { cacheFileListing } from "../federation/federation.ts";
import type { PageMeta } from "../../web/types.ts";
// Key space: // Key space:
// meta: => metaJson // meta: => metaJson
@ -95,7 +97,28 @@ export async function pageComplete(completeEvent: CompleteEvent) {
if (!match) { if (!match) {
return null; return null;
} }
const allPages = await space.listPages(); let allPages: PageMeta[] = await space.listPages();
const prefix = match[1];
if (prefix.startsWith("!")) {
// Federation prefix, let's first see if we're matching anything from federation that is locally synced
const prefixMatches = allPages.filter((pageMeta) =>
pageMeta.name.startsWith(prefix)
);
if (prefixMatches.length === 0) {
// Ok, nothing synced in via federation, let's see if this URI is complete enough to try to fetch index.json
if (prefix.includes("/")) {
// Yep
const domain = prefix.split("/")[0];
// Cached listing
allPages = (await cacheFileListing(domain)).filter((fm) =>
fm.name.endsWith(".md")
).map((fm) => ({
...fm,
name: fm.name.slice(0, -3),
}));
}
}
}
return { return {
from: completeEvent.pos - match[1].length, from: completeEvent.pos - match[1].length,
options: allPages.map((pageMeta) => { options: allPages.map((pageMeta) => {

View File

@ -43,18 +43,31 @@ export async function listFiles(): Promise<FileMeta[]> {
// Fetch them all in parallel // Fetch them all in parallel
try { try {
await Promise.all((await readFederationConfigs()).map(async (config) => { await Promise.all((await readFederationConfigs()).map(async (config) => {
const items = await cacheFileListing(config.uri);
fileMetas = fileMetas.concat(items);
}));
// console.log("All of em: ", fileMetas);
return fileMetas;
} catch (e: any) {
console.error("Error listing federation files", e);
return [];
}
}
export async function cacheFileListing(uri: string): Promise<FileMeta[]> {
const cachedListing = await store.get( const cachedListing = await store.get(
`${fileListingPrefixCacheKey}${config.uri}`, `${fileListingPrefixCacheKey}${uri}`,
) as FileListingCacheEntry; ) as FileListingCacheEntry;
if ( if (
cachedListing && cachedListing &&
cachedListing.lastUpdated > Date.now() - listingCacheTimeout cachedListing.lastUpdated > Date.now() - listingCacheTimeout
) { ) {
fileMetas = fileMetas.concat(cachedListing.items); // console.info("Using cached listing", cachedListing);
return; return cachedListing.items;
} }
console.log("Fetching listing from federated", config); console.log("Fetching listing from federated", uri);
const uriParts = config.uri.split("/"); const uriParts = uri.split("/");
const rootUri = uriParts[0]; const rootUri = uriParts[0];
const prefix = uriParts.slice(1).join("/"); const prefix = uriParts.slice(1).join("/");
const indexUrl = `${federatedPathToUrl(rootUri)}/index.json`; const indexUrl = `${federatedPathToUrl(rootUri)}/index.json`;
@ -69,6 +82,7 @@ export async function listFiles(): Promise<FileMeta[]> {
method: "GET", method: "GET",
headers: { headers: {
Accept: "application/json", Accept: "application/json",
"Cache-Control": "no-cache",
}, },
signal: fetchController.signal, signal: fetchController.signal,
}); });
@ -82,29 +96,22 @@ export async function listFiles(): Promise<FileMeta[]> {
meta.name.startsWith(prefix) meta.name.startsWith(prefix)
).map((meta: FileMeta) => ({ ).map((meta: FileMeta) => ({
...meta, ...meta,
perm: config.perm || "ro", perm: "ro",
name: `${rootUri}/${meta.name}`, name: `${rootUri}/${meta.name}`,
})); }));
await store.set(`${fileListingPrefixCacheKey}${config.uri}`, { await store.set(`${fileListingPrefixCacheKey}${uri}`, {
items, items,
lastUpdated: Date.now(), lastUpdated: Date.now(),
} as FileListingCacheEntry); } as FileListingCacheEntry);
fileMetas = fileMetas.concat(items); return items;
} catch (e: any) { } catch (e: any) {
console.error("Failed to process", indexUrl, e); console.error("Failed to process", indexUrl, e);
if (cachedListing) { if (cachedListing) {
console.info("Using cached listing"); console.info("Using cached listing");
fileMetas = fileMetas.concat(cachedListing.items); return cachedListing.items;
} }
} }
}));
// console.log("All of em: ", fileMetas);
return fileMetas;
} catch (e: any) {
console.error("Error listing federation files", e);
return []; return [];
}
} }
export async function readFile( export async function readFile(