From 1c5f90cff657d7b4fadca496ba0346b19d4af384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Fri, 15 Feb 2019 12:23:05 +0100 Subject: [PATCH] Added support for locking rooms --- app/lib/RoomClient.js | 93 +++++++-- app/lib/components/Controls/Sidebar.jsx | 34 +++- app/lib/components/Room.jsx | 187 ++++++++++--------- app/lib/redux/reducers/room.js | 17 ++ app/lib/redux/stateActions.js | 21 +++ app/resources/images/icon_locked_white.svg | 4 + app/resources/images/icon_unlocked_white.svg | 4 + app/stylus/components/Room.styl | 14 ++ app/stylus/components/Sidebar.styl | 10 + server/lib/Room.js | 42 +++++ server/server.js | 13 +- 11 files changed, 331 insertions(+), 108 deletions(-) create mode 100644 app/resources/images/icon_locked_white.svg create mode 100644 app/resources/images/icon_unlocked_white.svg diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js index 5957919..62a19fb 100644 --- a/app/lib/RoomClient.js +++ b/app/lib/RoomClient.js @@ -990,10 +990,22 @@ export default class RoomClient this._signalingSocket.on('connect', () => { logger.debug('signaling Peer "connect" event'); + }); + + this._signalingSocket.on('room-ready', () => + { + logger.debug('signaling Peer "room-ready" event'); this._joinRoom({ displayName, device }); }); + this._signalingSocket.on('room-locked', () => + { + logger.debug('signaling Peer "room-locked" event'); + + store.dispatch(stateActions.setRoomLockedOut()); + }); + this._signalingSocket.on('disconnect', () => { logger.warn('signaling Peer "disconnect" event'); @@ -1024,10 +1036,34 @@ export default class RoomClient this._room.receiveNotification(notification); }); - this._signalingSocket.on('active-speaker', (data) => + this._signalingSocket.on('lock-room', ({ peerName }) => { - const { peerName } = data; + store.dispatch( + stateActions.setRoomLocked()); + const peer = this._room.getPeerByName(peerName); + + if (peer) + { + this.notify(`${peer.appData.displayName} locked the room.`); + } + }); + + this._signalingSocket.on('unlock-room', ({ peerName }) => + { + store.dispatch( + stateActions.setRoomUnLocked()); + + const peer = this._room.getPeerByName(peerName); + + if (peer) + { + this.notify(`${peer.appData.displayName} unlocked the room.`); + } + }); + + this._signalingSocket.on('active-speaker', ({ peerName }) => + { store.dispatch( stateActions.setRoomActiveSpeaker(peerName)); @@ -1035,11 +1071,8 @@ export default class RoomClient this._spotlights.handleActiveSpeaker(peerName); }); - this._signalingSocket.on('display-name-changed', (data) => + this._signalingSocket.on('display-name-changed', ({ peerName, displayName: name }) => { - // eslint-disable-next-line no-shadow - const { peerName, displayName } = data; - // NOTE: Hack, we shouldn't do this, but this is just a demo. const peer = this._room.getPeerByName(peerName); @@ -1050,20 +1083,18 @@ export default class RoomClient return; } - const oldDisplayName = peer.appData.displayName; + const oldDisplayName = peer.appData.name; - peer.appData.displayName = displayName; + peer.appData.displayName = name; store.dispatch( - stateActions.setPeerDisplayName(displayName, peerName)); + stateActions.setPeerDisplayName(name, peerName)); - this.notify(`${oldDisplayName} changed their display name to ${displayName}.`); + this.notify(`${oldDisplayName} changed their display name to ${name}.`); }); - this._signalingSocket.on('profile-picture-changed', (data) => + this._signalingSocket.on('profile-picture-changed', ({ peerName, picture }) => { - const { peerName, picture } = data; - store.dispatch(stateActions.setPeerPicture(peerName, picture)); }); @@ -1292,6 +1323,42 @@ export default class RoomClient } } + async lockRoom() + { + logger.debug('lockRoom()'); + + try + { + await this.sendRequest('lock-room'); + + store.dispatch( + stateActions.setRoomLocked()); + this.notify('You locked the room.'); + } + catch (error) + { + logger.error('lockRoom() | failed: %o', error); + } + } + + async unlockRoom() + { + logger.debug('unlockRoom()'); + + try + { + await this.sendRequest('unlock-room'); + + store.dispatch( + stateActions.setRoomUnLocked()); + this.notify('You unlocked the room.'); + } + catch (error) + { + logger.error('unlockRoom() | failed: %o', error); + } + } + async _setMicProducer() { if (!this._room.canSend('audio')) diff --git a/app/lib/components/Controls/Sidebar.jsx b/app/lib/components/Controls/Sidebar.jsx index 473c523..32fa6e6 100644 --- a/app/lib/components/Controls/Sidebar.jsx +++ b/app/lib/components/Controls/Sidebar.jsx @@ -59,11 +59,13 @@ class Sidebar extends Component roomClient, toolbarsVisible, me, - screenProducer + screenProducer, + locked } = this.props; let screenState; let screenTip; + let lockState = 'unlocked'; if (me.needExtension) { @@ -86,6 +88,11 @@ class Sidebar extends Component screenTip = 'Start screen sharing'; } + if (locked) + { + lockState = 'locked'; + } + return (
+
+ { + if (locked) + { + roomClient.unlockRoom(); + } + else + { + roomClient.lockRoom(); + } + }} + />
@@ -196,7 +223,8 @@ const mapStateToProps = (state) => toolbarsVisible : state.room.toolbarsVisible, screenProducer : Object.values(state.producers) .find((producer) => producer.source === 'screen'), - me : state.me + me : state.me, + locked : state.room.locked }); export default withRoomContext(connect( diff --git a/app/lib/components/Room.jsx b/app/lib/components/Room.jsx index 12fd006..352b9df 100644 --- a/app/lib/components/Room.jsx +++ b/app/lib/components/Room.jsx @@ -73,97 +73,114 @@ class Room extends React.Component democratic : Peers }[room.mode]; - return ( - - -
- - This website uses cookies to enhance the user experience. - - - - - - -
-
- - - - - -
-
-

{room.state}

-
- - -
- + if (room.lockedOut) + { + return ( + + +
+
+ This room is locked at the moment, try again later.
- - - - +
+
+
+ ); + } + else + { + return ( + + +
+ + This website uses cookies to enhance the user experience. + + + + + + + - - - ); + + + ); + } } } diff --git a/app/lib/redux/reducers/room.js b/app/lib/redux/reducers/room.js index eed2e8a..a2a267e 100644 --- a/app/lib/redux/reducers/room.js +++ b/app/lib/redux/reducers/room.js @@ -2,6 +2,8 @@ const initialState = { url : null, state : 'new', // new/connecting/connected/disconnected/closed, + locked : false, + lockedOut : false, activeSpeakerName : null, torrentSupport : false, showSettings : false, @@ -35,6 +37,21 @@ const room = (state = initialState, action) => return { ...state, state: roomState, activeSpeakerName: null }; } + case 'SET_ROOM_LOCKED': + { + return { ...state, locked: true }; + } + + case 'SET_ROOM_UNLOCKED': + { + return { ...state, locked: false }; + } + + case 'SET_ROOM_LOCKED_OUT': + { + return { ...state, lockedOut: true }; + } + case 'SET_ROOM_ACTIVE_SPEAKER': { const { peerName } = action.payload; diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js index a837631..a797006 100644 --- a/app/lib/redux/stateActions.js +++ b/app/lib/redux/stateActions.js @@ -22,6 +22,27 @@ export const setRoomActiveSpeaker = (peerName) => }; }; +export const setRoomLocked = () => +{ + return { + type : 'SET_ROOM_LOCKED' + }; +}; + +export const setRoomUnLocked = () => +{ + return { + type : 'SET_ROOM_UNLOCKED' + }; +}; + +export const setRoomLockedOut = () => +{ + return { + type : 'SET_ROOM_LOCKED_OUT' + }; +}; + export const setMe = ({ peerName, displayName, displayNameSet, device, loginEnabled }) => { return { diff --git a/app/resources/images/icon_locked_white.svg b/app/resources/images/icon_locked_white.svg new file mode 100644 index 0000000..5395581 --- /dev/null +++ b/app/resources/images/icon_locked_white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/resources/images/icon_unlocked_white.svg b/app/resources/images/icon_unlocked_white.svg new file mode 100644 index 0000000..d281e4b --- /dev/null +++ b/app/resources/images/icon_unlocked_white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index f107704..ee1371b 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -1,6 +1,20 @@ [data-component='Room'] { AppearFadeIn(300ms); + > .locked-out { + position: fixed; + top: 50%; + left: 50%; + transform: translateX(-50%) translateY(-50%); + width: 30vw; + text-align: center; + font-family: 'Roboto'; + font-size: 2.5em; + box-shadow: 0px 5px 12px 2px rgba(17, 17, 17, 0.5); + background-color: #fff; + padding: 2vmin; + } + > .room-wrapper { position: absolute; top: 0; diff --git a/app/stylus/components/Sidebar.styl b/app/stylus/components/Sidebar.styl index 145b80f..2200c47 100644 --- a/app/stylus/components/Sidebar.styl +++ b/app/stylus/components/Sidebar.styl @@ -96,6 +96,16 @@ } } + &.lock { + &.locked { + background-image: url('/resources/images/icon_locked_white.svg'); + } + + &.unlocked { + background-image: url('/resources/images/icon_unlocked_white.svg'); + } + } + &.raise-hand { background-image: url('/resources/images/icon-hand-white.svg'); diff --git a/server/lib/Room.js b/server/lib/Room.js index 5e7530b..2d5d3ea 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -25,6 +25,9 @@ class Room extends EventEmitter // Closed flag. this._closed = false; + // Locked flag. + this._locked = false; + this._chatHistory = []; this._fileHistory = []; @@ -102,6 +105,7 @@ class Room extends EventEmitter { logger.info('handleConnection() [peerName:"%s"]', peerName); + // This will allow reconnects to join despite lock if (this._signalingPeers.has(peerName)) { logger.warn( @@ -114,6 +118,11 @@ class Room extends EventEmitter signalingPeer.socket.disconnect(); this._signalingPeers.delete(peerName); } + else if (this._locked) // Don't allow connections to a locked room + { + socket.emit('room-locked'); + socket.disconnect(true); + } const signalingPeer = { peerName : peerName, socket : socket }; @@ -127,6 +136,7 @@ class Room extends EventEmitter this._signalingPeers.set(peerName, signalingPeer); this._handleSignalingPeer(signalingPeer); + socket.emit('room-ready'); } authCallback(data) @@ -308,6 +318,38 @@ class Room extends EventEmitter ); }); + signalingPeer.socket.on('lock-room', (request, cb) => + { + // Return no error + cb(null); + + this._locked = true; + + // Spread to others + signalingPeer.socket.broadcast.to(this._roomId).emit( + 'lock-room', + { + peerName : signalingPeer.peerName + } + ); + }); + + signalingPeer.socket.on('unlock-room', (request, cb) => + { + // Return no error + cb(null); + + this._locked = false; + + // Spread to others + signalingPeer.socket.broadcast.to(this._roomId).emit( + 'unlock-room', + { + peerName : signalingPeer.peerName + } + ); + }); + signalingPeer.socket.on('send-file', (request, cb) => { // Return no error diff --git a/server/server.js b/server/server.js index 9a0583b..21f46d1 100755 --- a/server/server.js +++ b/server/server.js @@ -10,7 +10,6 @@ const https = require('https'); const http = require('http'); const express = require('express'); const compression = require('compression'); -const url = require('url'); const Logger = require('./lib/Logger'); const Room = require('./lib/Room'); const Dataporten = require('passport-dataporten'); @@ -46,12 +45,12 @@ const dataporten = new Dataporten.Setup(config.oauth2); app.all('*', (req, res, next) => { - if(req.secure) + if (req.secure) { return next(); } - res.redirect('https://' + req.hostname + req.url); + res.redirect(`https://${req.hostname}${req.url}`); }); app.use(dataporten.passport.initialize()); @@ -71,10 +70,10 @@ app.get('/login', (req, res, next) => dataporten.setupLogout(app, '/logout'); -app.get('/', function (req, res) { - console.log(req.url); - res.sendFile(`${__dirname}/public/chooseRoom.html`); -}) +app.get('/', (req, res) => +{ + res.sendFile(`${__dirname}/public/chooseRoom.html`); +}); app.get( '/auth-callback',