proof of work, bug fixes, reorg, more

This commit is contained in:
Zoe
2025-09-15 22:24:43 -05:00
parent de96b33a41
commit cad5d6d98e
21 changed files with 412 additions and 88 deletions

View File

@@ -16,12 +16,16 @@ export enum WebSocketMessageType {
CREATE_ROOM = "create",
JOIN_ROOM = "join",
LEAVE_ROOM = "leave",
CHECK_ROOM_EXISTS = "check",
REQUEST_CHALLENGE = "request-challenge",
// response messages
ROOM_CREATED = "created",
ROOM_JOINED = "joined",
ROOM_LEFT = "left",
ROOM_READY = "ready",
ROOM_STATUS = "status",
CHALLENGE = "challenge",
// webrtc messages
WEBRTC_OFFER = "offer",
@@ -31,14 +35,19 @@ export enum WebSocketMessageType {
ERROR = "error",
}
// TODO: name the interfaces better
export type WebSocketMessage =
| CreateRoomMessage
| JoinRoomMessage
| LeaveRoomMessage
| CheckRoomExistsMessage
| RequestChallengeMessage
| RoomCreatedMessage
| RoomJoinedMessage
| RoomLeftMessage
| RoomStatusMessage
| RoomReadyMessage
| ChallengeMessage
| OfferMessage
| AnswerMessage
| IceCandidateMessage
@@ -49,14 +58,20 @@ interface ErrorMessage {
data: string;
}
// ====== Query Messages ======
interface CreateRoomMessage {
type: WebSocketMessageType.CREATE_ROOM;
roomName?: string;
nonce: string;
challenge: string;
}
// TODO: this is used as a query message, but it's also used as a response message
interface JoinRoomMessage {
type: WebSocketMessageType.JOIN_ROOM;
roomId: string;
nonce?: string;
challenge?: string;
}
interface LeaveRoomMessage {
@@ -64,6 +79,20 @@ interface LeaveRoomMessage {
roomId: string;
}
interface CheckRoomExistsMessage {
type: WebSocketMessageType.CHECK_ROOM_EXISTS;
// if sha256(roomId + challenge + nonce) has a certain number of leading zeros, then we can give the status to the user
roomId: string;
nonce: string;
challenge: string;
}
interface RequestChallengeMessage {
type: WebSocketMessageType.REQUEST_CHALLENGE;
}
// ====== Response Messages ======
interface RoomCreatedMessage {
type: WebSocketMessageType.ROOM_CREATED;
data: string;
@@ -80,6 +109,12 @@ interface RoomLeftMessage {
roomId: string;
}
interface RoomStatusMessage {
type: WebSocketMessageType.ROOM_STATUS;
roomId: string;
status: 'found' | 'not-found';
}
interface RoomReadyMessage {
type: WebSocketMessageType.ROOM_READY;
data: {
@@ -87,6 +122,14 @@ interface RoomReadyMessage {
};
}
interface ChallengeMessage {
type: WebSocketMessageType.CHALLENGE;
challenge: string;
difficulty: number;
}
// ====== WebRTC signaling messages ======
// as the server, we dont do anything with these messages other than relay them to the other peers in the room
interface OfferMessage {
type: WebSocketMessageType.WEBRTC_OFFER;
data: {
@@ -122,6 +165,9 @@ export class Socket {
public addEventListener: typeof WebSocket.prototype.addEventListener;
public removeEventListener: typeof WebSocket.prototype.removeEventListener;
public close: typeof WebSocket.prototype.close;
// maps WebSocketMessageType to an array of functions that handle that message
// this allows for consumbers to subscribe to a specific message type and handle it themselves
private functionStack: Map<WebSocketMessageType, Function[]>;
constructor(webSocket: WebSocket) {
this.ws = webSocket;
@@ -130,6 +176,18 @@ export class Socket {
console.log("WebSocket opened");
});
this.functionStack = new Map();
this.ws.addEventListener("message", async (event) => {
console.log("WebSocket received message:", event.data);
const message: WebSocketMessage = JSON.parse(event.data);
if (this.functionStack.has(message.type)) {
for (let func of this.functionStack.get(message.type)!) {
func(message);
}
}
});
this.addEventListener = this.ws.addEventListener.bind(this.ws);
this.removeEventListener = this.ws.removeEventListener.bind(this.ws);
@@ -145,4 +203,15 @@ export class Socket {
this.ws.send(JSON.stringify(message));
}
public handleEvent<T extends WebSocketMessageType>(messageType: T, func: (message: WebSocketMessage & { type: T }) => void): () => void {
if (!this.functionStack.has(messageType)) {
this.functionStack.set(messageType, []);
}
this.functionStack.get(messageType)!.push(func);
return () => {
this.functionStack.get(messageType)!.splice(this.functionStack.get(messageType)!.indexOf(func), 1);
}
}
}