feat: initial scaffolding, client can connect with a user name
This commit is contained in:
commit
b0ce2fe0af
31 changed files with 3342 additions and 0 deletions
12
server/src/handleClientMessage.ts
Normal file
12
server/src/handleClientMessage.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import type { ServerWebSocket } from "bun";
|
||||
import type { ClientMessage } from "../../shared";
|
||||
import type { Room, WebSocketData } from "./types";
|
||||
|
||||
export default function handleClientMessage(
|
||||
client: ServerWebSocket<WebSocketData>,
|
||||
data: ClientMessage,
|
||||
room: Room,
|
||||
) {
|
||||
// handle client messages
|
||||
console.log("Received new message ", data);
|
||||
}
|
||||
85
server/src/index.ts
Normal file
85
server/src/index.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import type { ClientMessage } from "../../shared.ts";
|
||||
import handleClientMessage from "./handleClientMessage.ts";
|
||||
import type { Room, WebSocketData } from "./types.ts";
|
||||
|
||||
const rooms = new Map<string, Room>(); // roomId -> Room
|
||||
|
||||
const server = Bun.serve<WebSocketData>({
|
||||
port: 3000,
|
||||
|
||||
async fetch(request, server) {
|
||||
// check if not a websocket request
|
||||
if (!request.headers.get("Upgrade")) {
|
||||
return new Response("Only Websocket Connections supported", {
|
||||
status: 200,
|
||||
});
|
||||
}
|
||||
|
||||
// extract the roomId out of the URL
|
||||
const url = new URL(request.url);
|
||||
const matches = url.pathname.match(/^\/ws\/room\/(.+)$/);
|
||||
|
||||
if (!matches) {
|
||||
return new Response("Invalid room URL format", { status: 400 });
|
||||
}
|
||||
|
||||
const roomId = matches[1];
|
||||
|
||||
// pass it to on as data attr
|
||||
if (
|
||||
server.upgrade(request, {
|
||||
data: { roomId },
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return new Response("Upgrade failed", { status: 500 });
|
||||
},
|
||||
websocket: {
|
||||
open(ws) {
|
||||
const roomId = ws.data.roomId;
|
||||
|
||||
if (!roomId) {
|
||||
console.log("Error: RoomId cannot be empty");
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rooms.has(roomId)) {
|
||||
console.log(`Creating room: ${roomId}`);
|
||||
rooms.set(roomId, {
|
||||
roomId,
|
||||
userConnections: new Map(),
|
||||
});
|
||||
}
|
||||
},
|
||||
close(ws) {
|
||||
// cleanup, delete room if empty
|
||||
const roomId = ws.data.roomId;
|
||||
const room = rooms.get(roomId);
|
||||
|
||||
if (!room) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (room.userConnections.size === 0) {
|
||||
rooms.delete(roomId);
|
||||
console.log("Cleaned up room", roomId);
|
||||
}
|
||||
},
|
||||
message(ws, message) {
|
||||
const roomId = ws.data.roomId;
|
||||
const room = rooms.get(roomId);
|
||||
|
||||
if (!room) {
|
||||
console.log(`Room not found: ${roomId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = JSON.parse(message.toString()) as ClientMessage;
|
||||
|
||||
handleClientMessage(ws, data, room);
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(`Server running at ${server.url}`);
|
||||
17
server/src/types.ts
Normal file
17
server/src/types.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { ServerWebSocket } from "bun";
|
||||
import type { User } from "../../shared";
|
||||
|
||||
export interface WebSocketData {
|
||||
roomId: string;
|
||||
}
|
||||
|
||||
export interface Room {
|
||||
roomId: string;
|
||||
userConnections: Map<
|
||||
string, // userId
|
||||
{
|
||||
user: User;
|
||||
socket: ServerWebSocket<WebSocketData>;
|
||||
}
|
||||
>;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue