From 88e83901649304542a2e2c04a042dcfe08418af8 Mon Sep 17 00:00:00 2001 From: williamtnguyen <42355738+williamtnguyen@users.noreply.github.com> Date: Sun, 2 May 2021 17:08:58 -0700 Subject: [PATCH] Refactor rtc-server to separate directory (#23) * Refactor rtc-server to separate directory * Fix adding clients for mediasoup and displaying speaker * Remove redisClientId from event parameters This change removes redisClientId from params of all socket events. Now, rtc-server stores in memory mapping of rtcSocketId to redisClientId. * Remove dependencies and address lint errors * Fix declined client notitification Co-authored-by: Gary C --- client/src/pages/Landing.tsx | 14 +- client/src/pages/Room.tsx | 274 +++++++------ client/src/utils/MediasoupPeer.ts | 239 ++++++------ client/src/utils/helpers.ts | 3 +- client/src/utils/rtc-socket-client.ts | 22 ++ ...ket-client.ts => session-socket-client.ts} | 11 +- client/tslint.json | 5 +- {server => rtc-server}/mediasoup-config.ts | 26 +- rtc-server/package.json | 32 ++ rtc-server/server.ts | 15 + rtc-server/tsconfig.json | 69 ++++ rtc-server/tslint.json | 21 + rtc-server/utils/Rooms.ts | 359 ++++++++++++++++++ rtc-server/utils/attach-socket-events.ts | 177 +++++++++ server/package.json | 1 - server/server.ts | 10 +- server/utils/Rooms.ts | 232 +---------- ...ket-handler.ts => attach-socket-events.ts} | 219 +++-------- 18 files changed, 1085 insertions(+), 644 deletions(-) create mode 100644 client/src/utils/rtc-socket-client.ts rename client/src/utils/{socket-client.ts => session-socket-client.ts} (91%) rename {server => rtc-server}/mediasoup-config.ts (69%) create mode 100644 rtc-server/package.json create mode 100644 rtc-server/server.ts create mode 100644 rtc-server/tsconfig.json create mode 100644 rtc-server/tslint.json create mode 100644 rtc-server/utils/Rooms.ts create mode 100644 rtc-server/utils/attach-socket-events.ts rename server/utils/{socket-handler.ts => attach-socket-events.ts} (57%) diff --git a/client/src/pages/Landing.tsx b/client/src/pages/Landing.tsx index ba57e22..5fed733 100644 --- a/client/src/pages/Landing.tsx +++ b/client/src/pages/Landing.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { createConnection } from '../utils/socket-client'; +import { openSessionSocket } from '../utils/session-socket-client'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { SocketContext } from '../App'; import CreateSessionForm from '../components/CreateSessionForm'; @@ -13,10 +13,14 @@ const { TabPane } = Tabs; const Landing = (props: RouteComponentProps & any) => { const { setClientId, setClientDisplayName } = useContext(SocketContext); - const startSession = async ( - { displayName, roomType }: { displayName: string, roomType: string } - ) => { - const newSocket = await createConnection(displayName, roomType, true); + const startSession = async ({ + displayName, + roomType, + }: { + displayName: string; + roomType: string; + }) => { + const newSocket = await openSessionSocket(displayName, roomType, true); setClientId(newSocket.id); setClientDisplayName(displayName); diff --git a/client/src/pages/Room.tsx b/client/src/pages/Room.tsx index f411c9b..88fafdf 100644 --- a/client/src/pages/Room.tsx +++ b/client/src/pages/Room.tsx @@ -1,6 +1,10 @@ import React, { useState, useEffect, useContext } from 'react'; import { RouteComponentProps, withRouter, useHistory } from 'react-router-dom'; -import { createConnection, roomSocketEvents } from '../utils/socket-client'; +import { + openSessionSocket, + subscribeToRoomEvents, +} from '../utils/session-socket-client'; +import { openRtcSocket } from '../utils/rtc-socket-client'; import { SocketContext } from '../App'; import Video from '../components/Video'; import { ClientContext } from '../contexts/clientContext'; @@ -11,7 +15,19 @@ import Playlist from '../components/Playlist'; import RoomParticipants from '../components/RoomParticipants'; import { MediasoupPeer } from '../utils/MediasoupPeer'; -import { Row, Col, Modal, Form, Input, Button, Select, Alert, Space, notification, Spin } from 'antd'; +import { + Row, + Col, + Modal, + Form, + Input, + Button, + Select, + Alert, + Space, + notification, + Spin, +} from 'antd'; import roomStyles from '../styles/pages/room.module.scss'; const { Option } = Select; @@ -53,14 +69,18 @@ const Room = ({ location, match }: RoomProps & any) => { ? [{ id: clientId, name: clientDisplayName, isMuted: false }] : [] ); - const [waitingClients, setWaitingClients] = useState<{[socketId: string]: string}>({}); + const [waitingClients, setWaitingClients] = useState<{ + [socketId: string]: string; + }>({}); const [enterDisplayName, setEnterDisplayName] = useState(false); const [isMuted, setIsMuted] = useState(false); const [selectNewAudio, setSelectNewAudio] = useState(false); const [canEnter, setCanEnter] = useState(clientId ? true : false); - const [socket, setSocket] = useState(location.socket ? location.socket : {}); + const [sessionSocket, setSessionSocket] = useState( + location.socket ? location.socket : {} + ); const [mediasoupPeer, setMediasoupPeer] = useState(); const [audioDevices, setAudioDevices] = useState([]); const [selectedAudioDevice, setSelectedAudioDevice] = useState<{ @@ -91,47 +111,53 @@ const Room = ({ location, match }: RoomProps & any) => { youtubeID: roomYoutubeId, }); setCanEnter(true); - setHostEvents(location.socket); - setWaitingRoomEvents(location.socket); - updateClientList(location.socket); - setSocket(location.socket); - roomSocketEvents(location.socket, dispatches); - await startAudioCall(location.socket); + attachHostNotifs(location.socket); + setSessionSocket(location.socket); + subscribeToHostEvents(location.socket); + subscribeToClientListUpdates(location.socket); + subscribeToRoomEvents(location.socket, dispatches); + await startAudioCall(location.socket.id); } - // Joining client from landing, inputted displayName, or Room client + // Joining client from landing, inputted displayName, or Room client // that already made connection and refreshed - else if ((!clientId && clientDisplayName) || (clientId && clientDisplayName)) { + else if ( + (!clientId && clientDisplayName) || + (clientId && clientDisplayName) + ) { const { roomId } = match.params; - const socketConnection = await createConnection( + const socketConnection = await openSessionSocket( clientDisplayName, '', canEnter, roomId ); - setSocket(socketConnection); + setSessionSocket(socketConnection); if (canEnter) { await enterRoom(socketConnection); - } - else { + } else { socketConnection.on('accept', async () => { rejoinSocket(roomId, socketConnection); setCanEnter(true); await enterRoom(socketConnection); }); - socketConnection.on('decline', () => history.push('/')); + socketConnection.on('decline', () => { + socketConnection.disconnect(); + history.push('/'); + }); - const callback = async (roomType: string) => { - if (roomType !== 'private') { - rejoinSocket(roomId, socketConnection); - await enterRoom(socketConnection); - } + const admitClient = async () => { + rejoinSocket(roomId, socketConnection); + await enterRoom(socketConnection); }; - - socketConnection.emit('getRoomType', { - clientName: clientDisplayName, - roomId - }, callback); + socketConnection.emit( + 'getRoomType', + { + clientName: clientDisplayName, + roomId, + }, + admitClient + ); } } // Joining client from direct URL, prompt for displayName @@ -140,14 +166,17 @@ const Room = ({ location, match }: RoomProps & any) => { } }; - // Subscribes to updateClientList broadcasts from WebSocketServer - const updateClientList = (connectingSocket: SocketIOClient.Socket) => { + const subscribeToClientListUpdates = ( + connectingSocket: SocketIOClient.Socket + ) => { connectingSocket.on('updateClientList', (newClientList: Client[]) => { setClients(newClientList); }); }; - const updatePlaylist = (connectingSocket: SocketIOClient.Socket) => { + const subscribeToPlaylistUpdates = ( + connectingSocket: SocketIOClient.Socket + ) => { connectingSocket.on('updatePlaylist', (newPlaylist: string[]) => { clientDispatch({ type: ClientStates.DELETE_VIDEO, @@ -156,71 +185,79 @@ const Room = ({ location, match }: RoomProps & any) => { }); }; - const handleFormSubmit = (displayNameInput: string) => { - setClientDisplayName(displayNameInput); - setEnterDisplayName(false); - }; - - const rejoinSocket = (roomId: string, connectingSocket: SocketIOClient.Socket) => { - setCanEnter(true); - const clientData = { - roomId, - clientId: connectingSocket.id, - clientName: clientDisplayName, - roomType: '', - canJoin: true - }; - - connectingSocket.emit('join', clientData); - }; - - const setWaitingRoomEvents = (connectingSocket: SocketIOClient.Socket) => { + const subscribeToHostEvents = (connectingSocket: SocketIOClient.Socket) => { connectingSocket.on('newHost', (hostName: string, hostId: string) => { notification.open({ message: 'New Host', - description: - `${connectingSocket.id !== hostId ? `${hostName} is` : 'You are'} now the host`, - duration: 8 + description: `${ + connectingSocket.id !== hostId ? `${hostName} is` : 'You are' + } now the host`, + duration: 8, }); if (connectingSocket.id === hostId) { - setHostEvents(connectingSocket); + attachHostNotifs(connectingSocket); } }); }; - const setHostEvents = (connectingSocket: SocketIOClient.Socket) => { - connectingSocket.on('waitingClient', ( - { socketId, clientName }: {socketId: string, clientName: string} - ) => { - setWaitingClients({ - ...waitingClients, - [socketId]: clientName - }); - }); - - connectingSocket.on('updateWaitingClients', ( - { waitingClientList, clientIdLeft }: { - waitingClientList: {[socketId: string]: string}, - clientIdLeft: string + const attachHostNotifs = (connectingSocket: SocketIOClient.Socket) => { + connectingSocket.on( + 'waitingClient', + ({ + waitingClients, + }: { + waitingClients: { [socketId: string]: string }; }) => { - setWaitingClients(waitingClientList); - if (clientIdLeft.length > 0) notification.close(clientIdLeft); - }); + setWaitingClients(waitingClients); + } + ); + + connectingSocket.on( + 'updateWaitingClients', + ({ + waitingClientList, + clientIdLeft, + }: { + waitingClientList: { [socketId: string]: string }; + clientIdLeft: string; + }) => { + setWaitingClients(waitingClientList); + if (clientIdLeft.length > 0) notification.close(clientIdLeft); + } + ); + }; + + const rejoinSocket = ( + roomId: string, + connectingSocket: SocketIOClient.Socket + ) => { + setCanEnter(true); + const clientData = { + roomId, + clientId: connectingSocket.id, + clientName: clientDisplayName, + roomType: '', + canJoin: true, + }; + + connectingSocket.emit('join', clientData); }; const enterRoom = async (connectingSocket: SocketIOClient.Socket) => { - setWaitingRoomEvents(connectingSocket); setClientId(connectingSocket.id); - updateClientList(connectingSocket); - updatePlaylist(connectingSocket); - roomSocketEvents(connectingSocket, dispatches); - await startAudioCall(connectingSocket); + subscribeToHostEvents(connectingSocket); + subscribeToClientListUpdates(connectingSocket); + subscribeToPlaylistUpdates(connectingSocket); + subscribeToRoomEvents(connectingSocket, dispatches); + await startAudioCall(connectingSocket.id); }; - const startAudioCall = async (socket: SocketIOClient.Socket) => { + const startAudioCall = async (redisClientId: string) => { + const { roomId } = match.params; + const rtcSocket = await openRtcSocket(roomId, redisClientId); const deviceId = await setMediaDevices(); - await startMediasoup(socket, deviceId); + await startMediasoup(rtcSocket, deviceId); }; const setMediaDevices = async () => { @@ -242,10 +279,10 @@ const Room = ({ location, match }: RoomProps & any) => { }; const startMediasoup = async ( - socket: SocketIOClient.Socket, + rtcSocket: SocketIOClient.Socket, audioDeviceId: string ) => { - const peer = new MediasoupPeer(socket, remoteAudiosDiv); + const peer = new MediasoupPeer(rtcSocket, remoteAudiosDiv); setMediasoupPeer(peer); await peer.init(); await peer.produce(audioDeviceId); @@ -280,10 +317,15 @@ const Room = ({ location, match }: RoomProps & any) => { const newClients = clients; for (const client of newClients) { - if (socket.id === client.id) client.isMuted = !client.isMuted; + if (sessionSocket.id === client.id) client.isMuted = !client.isMuted; } setClients(newClients); - socket.emit('mute', { id: socket.id }); + sessionSocket.emit('mute', { id: sessionSocket.id }); + }; + + const handleFormSubmit = (displayNameInput: string) => { + setClientDisplayName(displayNameInput); + setEnterDisplayName(false); }; const handleSelectAudioModal = () => { @@ -294,7 +336,7 @@ const Room = ({ location, match }: RoomProps & any) => { const newWaitingClients = waitingClients; delete newWaitingClients[socketId]; setWaitingClients(newWaitingClients); - socket.emit('waitingResponse', { socketId, status }); + sessionSocket.emit('waitingResponse', { socketId, status }); notification.close(socketId); }; @@ -327,38 +369,37 @@ const Room = ({ location, match }: RoomProps & any) => { ) : !canEnter ? (

Please wait while the host lets you in

- +
) : (
- {selectNewAudio && - selectedAudioDevice.deviceId && ( - -
- -
-
- )} - {Object.keys(waitingClients).map((socketId) => ( + {selectNewAudio && selectedAudioDevice.deviceId && ( + +
+ +
+
+ )} + {Object.keys(waitingClients).map((socketId) => notification.open({ key: socketId, message: 'Waiting Room Notification', @@ -377,7 +418,8 @@ const Room = ({ location, match }: RoomProps & any) => {