From 1a1b942f924af1442c4e8fa58c13780259a108ca Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Fri, 26 May 2023 14:04:32 +0200 Subject: [PATCH] No longer serialize binary blobs as data URLs --- plug-api/silverbullet-syscall/space.ts | 8 ++-- plugs/core/navigate.ts | 3 -- plugs/core/plugmanager.ts | 3 +- plugs/markdown/markdown_render.ts | 18 ++++----- plugs/markdown/preview.ts | 11 ++--- web/cm_plugins/editor_paste.ts | 2 +- web/cm_plugins/table.ts | 14 ++----- web/service_worker.ts | 1 - web/space.ts | 56 +++++--------------------- web/syscalls/space.ts | 12 +++--- 10 files changed, 34 insertions(+), 94 deletions(-) diff --git a/plug-api/silverbullet-syscall/space.ts b/plug-api/silverbullet-syscall/space.ts index c6e4f497..5c9a53de 100644 --- a/plug-api/silverbullet-syscall/space.ts +++ b/plug-api/silverbullet-syscall/space.ts @@ -42,23 +42,21 @@ export function getAttachmentMeta(name: string): Promise { */ export function readAttachment( name: string, -): Promise { +): Promise<{ data: Uint8Array; meta: AttachmentMeta }> { return syscall("space.readAttachment", name); } /** * Writes an attachment to the space * @param name path of the attachment to write - * @param encoding encoding of the data ("utf8" or "dataurl) * @param data data itself * @returns */ export function writeAttachment( name: string, - encoding: "utf8" | "dataurl", - data: string, + data: Uint8Array, ): Promise { - return syscall("space.writeAttachment", name, encoding, data); + return syscall("space.writeAttachment", name, data); } /** diff --git a/plugs/core/navigate.ts b/plugs/core/navigate.ts index 83671db2..6461867f 100644 --- a/plugs/core/navigate.ts +++ b/plugs/core/navigate.ts @@ -77,9 +77,6 @@ async function actionClickOrActionEnter( } if (url.indexOf("://") === -1 && !url.startsWith("mailto:")) { url = decodeURIComponent(url); - // // attachment URL, let's fetch as a data url - // const dataUrl = await space.readAttachment(url); - // return editor.downloadFile(url, dataUrl); return editor.openUrl(`/.fs/${url}`); } else { await editor.openUrl(url); diff --git a/plugs/core/plugmanager.ts b/plugs/core/plugmanager.ts index ba9d47cb..d8fa4513 100644 --- a/plugs/core/plugmanager.ts +++ b/plugs/core/plugmanager.ts @@ -57,8 +57,7 @@ export async function updatePlugsCommand() { // console.log("Writing", `_plug/${plugName}.plug.js`, workerCode); await space.writeAttachment( `_plug/${plugName}.plug.js`, - "utf8", - workerCode, + new TextEncoder().encode(workerCode), ); } diff --git a/plugs/markdown/markdown_render.ts b/plugs/markdown/markdown_render.ts index 78e21734..79558644 100644 --- a/plugs/markdown/markdown_render.ts +++ b/plugs/markdown/markdown_render.ts @@ -12,7 +12,7 @@ type MarkdownRenderOptions = { annotationPositions?: true; attachmentUrlPrefix?: string; // When defined, use to inline images as data: urls - inlineAttachments?: (url: string) => Promise; + inlineAttachments?: (url: string) => string; }; function cleanTags(values: (Tag | null)[]): Tag[] { @@ -364,34 +364,34 @@ function render( } } -async function traverseTag( +function traverseTag( t: Tag, - fn: (t: Tag) => Promise, -): Promise { - await fn(t); + fn: (t: Tag) => void, +) { + fn(t); if (typeof t === "string") { return; } if (t.body) { for (const child of t.body) { - await traverseTag(child, fn); + traverseTag(child, fn); } } } -export async function renderMarkdownToHtml( +export function renderMarkdownToHtml( t: ParseTree, options: MarkdownRenderOptions = {}, ) { preprocess(t, options); const htmlTree = posPreservingRender(t, options); if (htmlTree && options.inlineAttachments) { - await traverseTag(htmlTree, async (t) => { + traverseTag(htmlTree, (t) => { if (typeof t === "string") { return; } if (t.name === "img") { - t.attrs!.src = await options.inlineAttachments!(t.attrs!.src!); + t.attrs!.src = options.inlineAttachments!(t.attrs!.src!); } }); } diff --git a/plugs/markdown/preview.ts b/plugs/markdown/preview.ts index d249974d..e6525747 100644 --- a/plugs/markdown/preview.ts +++ b/plugs/markdown/preview.ts @@ -12,17 +12,12 @@ export async function updateMarkdownPreview() { // const cleanMd = await cleanMarkdown(text); const css = await asset.readAsset("assets/styles.css"); const js = await asset.readAsset("assets/handler.js"); - const html = await renderMarkdownToHtml(mdTree, { + const html = renderMarkdownToHtml(mdTree, { smartHardBreak: true, annotationPositions: true, - inlineAttachments: async (url): Promise => { + inlineAttachments: (url) => { if (!url.includes("://")) { - try { - return await space.readAttachment(url); - } catch (e: any) { - console.error(e); - return url; - } + return `/.fs/${url}`; } return url; }, diff --git a/web/cm_plugins/editor_paste.ts b/web/cm_plugins/editor_paste.ts index a5b6e21f..9e3c41e2 100644 --- a/web/cm_plugins/editor_paste.ts +++ b/web/cm_plugins/editor_paste.ts @@ -180,7 +180,7 @@ export function attachmentExtension(editor: Editor) { if (!finalFileName) { return; } - await editor.space.writeAttachment(finalFileName, "arraybuffer", data!); + await editor.space.writeAttachment(finalFileName, new Uint8Array(data)); let attachmentMarkdown = `[${finalFileName}](${ encodeURIComponent(finalFileName) })`; diff --git a/web/cm_plugins/table.ts b/web/cm_plugins/table.ts index 25cde0eb..358e3575 100644 --- a/web/cm_plugins/table.ts +++ b/web/cm_plugins/table.ts @@ -33,24 +33,16 @@ class TableViewWidget extends WidgetType { }); }); - renderMarkdownToHtml(this.t, { + dom.innerHTML = renderMarkdownToHtml(this.t, { // Annotate every element with its position so we can use it to put // the cursor there when the user clicks on the table. annotationPositions: true, - inlineAttachments: async (url): Promise => { + inlineAttachments: (url) => { if (!url.includes("://")) { - try { - const d = await this.editor.space.readAttachment(url, "dataurl"); - return d.data as string; - } catch (e: any) { - console.error(e); - return url; - } + return `/.fs/${url}`; } return url; }, - }).then((html) => { - dom.innerHTML = html; }); return dom; } diff --git a/web/service_worker.ts b/web/service_worker.ts index 0cca5bc2..b61bd457 100644 --- a/web/service_worker.ts +++ b/web/service_worker.ts @@ -3,7 +3,6 @@ import { mime } from "https://deno.land/x/mimetypes@v1.0.0/mod.ts"; import type { FileContent } from "../common/spaces/indexeddb_space_primitives.ts"; import { simpleHash } from "../common/crypto.ts"; -import { clientStore } from "../plug-api/silverbullet-syscall/mod.ts"; const CACHE_NAME = "{{CACHE_NAME}}"; diff --git a/web/space.ts b/web/space.ts index d5ae68ed..20014b81 100644 --- a/web/space.ts +++ b/web/space.ts @@ -10,9 +10,6 @@ import { import { mime } from "./deps.ts"; import { AttachmentMeta, PageMeta } from "./types.ts"; -export type FileEncoding = "utf8" | "arraybuffer" | "dataurl"; -export type FileData = ArrayBuffer | string; - export type SpaceEvents = { pageCreated: (meta: PageMeta) => void; pageChanged: (meta: PageMeta) => void; @@ -190,31 +187,12 @@ export class Space extends EventEmitter { /** * Reads an attachment * @param name path of the attachment - * @param encoding how the return value is expected to be encoded * @returns */ - async readAttachment( + readAttachment( name: string, - encoding: FileEncoding, - ): Promise<{ data: FileData; meta: AttachmentMeta }> { - const { data, meta } = await this.spacePrimitives.readFile(name); - switch (encoding) { - case "arraybuffer": - return { data, meta }; - case "dataurl": - return { - data: base64EncodedDataUrl( - mime.getType(name) || "application/octet-stream", - data, - ), - meta, - }; - case "utf8": - return { - data: new TextDecoder().decode(data), - meta, - }; - } + ): Promise<{ data: Uint8Array; meta: AttachmentMeta }> { + return this.spacePrimitives.readFile(name); } getAttachmentMeta(name: string): Promise { @@ -223,30 +201,14 @@ export class Space extends EventEmitter { writeAttachment( name: string, - encoding: FileEncoding, - data: FileData, + data: Uint8Array, selfUpdate?: boolean | undefined, ): Promise { - switch (encoding) { - case "arraybuffer": - return this.spacePrimitives.writeFile( - name, - data as Uint8Array, - selfUpdate, - ); - case "dataurl": - return this.spacePrimitives.writeFile( - name, - base64DecodeDataUrl(data as string), - selfUpdate, - ); - case "utf8": - return this.spacePrimitives.writeFile( - name, - new TextEncoder().encode(data as string), - selfUpdate, - ); - } + return this.spacePrimitives.writeFile( + name, + data as Uint8Array, + selfUpdate, + ); } deleteAttachment(name: string): Promise { diff --git a/web/syscalls/space.ts b/web/syscalls/space.ts index 9d520e2f..83d26a9b 100644 --- a/web/syscalls/space.ts +++ b/web/syscalls/space.ts @@ -1,7 +1,6 @@ import { Editor } from "../editor.tsx"; import { SysCallMapping } from "../../plugos/system.ts"; import { AttachmentMeta, PageMeta } from "../types.ts"; -import { FileData, FileEncoding } from "../space.ts"; export function spaceSyscalls(editor: Editor): SysCallMapping { const space = editor.space; @@ -44,8 +43,8 @@ export function spaceSyscalls(editor: Editor): SysCallMapping { "space.readAttachment": async ( _ctx, name: string, - ): Promise => { - return (await space.readAttachment(name, "dataurl")).data; + ): Promise => { + return (await space.readAttachment(name)).data; }, "space.getAttachmentMeta": async ( _ctx, @@ -53,13 +52,12 @@ export function spaceSyscalls(editor: Editor): SysCallMapping { ): Promise => { return await space.getAttachmentMeta(name); }, - "space.writeAttachment": async ( + "space.writeAttachment": ( _ctx, name: string, - encoding: FileEncoding, - data: string, + data: Uint8Array, ): Promise => { - return await space.writeAttachment(name, encoding, data); + return space.writeAttachment(name, data); }, "space.deleteAttachment": async (_ctx, name: string) => { await space.deleteAttachment(name);