|
| 1 | +"use strict"; |
| 2 | +var __importDefault = (this && this.__importDefault) || function (mod) { |
| 3 | + return (mod && mod.__esModule) ? mod : { "default": mod }; |
| 4 | +}; |
| 5 | +Object.defineProperty(exports, "__esModule", { value: true }); |
| 6 | +const ws_1 = require("ws"); |
| 7 | +const actions_1 = __importDefault(require("../src/constants/actions")); |
| 8 | +const { OFFER, ANSWER, ICECANDIDATE, LOGIN, LEAVE } = actions_1.default; |
| 9 | +/** |
| 10 | + * @class |
| 11 | + * @classdesc Class representing the SignalingChannel using websockets to allow communication between clients connected to the websocket server |
| 12 | + * @prop { WebsocketServer } websocketServer - a simple websocket server |
| 13 | + * @prop { Map } users - an object of users in the following fashion { username1: socket1, username2: socket2, usernameN: socketN, ... } |
| 14 | + */ |
| 15 | +class SignalingChannel { |
| 16 | + /** |
| 17 | + * |
| 18 | + * @constructor constructing a websocket server with an https object passed in upon instantiating SignalingChannel |
| 19 | + * @param {Server} server - pass in a server (http or https), or pass in port (not the same port (this port can't be the same as the application port and has to listen on the same port in rtconnect!) |
| 20 | + */ |
| 21 | + constructor(server) { |
| 22 | + this.webSocketServer = typeof server === 'number' ? new ws_1.WebSocket.Server({ port: server }) : new ws_1.WebSocket.Server({ server: server }); |
| 23 | + this.users = new Map(); |
| 24 | + // this.rooms = new Map(); //focus on later when constructing 2+ video conferencing functionality, SFU topology |
| 25 | + } |
| 26 | + /** |
| 27 | + * @description Upon creation and connection to the websocket server, the websocket server will add these event listeners to their socket to perform key functionality |
| 28 | + * @function initializeConnection Signaling server will listen to client when client has been connected. |
| 29 | + * when the message event is triggered, it will either send each user list to each user upon login or sending the receiver the data |
| 30 | + * @return a socket that corresponds to the client conencting. |
| 31 | + */ |
| 32 | + initializeConnection() { |
| 33 | + this.webSocketServer.on('connection', (socket) => { |
| 34 | + console.log('A user has connected to the websocket server.'); |
| 35 | + // when a client closes their browser or connection to the websocket server (onclose), their socket gets terminated and they are removed from the map of users |
| 36 | + // lastly a new user list is sent out to all clients connected to the websocket server. |
| 37 | + socket.on('close', () => { |
| 38 | + const userToDelete = this.getByValue(this.users, socket); |
| 39 | + this.users.delete(userToDelete); |
| 40 | + socket.terminate(); |
| 41 | + const userList = { ACTION_TYPE: LOGIN, payload: Array.from(this.users.keys()) }; |
| 42 | + this.webSocketServer.clients.forEach(client => client.send(JSON.stringify(userList))); |
| 43 | + }); |
| 44 | + // the meat of the websocket server, when messages are received from the client... |
| 45 | + // we will filter through what course of action to take based on data.ACTION_TYPE (see constants/actions.ts) |
| 46 | + socket.on('message', (message) => { |
| 47 | + // messages sent between the client and websocket server must be strings |
| 48 | + // importantly, messages sent to the websocket server are passed as Buffer objects encoded in utf-8 format |
| 49 | + const stringifiedMessage = message.toString('utf-8'); |
| 50 | + const data = JSON.parse(stringifiedMessage); |
| 51 | + switch (data.ACTION_TYPE) { |
| 52 | + case OFFER: |
| 53 | + this.transmit(data); |
| 54 | + break; |
| 55 | + case ANSWER: |
| 56 | + this.transmit(data); |
| 57 | + break; |
| 58 | + case ICECANDIDATE: |
| 59 | + this.transmit(data); |
| 60 | + break; |
| 61 | + case LOGIN: |
| 62 | + this.users.set(data.payload, socket); |
| 63 | + this.webSocketServer.clients.forEach(client => client.send(JSON.stringify({ |
| 64 | + ACTION_TYPE: LOGIN, |
| 65 | + payload: Array.from(this.users.keys()) |
| 66 | + }))); |
| 67 | + break; |
| 68 | + case LEAVE: |
| 69 | + this.transmit(data); |
| 70 | + break; |
| 71 | + default: |
| 72 | + console.error('error', data); |
| 73 | + break; |
| 74 | + } |
| 75 | + }); |
| 76 | + }); |
| 77 | + } |
| 78 | + /** |
| 79 | + * @description Broadcasting from sender to receiver. Accessing the receiver from the data object and if the user exists, the data is sent |
| 80 | + * @param {object} data |
| 81 | + */ |
| 82 | + transmit(data) { |
| 83 | + var _a; |
| 84 | + (_a = this.users.get(data.receiver)) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(data)); |
| 85 | + } |
| 86 | + /** |
| 87 | + * @description Getting user from Map |
| 88 | + * @function getByValue identifies user and their specific websocket |
| 89 | + * @param {Map} map |
| 90 | + * @param {WebSocket} searchValue |
| 91 | + * @returns {string} user |
| 92 | + */ |
| 93 | + getByValue(map, searchValue) { |
| 94 | + let user = ''; |
| 95 | + for (const [key, value] of map.entries()) { |
| 96 | + if (value === searchValue) |
| 97 | + user = key; |
| 98 | + } |
| 99 | + return user; |
| 100 | + } |
| 101 | +} |
| 102 | +exports.default = SignalingChannel; |
0 commit comments