From 1520da24b3b80994f0de3ac3969d6316f30402fc Mon Sep 17 00:00:00 2001 From: Brian Broll Date: Sat, 9 Dec 2023 07:39:24 -0600 Subject: [PATCH 1/2] Configure the cloud to connect to via qs This should make development easier since the cloud can then be swapped out in a modular fashion like the browser code. --- utils/serve.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/utils/serve.js b/utils/serve.js index 2bc3cf8c5a..cb0933c424 100644 --- a/utils/serve.js +++ b/utils/serve.js @@ -19,7 +19,7 @@ const isDevMode = ENV !== "production"; writeCloudFile(CLOUD_URL); const file = new nodeStatic.Server(path.join(__dirname, "..")); -const getExampleThumbnail = cached(async function (name) { +const getExampleThumbnail = cached(async function (cloudUrl, name) { console.log("getting thumbnail url for", name); const filepath = path.join( __dirname, @@ -33,7 +33,7 @@ const getExampleThumbnail = cached(async function (name) { "data:image/png;base64,", ); - return CLOUD_URL + + return cloudUrl + `/projects/thumbnail?xml=${encodeURIComponent(thumbnailXml)}`; }); const server = http.createServer(async (req, res) => { @@ -42,6 +42,7 @@ const server = http.createServer(async (req, res) => { .map((url) => url.replace(/#.*$/, "")); const isIndexHtml = url === "/" || url === "/index.html"; console.log(req.url); + if (isIndexHtml) { // dynamically generate the index.html file const query = Object.fromEntries( @@ -50,15 +51,17 @@ const server = http.createServer(async (req, res) => { return [key, decodeURIComponent(value)]; }), ); + const cloudUrl = query.cloud || CLOUD_URL; + const metaInfo = { title: "NetsBlox", description: "Add project notes here...", - cloud: CLOUD_URL, + cloud: cloudUrl, isDevMode, }; if (query.action === "present") { - const url = CLOUD_URL + + const url = cloudUrl + `/projects/user/${query.Username}/${query.ProjectName}/metadata`; const response = await fetch(url); if (response.ok) { @@ -66,14 +69,14 @@ const server = http.createServer(async (req, res) => { // TODO: parse the notes? These should probably be saved separately metaInfo.title = metadata.name; metaInfo.image = { - url: CLOUD_URL + `/projects/id/${metadata.id}/thumbnail`, + url: cloudUrl + `/projects/id/${metadata.id}/thumbnail`, width: 640, height: 480, }; } } else if (query.action === "example" && query.ProjectName) { metaInfo.image = { - url: await getExampleThumbnail(query.ProjectName), + url: await getExampleThumbnail(cloudUrl, query.ProjectName), width: 640, height: 480, }; @@ -95,16 +98,13 @@ console.log("listening on port", port); // Cached function function cached(fn) { const cacheStore = {}; - assert.equal( - fn.length, - 1, - "Only functions accepting a single argument can be cached for now.", - ); - return async function (arg) { - if (!cacheStore[arg]) { - cacheStore[arg] = await fn(arg); + + return async function () { + const key = [...arguments].join("\t"); + if (!cacheStore[key]) { + cacheStore[key] = await fn(...arguments); } - return cacheStore[arg]; + return cacheStore[key]; }; } From 5568192065c51e9e5395ca46732c5844431e4698 Mon Sep 17 00:00:00 2001 From: Brian Broll Date: Tue, 12 Dec 2023 10:14:23 -0600 Subject: [PATCH 2/2] Better error handling if example, project not found --- utils/serve.js | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/utils/serve.js b/utils/serve.js index cb0933c424..c4c9ac72dd 100644 --- a/utils/serve.js +++ b/utils/serve.js @@ -20,7 +20,6 @@ writeCloudFile(CLOUD_URL); const file = new nodeStatic.Server(path.join(__dirname, "..")); const getExampleThumbnail = cached(async function (cloudUrl, name) { - console.log("getting thumbnail url for", name); const filepath = path.join( __dirname, "..", @@ -61,31 +60,42 @@ const server = http.createServer(async (req, res) => { }; if (query.action === "present") { - const url = cloudUrl + - `/projects/user/${query.Username}/${query.ProjectName}/metadata`; - const response = await fetch(url); - if (response.ok) { - const metadata = await response.json(); + try { + const metadata = await getPublicProjectMetadata(cloudUrl, query); // TODO: parse the notes? These should probably be saved separately - metaInfo.title = metadata.name; + if (metadata) { + metaInfo.title = metadata.name; + metaInfo.image = { + url: cloudUrl + `/projects/id/${metadata.id}/thumbnail`, + width: 640, + height: 480, + }; + } + } catch (err) { + console.warn( + `Unable to fetch public project metadata from ${cloudUrl}: ${err.message}`, + ); + } + } else if (query.action === "example" && query.ProjectName) { + try { + const url = await getExampleThumbnail(cloudUrl, query.ProjectName); metaInfo.image = { - url: cloudUrl + `/projects/id/${metadata.id}/thumbnail`, + url, width: 640, height: 480, }; + } catch (err) { + console.warn( + `Unable to fetch example "${query.ProjectName}"`, + ); } - } else if (query.action === "example" && query.ProjectName) { - metaInfo.image = { - url: await getExampleThumbnail(cloudUrl, query.ProjectName), - width: 640, - height: 480, - }; } const userAgent = req.headers["user-agent"]; if (userAgent) { addScraperSettings(userAgent, metaInfo); } + res.writeHead(200); res.end(indexTpl(metaInfo)); } else { @@ -95,6 +105,15 @@ const server = http.createServer(async (req, res) => { server.listen(port); console.log("listening on port", port); +async function getPublicProjectMetadata(cloudUrl, query) { + const url = cloudUrl + + `/projects/user/${query.Username}/${query.ProjectName}/metadata`; + const response = await fetch(url); + if (response.ok) { + return await response.json(); + } +} + // Cached function function cached(fn) { const cacheStore = {};