96 lines
2.7 KiB
TypeScript

import { existsSync } from "node:fs";
import path from "node:path";
import type { Metadata } from "next";
import { redirect } from "next/navigation";
import { auth } from "@/app/(auth)/auth";
import { PascalEditorFrame } from "@/components/pascal-editor/pascal-editor-frame";
import { getSiteSettings } from "@/lib/db/queries";
const LOCAL_PASCAL_EDITOR_SRC = "/vendor/pascal-editor/index.html";
const DEV_SELF_HOSTED_PASCAL_EDITOR_SRC = "http://localhost:3002";
export const dynamic = "force-dynamic";
export const metadata: Metadata = {
title: "建筑编辑",
};
export const runtime = "nodejs";
export default async function PascalEditorPage() {
const [session, siteSettings] = await Promise.all([auth(), getSiteSettings()]);
if (!session?.user?.id) {
redirect("/login?callbackUrl=%2Fpascal-editor");
}
const configuredSrc = normalizePascalEditorUrl(
process.env.NEXT_PUBLIC_PASCAL_EDITOR_URL ||
process.env.PASCAL_EDITOR_URL ||
""
);
const hasLocalEditor = existsSync(
path.join(process.cwd(), "public/vendor/pascal-editor/index.html")
);
const shouldUseDevSelfHosted =
process.env.NODE_ENV === "development" && !configuredSrc && !hasLocalEditor;
const hasDevSelfHostedEditor =
shouldUseDevSelfHosted &&
(await isHttpUrlReachable(DEV_SELF_HOSTED_PASCAL_EDITOR_SRC));
const src =
configuredSrc ||
(hasLocalEditor ? LOCAL_PASCAL_EDITOR_SRC : "") ||
(hasDevSelfHostedEditor ? DEV_SELF_HOSTED_PASCAL_EDITOR_SRC : "") ||
LOCAL_PASCAL_EDITOR_SRC;
const isReady = Boolean(configuredSrc || hasLocalEditor || hasDevSelfHostedEditor);
return (
<PascalEditorFrame
fallbackSrc={LOCAL_PASCAL_EDITOR_SRC}
isReady={isReady}
sourceLabel={
hasDevSelfHostedEditor
? "本机 Pascal Editor"
: configuredSrc
? "Pascal Editor"
: "本地 Pascal Editor"
}
selfHostedSrc={DEV_SELF_HOSTED_PASCAL_EDITOR_SRC}
siteLogo={siteSettings.siteLogo}
siteLogoDark={siteSettings.siteLogoDark}
siteName={siteSettings.siteName}
src={src}
user={session.user}
/>
);
}
function normalizePascalEditorUrl(value: string) {
const trimmed = value.trim();
if (!trimmed) {
return "";
}
if (trimmed.startsWith("/")) {
return trimmed;
}
try {
const url = new URL(trimmed);
return url.protocol === "http:" || url.protocol === "https:"
? url.toString()
: "";
} catch {
return "";
}
}
async function isHttpUrlReachable(value: string) {
try {
const response = await fetch(value, {
cache: "no-store",
signal: AbortSignal.timeout(3000),
});
return response.ok;
} catch {
return false;
}
}