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
2 changes: 1 addition & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"release": "cliff-jumper"
},
"dependencies": {
"@nanoforge-dev/loader-website": "^1.0.0",
"@nanoforge-dev/loader-website": "^1.1.0",
"bun": "^1.3.3"
},
"devDependencies": {
Expand Down
12 changes: 12 additions & 0 deletions apps/client/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ export const getGameDir = () => {
if (process.env.GAME_DIR) return process.env.GAME_DIR;
throw new Error("GAME_DIR env variable not found");
};

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;
};
27 changes: 24 additions & 3 deletions apps/client/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
import { join } from "node:path";

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

export const MANIFEST: { version: string; files: { path: string }[] } = {
type IManifest = {
version: string;
files: { path: string }[];
watch: { enable: false } | { enable: true; url: string };
};

const watch = getWatch() === "true";

export const MANIFEST: IManifest = {
version: "",
files: [],
watch: {
enable: false,
},
};

const resolveWebDir = (str: string) => {
Expand Down Expand Up @@ -68,4 +87,6 @@ const server = Bun.serve({
},
});

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

if (watch) startWatch(gameDir, getWatchPort(), getWatchServerGameDir());
54 changes: 54 additions & 0 deletions apps/client/src/watch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { watch } from "fs";

import { MANIFEST } from "./server";

export const startWatch = (gameDir: string, port?: string, serverGameDir?: string) => {
const server = Bun.serve({
port: port ?? 0,
fetch(req, server) {
if (server.upgrade(req)) {
return;
}
return new Response("Upgrade failed", { status: 500 });
},
websocket: {
message(ws) {
ws.send("not allowed");
},
open(ws) {
ws.subscribe("watch");
},
close(ws) {
ws.unsubscribe("watch");
},
},
});

MANIFEST.watch = {
enable: true,
url: server.url.toString(),
};

let lastCall = Date.now();

const onClientWatch = () => {
if (lastCall + 100 > Date.now()) return;
lastCall = Date.now();
server.publish("watch", "update");
console.log(`[Watcher] Game client triggered an updated`);
};

const onServerWatch = () => {
if (lastCall + 100 > Date.now()) return;
lastCall = Date.now();
setTimeout(() => {
server.publish("watch", "update");
console.log(`[Watcher] Game server triggered an updated`);
}, 100);
};

watch(gameDir, { recursive: true }, onClientWatch);
if (serverGameDir) watch(serverGameDir, { recursive: true }, onServerWatch);

console.log(`Watcher started on url ${server.url.toString()}`);
};
4 changes: 3 additions & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
},
"funding": "",
"scripts": {
"build": "bun build src/server.ts --outdir dist --target node",
"build": "pnpm run build:server && pnpm run build:worker",
"build:server": "bun build src/server.ts --outdir dist --target node",
"build:worker": "bun build src/worker.ts --outdir dist --target node",
"start": "node dist/server.js",
"lint": "prettier --check . && eslint --format=pretty src",
"format": "prettier --write . && eslint --fix --format=pretty src",
Expand Down
4 changes: 4 additions & 0 deletions apps/server/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ export const getGameDir = () => {
if (process.env.GAME_DIR) return process.env.GAME_DIR;
throw new Error("GAME_DIR env variable not found");
};

export const getWatch = () => {
return process.env.WATCH;
};
28 changes: 22 additions & 6 deletions apps/server/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { createRequire } from "node:module";
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 } from "./env";
import { getGameDir, getWatch } from "./env";
import { getFiles } from "./files";
import { startWatch } from "./watch";

const bootstrap = async () => {
const gameDir = getGameDir();
Expand All @@ -17,12 +21,24 @@ const bootstrap = async () => {

if (!mainPath) throw new Error("No main.js found");

const { main } = (await createRequire(import.meta.url)(mainPath)) as {
main: (options: { files: Map<string, string> }) => Promise<void>;
let child: ChildProcess | undefined;

const runWorker = async () => {
if (child) {
child.kill();
child = undefined;
}

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

console.log("Starting server");
await main({ files: new Map(paths) });
if (getWatch()) startWatch(gameDir, runWorker);

await runWorker();
};

bootstrap().then();
14 changes: 14 additions & 0 deletions apps/server/src/watch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { watch } from "fs";

export const startWatch = (gameDir: string, onWatch: () => Promise<void>) => {
let lastCall = Date.now();

watch(gameDir, { recursive: true, persistent: false }, async () => {
if (lastCall + 100 > Date.now()) return;
lastCall = Date.now();
console.log(`[Watcher] Game server triggered an updated`);
await onWatch();
});

console.log(`Watcher started`);
};
14 changes: 14 additions & 0 deletions apps/server/src/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createRequire } from "node:module";

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>;
};

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

bootstrap().then();
Loading