@hathora/server-sdk
Version:

73 lines (72 loc) • 2.83 kB
JavaScript
import uWS from "uWebSockets.js";
import jwt from "jsonwebtoken";
const socketsMap = new Map();
export function startServer(app, port) {
return new Promise((resolve, reject) => {
const server = uWS
.App()
.ws("/:roomId", {
upgrade: async (res, req, context) => {
const roomId = req.getParameter(0);
const queryParts = req.getQuery().split("token=");
if (queryParts.length !== 2) {
res.writeStatus("401").end();
return;
}
const token = queryParts[1];
const userId = await app.verifyToken(token, roomId);
if (userId === undefined) {
res.writeStatus("401").end();
return;
}
if (socketsMap.has(roomId + userId)) {
res.writeStatus("400").end();
return;
}
res.upgrade({ roomId, userId }, req.getHeader("sec-websocket-key"), req.getHeader("sec-websocket-protocol"), req.getHeader("sec-websocket-extensions"), context);
},
open: (ws) => {
const { roomId, userId } = ws.getUserData();
ws.subscribe(roomId);
socketsMap.set(roomId + userId, ws);
app.subscribeUser(roomId, userId);
},
message: (ws, message) => {
const { roomId, userId } = ws.getUserData();
app.onMessage(roomId, userId, message);
},
close: (ws) => {
const { roomId, userId } = ws.getUserData();
socketsMap.delete(roomId + userId);
app.unsubscribeUser(roomId, userId);
},
})
.listen(port, (listenSocket) => {
if (listenSocket) {
resolve({
sendMessage: (roomId, userId, data) => {
socketsMap.get(roomId + userId)?.send(data, true);
},
broadcastMessage: (roomId, data) => {
server.publish(roomId, data, true);
},
closeConnection: (roomId, userId, error) => {
socketsMap.get(roomId + userId)?.end(4000, error);
},
});
}
else {
reject(`Server failed to start, is the port ${port} already in use?`);
}
});
});
}
export function verifyJwt(token, secret, userIdField = "id") {
try {
const payload = jwt.verify(token, secret);
if (typeof payload === "object" && typeof payload.id === "string") {
return payload[userIdField];
}
}
catch (e) { }
}