feat: add Web App Port management alongside API Server Port and fix square 512x512 app launcher icon
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
statSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { createServer, type Server as HttpServer } from "node:http";
|
||||
import { homedir } from "node:os";
|
||||
import { basename, dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -101,10 +102,14 @@ export async function buildApp() {
|
||||
interface PersistedServerSysConfig {
|
||||
enabled: boolean;
|
||||
port: number;
|
||||
webPort: number;
|
||||
startOnBoot: boolean;
|
||||
projectDirectory: string;
|
||||
}
|
||||
|
||||
let secondaryWebServer: HttpServer | null = null;
|
||||
let activeWebPort: number = 5173;
|
||||
|
||||
function loadPersistedServerSysConfig(): PersistedServerSysConfig {
|
||||
try {
|
||||
if (existsSync(sysConfigPath)) {
|
||||
@@ -115,6 +120,10 @@ export async function buildApp() {
|
||||
typeof raw.port === "number" && raw.port >= 1024 && raw.port <= 65535
|
||||
? raw.port
|
||||
: config.port,
|
||||
webPort:
|
||||
typeof raw.webPort === "number" && raw.webPort >= 1024 && raw.webPort <= 65535
|
||||
? raw.webPort
|
||||
: 5173,
|
||||
startOnBoot:
|
||||
typeof raw.startOnBoot === "boolean"
|
||||
? raw.startOnBoot
|
||||
@@ -131,11 +140,36 @@ export async function buildApp() {
|
||||
return {
|
||||
enabled: true,
|
||||
port: config.port,
|
||||
webPort: 5173,
|
||||
startOnBoot: existsSync(autostartDesktopPath) || existsSync(systemdServicePath),
|
||||
projectDirectory: defaultProjectDir,
|
||||
};
|
||||
}
|
||||
|
||||
async function bindSecondaryWebPort(targetWebPort: number, enabled: boolean): Promise<number> {
|
||||
activeWebPort = targetWebPort;
|
||||
if (secondaryWebServer) {
|
||||
await new Promise<void>((res) => secondaryWebServer!.close(() => res()));
|
||||
secondaryWebServer = null;
|
||||
}
|
||||
if (!enabled || targetWebPort === config.port) {
|
||||
return targetWebPort;
|
||||
}
|
||||
return await new Promise<number>((res) => {
|
||||
const srv = createServer((req, reply) => {
|
||||
app.server.emit("request", req, reply);
|
||||
});
|
||||
srv.once("error", () => {
|
||||
// Port may already be served by Vite dev server (e.g. :5173); keep activeWebPort
|
||||
res(targetWebPort);
|
||||
});
|
||||
srv.listen(targetWebPort, "0.0.0.0", () => {
|
||||
secondaryWebServer = srv;
|
||||
res(targetWebPort);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function applySystemStartupFiles(cfg: PersistedServerSysConfig): boolean {
|
||||
try {
|
||||
mkdirSync(sysConfigDir, { recursive: true });
|
||||
@@ -225,6 +259,8 @@ export async function buildApp() {
|
||||
enabled: persisted.enabled,
|
||||
port: persisted.port,
|
||||
activePort: config.port,
|
||||
webPort: persisted.webPort,
|
||||
activeWebPort: activeWebPort || persisted.webPort,
|
||||
startOnBoot: persisted.startOnBoot,
|
||||
projectDirectory: persisted.projectDirectory,
|
||||
autostartPath: autostartDesktopPath,
|
||||
@@ -240,6 +276,11 @@ export async function buildApp() {
|
||||
if (!Number.isFinite(nextPort) || nextPort < 1024 || nextPort > 65535) {
|
||||
return reply.code(400).send({ error: "invalid_port" });
|
||||
}
|
||||
const nextWebPort =
|
||||
typeof body.webPort === "number" ? Math.trunc(body.webPort) : current.webPort;
|
||||
if (!Number.isFinite(nextWebPort) || nextWebPort < 1024 || nextWebPort > 65535) {
|
||||
return reply.code(400).send({ error: "invalid_web_port" });
|
||||
}
|
||||
const nextProjectDir =
|
||||
typeof body.projectDirectory === "string" && body.projectDirectory.trim()
|
||||
? body.projectDirectory.trim()
|
||||
@@ -247,16 +288,20 @@ export async function buildApp() {
|
||||
const next: PersistedServerSysConfig = {
|
||||
enabled: typeof body.enabled === "boolean" ? body.enabled : current.enabled,
|
||||
port: nextPort,
|
||||
webPort: nextWebPort,
|
||||
startOnBoot:
|
||||
typeof body.startOnBoot === "boolean" ? body.startOnBoot : current.startOnBoot,
|
||||
projectDirectory: nextProjectDir,
|
||||
};
|
||||
const configured = applySystemStartupFiles(next);
|
||||
const boundWebPort = await bindSecondaryWebPort(next.webPort, next.enabled);
|
||||
return {
|
||||
ok: true,
|
||||
enabled: next.enabled,
|
||||
port: next.port,
|
||||
activePort: config.port,
|
||||
webPort: next.webPort,
|
||||
activeWebPort: boundWebPort,
|
||||
startOnBoot: next.startOnBoot,
|
||||
projectDirectory: next.projectDirectory,
|
||||
autostartConfigured: configured,
|
||||
@@ -355,6 +400,21 @@ export async function buildApp() {
|
||||
});
|
||||
}
|
||||
|
||||
app.addHook("onClose", async () => {
|
||||
if (secondaryWebServer) {
|
||||
await new Promise<void>((res) => secondaryWebServer!.close(() => res()));
|
||||
secondaryWebServer = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (
|
||||
process.argv[1] !== undefined &&
|
||||
fileURLToPath(import.meta.url) === process.argv[1]
|
||||
) {
|
||||
const persisted = loadPersistedServerSysConfig();
|
||||
void bindSecondaryWebPort(persisted.webPort, persisted.enabled);
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user