99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
import type { ServerWebSocket } from "bun";
|
|
|
|
interface Scoreboard {
|
|
stage: number;
|
|
user: string;
|
|
}
|
|
|
|
const loadScoreboard = async (): Promise<Scoreboard[]> => {
|
|
try {
|
|
const scoreboardFile = Bun.file("./scoreboard.json");
|
|
const scoreboard = await scoreboardFile.json();
|
|
return scoreboard;
|
|
} catch (e) {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
const allowCors = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
"Access-Control-Allow-Headers": "Content-Type",
|
|
};
|
|
|
|
const lastMessage = new WeakMap<ServerWebSocket<unknown>, number>();
|
|
const server = Bun.serve({
|
|
async fetch(request: Request) {
|
|
if (request.method === "OPTIONS") {
|
|
const res = new Response("Departed", { headers: allowCors });
|
|
return res;
|
|
}
|
|
if (request.url.endsWith("ws")) {
|
|
if (server.upgrade(request)) return new Response("ok");
|
|
}
|
|
if (new URL(request.url).pathname === "/submit") {
|
|
const body = await request.text();
|
|
const data = JSON.parse(body) as { stage: number; user: string };
|
|
const scoreboardFile = Bun.file("./scoreboard.json");
|
|
const scoreboard = await loadScoreboard();
|
|
const currentScore = scoreboard.find((s) => s.user === data.user);
|
|
if (currentScore) {
|
|
if (currentScore.stage < data.stage) {
|
|
currentScore.stage = data.stage;
|
|
Bun.write(scoreboardFile, JSON.stringify(scoreboard));
|
|
}
|
|
return new Response(JSON.stringify(currentScore), {
|
|
headers: {
|
|
"content-type": "application/json",
|
|
...allowCors,
|
|
},
|
|
});
|
|
}
|
|
scoreboard.push(data);
|
|
Bun.write(scoreboardFile, JSON.stringify(scoreboard));
|
|
return new Response(JSON.stringify(data), {
|
|
headers: {
|
|
"content-type": "application/json",
|
|
...allowCors,
|
|
},
|
|
});
|
|
}
|
|
const scoreboard = await loadScoreboard();
|
|
const sorted = scoreboard.sort((a, b) => b.stage - a.stage);
|
|
return new Response(JSON.stringify(sorted), {
|
|
headers: {
|
|
"content-type": "application/json",
|
|
...allowCors,
|
|
},
|
|
});
|
|
},
|
|
websocket: {
|
|
message: (ws, message) => {
|
|
if (typeof message !== "string") {
|
|
return;
|
|
}
|
|
const msg = JSON.parse(message);
|
|
const now = Date.now();
|
|
if (lastMessage.has(ws) && now - lastMessage.get(ws)! < 200) {
|
|
return;
|
|
}
|
|
lastMessage.set(ws, now);
|
|
if (msg.type === "loss") {
|
|
server.publish(
|
|
"minesweeper",
|
|
JSON.stringify({ type: "loss", user: msg.user, stage: msg.stage }),
|
|
);
|
|
} else if (msg.type === "new") {
|
|
server.publish(
|
|
"minesweeper",
|
|
JSON.stringify({ type: "new", user: msg.user }),
|
|
);
|
|
}
|
|
},
|
|
open: async (ws) => {
|
|
ws.subscribe("minesweeper");
|
|
},
|
|
},
|
|
port: 8076,
|
|
});
|