Store manifest in memory so it does not need to be generated for every page request (#1433)

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
SleeplessOne1917 2023-06-21 11:55:27 +00:00 committed by GitHub
parent 638ab2c462
commit 3db4fdddcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 56 deletions

View file

@ -0,0 +1,28 @@
import type { Request, Response } from "express";
import { LemmyHttp } from "lemmy-js-client";
import { getHttpBaseInternal } from "../../shared/env";
import { wrapClient } from "../../shared/services/HttpService";
import generateManifestJson from "../utils/generate-manifest-json";
import { setForwardedHeaders } from "../utils/set-forwarded-headers";
let manifest: Awaited<ReturnType<typeof generateManifestJson>> | undefined =
undefined;
export default async (req: Request, res: Response) => {
if (!manifest) {
const headers = setForwardedHeaders(req.headers);
const client = wrapClient(new LemmyHttp(getHttpBaseInternal(), headers));
const site = await client.getSite({});
if (site.state === "success") {
manifest = await generateManifestJson(site.data);
} else {
res.sendStatus(500);
return;
}
}
res.setHeader("content-type", "application/manifest+json");
res.send(manifest);
};

View file

@ -2,6 +2,7 @@ import express from "express";
import path from "path"; import path from "path";
import process from "process"; import process from "process";
import CatchAllHandler from "./handlers/catch-all-handler"; import CatchAllHandler from "./handlers/catch-all-handler";
import ManifestHandler from "./handlers/manifest-handler";
import RobotsHandler from "./handlers/robots-handler"; import RobotsHandler from "./handlers/robots-handler";
import ServiceWorkerHandler from "./handlers/service-worker-handler"; import ServiceWorkerHandler from "./handlers/service-worker-handler";
import ThemeHandler from "./handlers/theme-handler"; import ThemeHandler from "./handlers/theme-handler";
@ -24,6 +25,7 @@ if (!process.env["LEMMY_UI_DISABLE_CSP"] && !process.env["LEMMY_UI_DEBUG"]) {
server.get("/robots.txt", RobotsHandler); server.get("/robots.txt", RobotsHandler);
server.get("/service-worker.js", ServiceWorkerHandler); server.get("/service-worker.js", ServiceWorkerHandler);
server.get("/manifest", ManifestHandler);
server.get("/css/themes/:name", ThemeHandler); server.get("/css/themes/:name", ThemeHandler);
server.get("/css/themelist", ThemesListHandler); server.get("/css/themelist", ThemesListHandler);
server.get("/*", CatchAllHandler); server.get("/*", CatchAllHandler);

View file

@ -5,32 +5,35 @@ import sharp from "sharp";
import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces"; import { ILemmyConfig, IsoDataOptionalSite } from "../../shared/interfaces";
import { favIconPngUrl, favIconUrl } from "../../shared/utils"; import { favIconPngUrl, favIconUrl } from "../../shared/utils";
import { fetchIconPng } from "./fetch-icon-png"; import { fetchIconPng } from "./fetch-icon-png";
import { generateManifestBase64 } from "./generate-manifest-base64";
const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || ""; const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
let appleTouchIcon: string | undefined = undefined;
export async function createSsrHtml( export async function createSsrHtml(
root: string, root: string,
isoData: IsoDataOptionalSite isoData: IsoDataOptionalSite
) { ) {
const site = isoData.site_res; const site = isoData.site_res;
const appleTouchIcon = site?.site_view.site.icon if (!appleTouchIcon) {
? `data:image/png;base64,${sharp( appleTouchIcon = site?.site_view.site.icon
await fetchIconPng(site.site_view.site.icon) ? `data:image/png;base64,${sharp(
) await fetchIconPng(site.site_view.site.icon)
.resize(180, 180) )
.extend({ .resize(180, 180)
bottom: 20, .extend({
top: 20, bottom: 20,
left: 20, top: 20,
right: 20, left: 20,
background: "#222222", right: 20,
}) background: "#222222",
.png() })
.toBuffer() .png()
.then(buf => buf.toString("base64"))}` .toBuffer()
: favIconPngUrl; .then(buf => buf.toString("base64"))}`
: favIconPngUrl;
}
const erudaStr = const erudaStr =
process.env["LEMMY_UI_DEBUG"] === "true" process.env["LEMMY_UI_DEBUG"] === "true"
@ -74,15 +77,7 @@ export async function createSsrHtml(
/> />
<!-- Web app manifest --> <!-- Web app manifest -->
${ <link rel="manifest" href="/manifest" />
site &&
`<link
rel="manifest"
href=${`data:application/manifest+json;base64,${await generateManifestBase64(
site
)}`}
/>`
}
<link rel="apple-touch-icon" href=${appleTouchIcon} /> <link rel="apple-touch-icon" href=${appleTouchIcon} />
<link rel="apple-touch-startup-image" href=${appleTouchIcon} /> <link rel="apple-touch-startup-image" href=${appleTouchIcon} />

View file

@ -5,7 +5,7 @@ import sharp from "sharp";
import { getHttpBaseExternal } from "../../shared/env"; import { getHttpBaseExternal } from "../../shared/env";
import { fetchIconPng } from "./fetch-icon-png"; import { fetchIconPng } from "./fetch-icon-png";
const iconSizes = [72, 96, 144, 192, 512]; const iconSizes = [72, 96, 128, 144, 152, 192, 384, 512];
const defaultLogoPathDirectory = path.join( const defaultLogoPathDirectory = path.join(
process.cwd(), process.cwd(),
@ -14,7 +14,7 @@ const defaultLogoPathDirectory = path.join(
"icons" "icons"
); );
export async function generateManifestBase64({ export default async function ({
my_user, my_user,
site_view: { site_view: {
site, site,
@ -25,7 +25,7 @@ export async function generateManifestBase64({
const icon = site.icon ? await fetchIconPng(site.icon) : null; const icon = site.icon ? await fetchIconPng(site.icon) : null;
const manifest = { return {
name: site.name, name: site.name,
description: site.description ?? "A link aggregator for the fediverse", description: site.description ?? "A link aggregator for the fediverse",
start_url: url, start_url: url,
@ -69,31 +69,24 @@ export async function generateManifestBase64({
short_name: "Communities", short_name: "Communities",
description: "Browse communities", description: "Browse communities",
}, },
] {
.concat( name: "Create Post",
my_user url: "/create_post",
? [ short_name: "Create Post",
{ description: "Create a post.",
name: "Create Post", },
url: "/create_post", ].concat(
short_name: "Create Post", my_user?.local_user_view.person.admin || !community_creation_admin_only
description: "Create a post.", ? [
}, {
] name: "Create Community",
: [] url: "/create_community",
) short_name: "Create Community",
.concat( description: "Create a community",
my_user?.local_user_view.person.admin || !community_creation_admin_only },
? [ ]
{ : []
name: "Create Community", ),
url: "/create_community",
short_name: "Create Community",
description: "Create a community",
},
]
: []
),
related_applications: [ related_applications: [
{ {
platform: "f-droid", platform: "f-droid",
@ -102,6 +95,4 @@ export async function generateManifestBase64({
}, },
], ],
}; };
return Buffer.from(JSON.stringify(manifest)).toString("base64");
} }