mini-world / server.ts
victor's picture
victor HF Staff
Initial deployment of Mini World game
a2d0320 verified
import { serve } from "bun";
import { readFile } from "fs/promises";
import { join } from "path";
import { GameState } from "./gameState";
import { AIService, MODEL } from "./aiService";
const PORT = parseInt(process.env.PORT || "7860");
const ROOT_DIR = import.meta.dir;
const gameState = new GameState(); // Single shared game state
const mimeTypes: Record<string, string> = {
".html": "text/html",
".js": "application/javascript",
".css": "text/css",
".map": "application/octet-stream",
".ico": "image/x-icon",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".webp": "image/webp",
".json": "application/json",
};
serve({
port: PORT,
async fetch(req) {
const url = new URL(req.url);
const pathname = url.pathname;
// Simple config endpoint to expose runtime info to the UI
if (pathname === "/config") {
return new Response(JSON.stringify({ model: MODEL }), {
headers: { "Content-Type": "application/json" },
});
}
// Handle SSE connection
if (pathname === "/game-stream") {
const stream = new ReadableStream<string>({
start(controller) {
gameState.setController(controller);
gameState.sendUpdate();
// Initial state will be sent by gameState
// Start AI agent loop
const runAI = async () => {
const state = gameState.getState();
const action = await AIService.getNextAction(
state.map,
state.history
);
await gameState.handleAction(action);
// Schedule next AI action
setTimeout(runAI, 1000);
};
runAI();
},
cancel() {
// No need to cleanup since we're using a shared state
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
}
// Serve static files
if (pathname === "/" || pathname === "/index.html") {
const data = await readFile(join(ROOT_DIR, "index.html"));
return new Response(data, {
headers: { "Content-Type": "text/html" },
});
}
const filePath = join(ROOT_DIR, pathname);
try {
const data = await readFile(filePath);
const ext = filePath.slice(filePath.lastIndexOf("."));
const mimeType = mimeTypes[ext] || "application/octet-stream";
return new Response(data, {
status: 200,
headers: {
"Content-Type": mimeType,
},
});
} catch (error) {
return new Response("Not Found", { status: 404 });
}
},
});
console.log(`Server is running at http://localhost:${PORT}`);