Skip to content

Commit

Permalink
refactor how balancer messages are handled
Browse files Browse the repository at this point in the history
makes it so that failure to handle an enum variant produces an error at compile time
  • Loading branch information
dyc3 committed Oct 26, 2023
1 parent 807c6a1 commit aedf73f
Showing 1 changed file with 60 additions and 30 deletions.
90 changes: 60 additions & 30 deletions server/clientmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,39 +229,69 @@ function onBalancerDisconnect(conn: BalancerConnection) {
}
}

function onBalancerMessage(conn: BalancerConnection, message: MsgB2M) {
async function onBalancerMessage(conn: BalancerConnection, message: MsgB2M) {
log.silly("balancer message: " + JSON.stringify(message));
if (message.type === "join") {
const msg = message.payload;
const client = new BalancerClient(msg.room, msg.client, conn);
connections.push(client);
client.on("auth", onClientAuth);
client.on("message", onClientMessage);
client.on("disconnect", onClientDisconnect);
client.auth(msg.token);
} else if (message.type === "leave") {
const msg = message.payload;
const client = connections.find(c => c.id === msg.client);
if (client instanceof BalancerClient) {
client.leave();
} else {
log.error(
`Balancer tried to make client leave that does not exist or is not a balancer client`
);
}
} else if (message.type === "client_msg") {
const msg = message.payload;
const client = connections.find(c => c.id === msg.client_id);
if (client instanceof BalancerClient) {
client.receiveMessage(msg.payload as ClientMessage);
} else {
log.error(
`Balancer sent message for client that does not exist or is not a balancer client`
);
}
} else {

/**
* This is a type that maps the message type to the handler for that message type.
*
* Useful for handling enums that are discriminated by a string, like the ones generated by typeshare.
*/
type EnumHandler<T extends { type: string; payload: T["payload"] }> = {
[P in T["type"]]: (
instruction: Extract<T, { type: P; payload: T["payload"] }>
) => Promise<void>;
};

// the intersection type makes it so that it throws a compile error if all the enum variants aren't handled
const handlers: Record<MsgB2M["type"], unknown> & EnumHandler<MsgB2M> = {
load: async message => {
const msg = message.payload;
await roommanager.getRoom(msg.room);
},
unload: async message => {
const msg = message.payload;
await roommanager.unloadRoom(msg.room);
},
join: async message => {
const msg = message.payload;
const client = new BalancerClient(msg.room, msg.client, conn);
connections.push(client);
client.on("auth", onClientAuth);
client.on("message", onClientMessage);
client.on("disconnect", onClientDisconnect);
client.auth(msg.token);
},
leave: async message => {
const msg = message.payload;
const client = connections.find(c => c.id === msg.client);
if (client instanceof BalancerClient) {
client.leave();
} else {
log.error(
`Balancer tried to make client leave that does not exist or is not a balancer client`
);
}
},
client_msg: async message => {
const msg = message.payload;
const client = connections.find(c => c.id === msg.client_id);
if (client instanceof BalancerClient) {
client.receiveMessage(msg.payload as ClientMessage);
} else {
log.error(
`Balancer sent message for client that does not exist or is not a balancer client`
);
}
},
};

const handler = handlers[message.type];
if (!handler) {
log.error(`Unknown balancer message type: ${(message as { type: string }).type}`);
return;
}
await handler(message as any); // this cast is safe because the type is checked and narrowed above
}

function onBalancerError(conn: BalancerConnection, error: WebSocket.ErrorEvent) {
Expand Down

0 comments on commit aedf73f

Please sign in to comment.