Skip to content
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
6 changes: 2 additions & 4 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
},
"dependencies": {
"@nanoforge-dev/loader-website": "workspace:*",
"bun": "catalog:core"
"bun": "catalog:core",
"commander": "catalog:core"
},
"devDependencies": {
"@favware/cliff-jumper": "catalog:ci",
Expand All @@ -79,8 +80,5 @@
"src/**/*.ts": [
"eslint --fix"
]
},
"pnpm": {
"neverBuiltDependencies": []
}
}
40 changes: 6 additions & 34 deletions apps/client/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,9 @@
export const getPublicEnv = () => {
const PREFIX = "NANOFORGE_";

export const getGameEnv = () => {
return Object.fromEntries(
Object.entries(process.env).filter(([key]) => key.startsWith("PUBLIC_")),
Object.entries(process.env)
.filter(([key]) => key.startsWith(PREFIX))
.map(([key, value]) => [key.replace(PREFIX, ""), value]),
);
};

export const getPort = () => {
if (process.env.PORT) return process.env.PORT;
throw new Error("PORT env variable not found");
};

export const getGameDir = () => {
if (process.env.GAME_DIR) return process.env.GAME_DIR;
throw new Error("GAME_DIR env variable not found");
};

export const getCert = () => {
if (process.env.CERT) return process.env.CERT;
else return undefined;
};

export const getKey = () => {
if (process.env.KEY) return process.env.KEY;
else return undefined;
};

export const getWatch = () => {
return process.env.WATCH;
};

export const getWatchPort = () => {
return process.env.WATCH_PORT;
};

export const getWatchServerGameDir = () => {
return process.env.WATCH_SERVER_GAME_DIR;
};
48 changes: 27 additions & 21 deletions apps/client/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import { program } from "commander";
import { join } from "node:path";

import {
getCert,
getGameDir,
getKey,
getPort,
getPublicEnv,
getWatch,
getWatchPort,
getWatchServerGameDir,
} from "./env";
import { getGameEnv } from "./env";
import { updateManifest } from "./manifest";
import { startWatch } from "./watch";

Expand All @@ -19,7 +11,27 @@ type IManifest = {
watch: { enable: false } | { enable: true; url: string };
};

const watch = getWatch() === "true";
program
.name("client loader")
.description("run client loader")
.option("-p, --port <port>", "port of the client", "3000")
.option("-d, --dir <dir>", "dir of the game", ".nanoforge/client")
.option("--watch", "watch the game dir", false)
.option("--watch-port <watch port>", "port for watch websocket (default: first port available)")
.option("--watch-server-dir <watch server dir>", "dir of the server for watch it too")
.option("--cert <cert>", "cert file for https")
.option("--key <key>", "key file for https")
.parse();

const { port, dir, watch, watchPort, watchServerDir, cert, key } = program.opts<{
port: string;
dir: string;
watch: boolean;
watchPort?: string;
watchServerDir?: string;
cert?: string;
key?: string;
}>();

export const MANIFEST: IManifest = {
version: "",
Expand All @@ -35,16 +47,10 @@ const resolveWebDir = (str: string) => {
.replace(/^file:\/\//, "");
};

const port = getPort();
const gameDir = getGameDir();

const headers = {
"Access-Control-Allow-Methods": "GET",
};

const cert = getCert();
const key = getKey();

const tls = cert && key ? { cert: Bun.file(cert), key: Bun.file(key) } : undefined;

const server = Bun.serve({
Expand Down Expand Up @@ -77,17 +83,17 @@ const server = Bun.serve({
}
},
"/manifest": async () => {
await updateManifest(gameDir);
await updateManifest(dir);
return Response.json(MANIFEST, {
headers,
});
},
"/env": () => {
return Response.json(getPublicEnv(), { headers });
return Response.json(getGameEnv(), { headers });
},
"/game/*": (req) => {
const path = new URL(req.url).pathname.replace("/game", "");
const file = Bun.file(join(gameDir, path));
const file = Bun.file(join(dir, path));
return new Response(file, {
headers,
});
Expand All @@ -97,4 +103,4 @@ const server = Bun.serve({

console.log(`Client started on url ${server.url.toString()}`);

if (watch) startWatch(gameDir, getWatchPort(), getWatchServerGameDir());
if (watch) startWatch(dir, watchPort, watchServerDir);
5 changes: 1 addition & 4 deletions apps/client/src/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ export const startWatch = (gameDir: string, port?: string, serverGameDir?: strin
const server = Bun.serve({
port: port ?? 0,
fetch(req, server) {
if (server.upgrade(req)) {
return;
}
return new Response("Upgrade failed", { status: 500 });
server.upgrade(req);
},
websocket: {
message(ws) {
Expand Down
6 changes: 3 additions & 3 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'apps/server/*'",
"release": "cliff-jumper"
},
"dependencies": {
"commander": "catalog:core"
},
"devDependencies": {
"@favware/cliff-jumper": "catalog:ci",
"@nanoforge-dev/utils-eslint-config": "catalog:lint",
Expand All @@ -77,8 +80,5 @@
"src/**/*.ts": [
"eslint --fix"
]
},
"pnpm": {
"neverBuiltDependencies": []
}
}
13 changes: 7 additions & 6 deletions apps/server/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export const getGameDir = () => {
if (process.env.GAME_DIR) return process.env.GAME_DIR;
throw new Error("GAME_DIR env variable not found");
};
const PREFIX = "NANOFORGE_";

export const getWatch = () => {
return process.env.WATCH;
export const getGameEnv = () => {
return Object.fromEntries(
Object.entries(process.env)
.filter(([key]) => key.startsWith(PREFIX))
.map(([key, value]) => [key.replace(PREFIX, ""), value]),
);
};
29 changes: 20 additions & 9 deletions apps/server/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { program } from "commander";
import { type ChildProcess, fork } from "node:child_process";
import { join } from "node:path";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";

import { getGameDir, getWatch } from "./env";
import { getFiles } from "./files";
import { startWatch } from "./watch";

const bootstrap = async () => {
const gameDir = getGameDir();

const paths = getFiles(gameDir);
program
.name("server loader")
.description("run server loader")
.option("-d, --dir <dir>", "dir of the game", ".nanoforge/server")
.option("--watch", "watch the game dir", false)
.parse();

const { dir, watch } = program.opts<{
dir: string;
watch: boolean;
}>();

const paths = getFiles(dir);
let mainPath: string | undefined = undefined;

paths.filter(([path, fullPath]) => {
Expand All @@ -30,13 +40,14 @@ const bootstrap = async () => {
}

const __filename = fileURLToPath(import.meta.url);
child = fork(join(dirname(__filename), "worker.js"), [
mainPath as string,
JSON.stringify(paths),
]);
child = fork(
join(dirname(__filename), "worker.js"),
[mainPath as string, JSON.stringify(paths)],
{ env: process.env },
);
};

if (getWatch()) startWatch(gameDir, runWorker);
if (watch) startWatch(dir, runWorker);

await runWorker();
};
Expand Down
9 changes: 7 additions & 2 deletions apps/server/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { createRequire } from "node:module";

import { getGameEnv } from "./env";

const bootstrap = async () => {
const mainPath = process.argv[2] as string;
const paths = JSON.parse(process.argv[3] as string);
const { main } = (await createRequire(import.meta.url)(mainPath)) as {
main: (options: { files: Map<string, string> }) => Promise<void>;
main: (options: {
files: Map<string, string>;
env: Record<string, string | undefined>;
}) => Promise<void>;
};

console.log("Starting server");
await main({ files: new Map(paths) });
await main({ files: new Map(paths), env: getGameEnv() });
};

bootstrap().then();
3 changes: 0 additions & 3 deletions apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,5 @@
"src/**/*.{ts,html,css}": [
"eslint --fix"
]
},
"pnpm": {
"neverBuiltDependencies": []
}
}
12 changes: 12 additions & 0 deletions apps/website/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Logger } from "./utils/logger.utils";

const logger = new Logger("Env");

export const getEnv = async (): Promise<Record<string, string | undefined>> => {
logger.info("Fetching environment");
const res = await fetch("/env");
if (!res.ok) throw new Error("Unable to fetch env");
const content = await res.json();
logger.info("Environment fetched!");
return content as Record<string, string | undefined>;
};
4 changes: 3 additions & 1 deletion apps/website/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GameCache } from "./cache/cache";
import { getEnv } from "./env";
import { runGame } from "./game";
import { loadGameFiles } from "./loader";
import { getManifest } from "./manifest";
Expand All @@ -16,8 +17,9 @@ const runLoad = async () => {
const cache = new GameCache();
const extendedManifest = await cache.updateCache(manifest, true);
const [files, mainModule] = await loadGameFiles(extendedManifest);
const env = await getEnv();
setLoadingStatus("Starting game");
runGame(mainModule, { files });
runGame(mainModule, { files, env });
};

runLoad()
Expand Down
1 change: 1 addition & 0 deletions apps/website/src/types/game.type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface IGameOptions {
canvas: HTMLCanvasElement;
files: Map<string, string>;
env: Record<string, string | undefined>;
}
Loading