Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/tidy server #1322

Merged
merged 17 commits into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions src/server/handlers/catch-all-handler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type { Request, Response } from "express";
import { StaticRouter, matchPath } from "inferno-router";
import { renderToString } from "inferno-server";
import IsomorphicCookie from "isomorphic-cookie";
import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
import { App } from "../../shared/components/app/app";
import { getHttpBaseInternal } from "../../shared/env";
import {
InitialFetchRequest,
IsoDataOptionalSite,
RouteData,
} from "../../shared/interfaces";
import { routes } from "../../shared/routes";
import {
FailedRequestState,
wrapClient,
} from "../../shared/services/HttpService";
import { ErrorPageData, initializeSite, isAuthPath } from "../../shared/utils";
import { createSsrHtml } from "../utils/create-ssr-html";
import { getErrorPageData } from "../utils/get-error-page-data";
import { setForwardedHeaders } from "../utils/set-forwarded-headers";

export default async (req: Request, res: Response) => {
try {
const activeRoute = routes.find(route => matchPath(req.path, route));
let auth: string | undefined = IsomorphicCookie.load("jwt", req);

const getSiteForm: GetSite = { auth };

const headers = setForwardedHeaders(req.headers);
const client = wrapClient(new LemmyHttp(getHttpBaseInternal(), headers));

const { path, url, query } = req;

// Get site data first
// This bypasses errors, so that the client can hit the error on its own,
// in order to remove the jwt on the browser. Necessary for wrong jwts
let site: GetSiteResponse | undefined = undefined;
let routeData: RouteData = {};
let errorPageData: ErrorPageData | undefined = undefined;
let try_site = await client.getSite(getSiteForm);
if (try_site.state === "failed" && try_site.msg == "not_logged_in") {
console.error(
"Incorrect JWT token, skipping auth so frontend can remove jwt cookie"
);
getSiteForm.auth = undefined;
auth = undefined;
try_site = await client.getSite(getSiteForm);
}

if (!auth && isAuthPath(path)) {
return res.redirect("/login");
}

if (try_site.state === "success") {
site = try_site.data;
initializeSite(site);

if (path !== "/setup" && !site.site_view.local_site.site_setup) {
return res.redirect("/setup");
}

if (site && activeRoute?.fetchInitialData) {
const initialFetchReq: InitialFetchRequest = {
client,
auth,
path,
query,
site,
};

routeData = await activeRoute.fetchInitialData(initialFetchReq);
}
} else if (try_site.state === "failed") {
errorPageData = getErrorPageData(new Error(try_site.msg), site);
}

const error = Object.values(routeData).find(
res => res.state === "failed"
) as FailedRequestState | undefined;

// Redirect to the 404 if there's an API error
if (error) {
console.error(error.msg);
if (error.msg === "instance_is_private") {
return res.redirect(`/signup`);
} else {
errorPageData = getErrorPageData(new Error(error.msg), site);
}
}

const isoData: IsoDataOptionalSite = {
path,
site_res: site,
routeData,
errorPageData,
};

const wrapper = (
<StaticRouter location={url} context={isoData}>
<App />
</StaticRouter>
);

const root = renderToString(wrapper);

res.send(await createSsrHtml(root, isoData));
} catch (err) {
// If an error is caught here, the error page couldn't even be rendered
console.error(err);
res.statusCode = 500;
return res.send(
process.env.NODE_ENV === "development" ? err.message : "Server error"
);
}
};
18 changes: 18 additions & 0 deletions src/server/handlers/robots-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Response } from "express";

export default async ({ res }: { res: Response }) => {
res.setHeader("content-type", "text/plain; charset=utf-8");

res.send(`User-Agent: *
Disallow: /login
Disallow: /settings
Disallow: /create_community
Disallow: /create_post
Disallow: /create_private_message
Disallow: /inbox
Disallow: /setup
Disallow: /admin
Disallow: /password_change
Disallow: /search/
`);
};
14 changes: 14 additions & 0 deletions src/server/handlers/service-worker-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Response } from "express";
import path from "path";

export default async ({ res }: { res: Response }) => {
res
.setHeader("Content-Type", "application/javascript")
.sendFile(
path.resolve(
`./dist/service-worker${
process.env.NODE_ENV === "development" ? "-development" : ""
}.js`
)
);
};
32 changes: 32 additions & 0 deletions src/server/handlers/theme-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Request, Response } from "express";
import { existsSync } from "fs";
import path from "path";

const extraThemesFolder =
process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";

export default async (req: Request, res: Response) => {
res.contentType("text/css");

const theme = req.params.name;

if (!theme.endsWith(".css")) {
res.statusCode = 400;
res.send("Theme must be a css file");
}

const customTheme = path.resolve(`./${extraThemesFolder}/${theme}`);

if (existsSync(customTheme)) {
res.sendFile(customTheme);
} else {
const internalTheme = path.resolve(`./dist/assets/css/themes/${theme}`);

// If the theme doesn't exist, just send litely
if (existsSync(internalTheme)) {
res.sendFile(internalTheme);
} else {
res.sendFile(path.resolve("./dist/assets/css/themes/litely.css"));
}
}
};
6 changes: 6 additions & 0 deletions src/server/handlers/themes-list-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Response } from "express";
import { buildThemeList } from "../utils/build-themes-list";

export default async ({ res }: { res: Response }) => {
res.type("json").send(JSON.stringify(await buildThemeList()));
};
Loading