Created
January 24, 2020 09:46
-
-
Save justgook/c6694d16f383fbc6e34c22e2f386d035 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Non-SSL is simply App() */ | |
const rooms = new Map(); | |
const { TextEncoder } = require("util"); | |
const NewUser = 10; | |
const UserLeave = 11; | |
const RoomData = 12; | |
const YourAreMaster = 14; | |
const YourAreSlave = 15; | |
const uWebSockets = require('uWebSockets.js') | |
const app = uWebSockets.App({ | |
/* There are tons of SSL options */ | |
// key_file_name: 'misc/key.pem', | |
// cert_file_name: 'misc/cert.pem', | |
}).ws('/*', { | |
compression: 0, | |
maxPayloadLength: 16 * 1024 * 1024, | |
idleTimeout: 10 * 60 * 60, //Maximum amount of seconds that may pass without sending or getting a message. | |
open: (ws, req) => open(ws, new URL(`ws://placeholder${req.getUrl()}?${req.getQuery()}`)), | |
message: message, | |
drain: (ws) => { | |
console.log("drain?"); | |
}, | |
close: onclose | |
}).any('/*', (res, req) => { | |
res.end('Nothing to see here!'); | |
}).listen(9001, (listenSocket) => { | |
if (listenSocket) { | |
console.log('Listening to port 9001'); | |
} | |
}); | |
function onclose(ws, code, message) { | |
const roomSet = rooms.get(ws.room); | |
const masterIterator = roomSet.values(); | |
console.log("User leave", ws.room); | |
if (masterIterator.next().value === ws) { | |
const candidate = masterIterator.next().value; | |
if (candidate) { | |
console.log(`New master for room ${ws.room}`); | |
candidate.send(intStringString(YourAreMaster, ws.session, ws.room), true); | |
} | |
} | |
roomSet.delete(ws) | |
if (roomSet.size === 0) { | |
rooms.delete(ws.room); | |
console.log(`Room ${ws.room} destroyed`); | |
} else { | |
for (let value of roomSet.values()) { | |
value.send(intString(UserLeave, ws.session), true); | |
} | |
} | |
} | |
function open(socket, url) { | |
let roomUUID = url.pathname.replace("/", ""); | |
let sessionId = url.searchParams.get("sessionId"); | |
if (roomUUID && rooms.has(roomUUID)) { | |
socket.session = validateSessionId(sessionId, rooms.get(roomUUID).values()); | |
socket.send(intStringString(YourAreSlave, socket.session, roomUUID), true); | |
console.log("New user in room", roomUUID); | |
} else { | |
roomUUID = roomUUID ? roomUUID : create_UUID(); | |
rooms.set(roomUUID, new Set()); | |
socket.session = validateSessionId(sessionId, new Set().values()); | |
socket.send(intStringString(YourAreMaster, socket.session, roomUUID), true); | |
console.log("Room created", roomUUID); | |
} | |
socket.room = roomUUID; | |
const roomSet = rooms.get(roomUUID); | |
for (let client of roomSet.values()) { | |
client.send(intString(NewUser, socket.session), true); | |
} | |
roomSet.add(socket); | |
} | |
function validateSessionId(sessionId, room) { | |
let candidate = { done: false }; | |
while (!candidate.done) { | |
candidate = room.next(); | |
if (sessionId === candidate.session) { | |
sessionId = create_UUID(); | |
candidate.done = true; | |
} | |
} | |
return sessionId || create_UUID(); | |
} | |
function message(socket, message) { | |
console.log("brodcastOrSendToMaster", message); | |
const room = rooms.get(socket.room).values(); | |
const master = room.next().value; | |
if (master == socket) { | |
for (let value of room) { | |
value.send(message, true); | |
} | |
} else { | |
master.send(message, true); | |
} | |
} | |
const intStringString = | |
(code, session, room) => | |
concatBuffer(intString(code, session), sizedString(room)); | |
const intString = | |
(code, session) => | |
concatBuffer(unsignedInt32BE(code), sizedString(session)); | |
//TODO Encoders - maybe find better way? | |
function unsignedInt32BE(data) { | |
const buf = Buffer.alloc(4); | |
buf.writeUInt32BE(data, 0); | |
return buf; | |
} | |
function sizedString(string) { | |
const encoder = new TextEncoder("utf-8"); | |
const bytes = encoder.encode(string); | |
return concatBuffer(unsignedInt32BE(bytes.length), bytes); | |
} | |
//TODO HELPER FUNCTIONS - NEED TO FIND BETTER SOLUTION!! | |
function concatBuffer(buffer1, buffer2) { | |
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); | |
tmp.set(new Uint8Array(buffer1), 0); | |
tmp.set(new Uint8Array(buffer2), buffer1.byteLength); | |
return tmp.buffer; | |
}; | |
// UUID generator from: https://gist.github.com/LeverOne/1308368 | |
const create_UUID = function (a, b) { | |
for (b = a = ''; a++ < 36; b += a * 51 & 52 ? (a ^ 15 ? 8 ^ Math.random() * (a ^ 20 ? 16 : 4) : 4).toString(16) : '-') ; | |
return b | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment