diff --git a/openvidu-getaroom/web/app.js b/openvidu-getaroom/web/app.js index cc17beb8..7805b77f 100644 --- a/openvidu-getaroom/web/app.js +++ b/openvidu-getaroom/web/app.js @@ -1,21 +1,22 @@ -var OV; -var session; -var publisher; -var sessionId; -var audioEnabled = true; -var videoEnabled = true; -var numOfVideos = 0; +var OV; // OpenVidu object to initialize a session +var session; // Session object where the user will connect +var publisher; // Publisher object which the user will publish +var sessionId; // Unique identifier of the session +var audioEnabled = true; // True if the audio track of publisher is active +var videoEnabled = true; // True if the video track of publisher is active +var numOfVideos = 0; // Keeps track of the number of videos that are being shown // Check if the URL already has a room window.addEventListener('load', function () { - sessionId = window.location.hash; + sessionId = window.location.hash; // For 'https://myurl/#roomId', sessionId would be '#roomId' if (sessionId) { - // The URL has a session id + // The URL has a session id. Join the room right away console.log("Joining to room " + sessionId); showSessionHideJoin(); joinRoom(sessionId); } else { + // The URL has not a session id. Show welcome page showJoinHideSession(); } }); @@ -38,11 +39,11 @@ function joinRoom(sessionId) { // --- 1) Get an OpenVidu object and init a session with a sessionId --- - // Init OpenVidu object OV = new OpenVidu(); - // We will join the video-call "sessionId". This parameter must start with the URL of OpenVidu Server, with secure WebSocket protocol ('wss://') - session = OV.initSession("wss://" + location.hostname + ":8443/" + sessionId + '?secret=MY_SECRET'); + // We will join the video-call "sessionId". As there's no server, this parameter must start with the URL of + // OpenVidu Server (with secure websocket protocol: "wss://") and must include the OpenVidu secret at the end + session = OV.initSession("wss://" + location.hostname + ":8443/" + sessionId + "?secret=MY_SECRET"); // --- 2) Specify the actions when events take place --- @@ -51,6 +52,7 @@ function joinRoom(sessionId) { session.on('streamCreated', function (event) { // Subscribe to the Stream to receive it. HTML video will be appended to element with 'subscriber' id var subscriber = session.subscribe(event.stream, 'videos'); + // When the new video is added to DOM, update the page layout to fit one more participant subscriber.on('videoElementCreated', function (event) { numOfVideos++; updateLayout(); @@ -59,6 +61,7 @@ function joinRoom(sessionId) { // On every new Stream destroyed... session.on('streamDestroyed', function (event) { + // Update the page layout numOfVideos--; updateLayout(); }); @@ -66,8 +69,7 @@ function joinRoom(sessionId) { // --- 3) Connect to the session --- - // 'token' param irrelevant when using insecure version of OpenVidu. Second param will be received by every user - // in Stream.connection.data property, which will be appended to DOM as the user's nickname + // Remember 'userId' param (usually called 'token') is irrelevant when using the insecure version of OpenVidu session.connect(userId, function (error) { // If the connection is successful, initialize a publisher and publish to the session @@ -82,9 +84,10 @@ function joinRoom(sessionId) { }); publisher.on('videoElementCreated', function (event) { + // When your own video is added to DOM, update the page layout to fit it numOfVideos++; updateLayout(); - $(event.element).prop('muted', true); + $(event.element).prop('muted', true); // Mute local video }); // --- 5) Publish your stream --- @@ -96,9 +99,11 @@ function joinRoom(sessionId) { } }); + // Update the URL shown in the browser's navigation bar to show the session id var pathname = (location.pathname.slice(-1) === "/" ? location.pathname : location.pathname+"/"); window.history.pushState("", "", pathname + sessionId); + // Auxiliary methods to show the session's view showSessionHideJoin(); initializeSessionView(); @@ -107,7 +112,7 @@ function joinRoom(sessionId) { function leaveRoom() { - + // --- 6) Leave the session by calling 'disconnect' method over the Session object --- session.disconnect(); diff --git a/openvidu-js-java/src/main/java/io/openvidu/js/java/LoginController.java b/openvidu-js-java/src/main/java/io/openvidu/js/java/LoginController.java index 055978e4..2445875e 100644 --- a/openvidu-js-java/src/main/java/io/openvidu/js/java/LoginController.java +++ b/openvidu-js-java/src/main/java/io/openvidu/js/java/LoginController.java @@ -46,15 +46,18 @@ public class LoginController { public ResponseEntity login(@RequestBody String userPass, HttpSession httpSession) throws ParseException { System.out.println("Logging in | {user, pass}=" + userPass); + // Retrieve params from POST body JSONObject userPassJson = (JSONObject) new JSONParser().parse(userPass); String user = (String) userPassJson.get("user"); String pass = (String) userPassJson.get("pass"); - if (login(user, pass)) { - System.out.println("'" + user + "' has logged in"); + if (login(user, pass)) { // Correct user-pass + // Validate session and return OK + // Value stored in HttpSession allows us to identify the user in future requests httpSession.setAttribute("loggedUser", user); return new ResponseEntity<>(HttpStatus.OK); - } else { + } else { // Wrong user-pass + // Invalidate session and return error httpSession.invalidate(); return new ResponseEntity<>("User/Pass incorrect", HttpStatus.UNAUTHORIZED); } diff --git a/openvidu-js-java/src/main/java/io/openvidu/js/java/SessionController.java b/openvidu-js-java/src/main/java/io/openvidu/js/java/SessionController.java index 5cc1ccfc..a5e9daf3 100644 --- a/openvidu-js-java/src/main/java/io/openvidu/js/java/SessionController.java +++ b/openvidu-js-java/src/main/java/io/openvidu/js/java/SessionController.java @@ -51,10 +51,18 @@ public class SessionController { System.out.println("Getting sessionId and token | {sessionName}=" + sessionNameParam); JSONObject sessionJSON = (JSONObject) new JSONParser().parse(sessionNameParam); + + // The video-call to connect ("TUTORIAL") String sessionName = (String) sessionJSON.get("session"); + + // Role associated to this user OpenViduRole role = LoginController.users.get(httpSession.getAttribute("loggedUser")).role; + + // Optional data to be passed to other users when this user connects to the video-call + // In this case, a JSON with the value we stored in the HttpSession object on login String serverData = "{\"serverData\": \"" + httpSession.getAttribute("loggedUser") + "\"}"; + // Build tokenOptions object with the serverData and the role TokenOptions tokenOptions = new TokenOptions.Builder().data(serverData).role(role).build(); JSONObject responseJson = new JSONObject(); @@ -63,16 +71,25 @@ public class SessionController { // Session already exists: return existing sessionId and a new token System.out.println("Existing session " + sessionName); try { + + // Get the existing sessionId from our collection with + // the sessionName param ("TUTORIAL") String sessionId = this.mapSessions.get(sessionName).getSessionId(); + // Generate a new token with the recently created tokenOptions String token = this.mapSessions.get(sessionName).generateToken(tokenOptions); - + + // Update our collection storing the new token this.mapSessionIdsTokens.get(sessionId).put(token, role); - + + // Prepare the response with the sessionId and the token responseJson.put(0, sessionId); responseJson.put(1, token); - + + // Return the response to the client return new ResponseEntity<>(responseJson, HttpStatus.OK); + } catch (Exception e) { + // If error generate an error message and return it to client return getErrorResponse(e); } @@ -80,19 +97,28 @@ public class SessionController { // New session: return a new sessionId and token System.out.println("New session " + sessionName); try { + + // Create a new OpenVidu Session Session session = this.openVidu.createSession(); + // Get the sessionId String sessionId = session.getSessionId(); + // Generate a new token with the recently created tokenOptions String token = session.generateToken(tokenOptions); + // Store the session and the token in our collections this.mapSessions.put(sessionName, session); this.mapSessionIdsTokens.put(sessionId, new ConcurrentHashMap<>()); this.mapSessionIdsTokens.get(sessionId).put(token, role); + // Prepare the response with the sessionId and the token responseJson.put(0, sessionId); responseJson.put(1, token); + // Return the response to the client return new ResponseEntity<>(responseJson, HttpStatus.OK); + } catch (Exception e) { + // If error generate an error message and return it to client return getErrorResponse(e); } } @@ -109,30 +135,36 @@ public class SessionController { } System.out.println("Removing user | {sessionName, token}=" + sessionNameToken); + // Retrieve the params from BODY JSONObject sessionNameTokenJSON = (JSONObject) new JSONParser().parse(sessionNameToken); String sessionName = (String) sessionNameTokenJSON.get("sessionName"); String token = (String) sessionNameTokenJSON.get("token"); + // If the session exists ("TUTORIAL" in this case) if (this.mapSessions.get(sessionName) != null) { String sessionId = this.mapSessions.get(sessionName).getSessionId(); if (this.mapSessionIdsTokens.containsKey(sessionId)) { + // If the token exists if (this.mapSessionIdsTokens.get(sessionId).remove(token) != null) { // User left the session if (this.mapSessionIdsTokens.get(sessionId).isEmpty()) { - // Last user left the session + // Last user left: session must be removed this.mapSessions.remove(sessionName); } return new ResponseEntity<>(HttpStatus.OK); } else { + // The TOKEN wasn't valid System.out.println("Problems in the app server: the TOKEN wasn't valid"); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } else { + // The SESSIONID wasn't valid System.out.println("Problems in the app server: the SESSIONID wasn't valid"); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } else { + // The SESSION does not exist System.out.println("Problems in the app server: the SESSION does not exist"); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } diff --git a/openvidu-js-java/src/main/resources/static/app.js b/openvidu-js-java/src/main/resources/static/app.js index 1814000c..f55a7016 100644 --- a/openvidu-js-java/src/main/resources/static/app.js +++ b/openvidu-js-java/src/main/resources/static/app.js @@ -73,7 +73,7 @@ function joinSession() { }; initMainVideo(event.element, userData); appendUserData(event.element, userData); - $(event.element).prop('muted', true); + $(event.element).prop('muted', true); // Mute local video }); @@ -116,17 +116,18 @@ function leaveSession() { -/* APPLICATION BACKEND METHODS */ +/* APPLICATION REST METHODS */ function logIn() { - var user = $("#user").val(); - userName = user; - var pass = $("#pass").val(); - var jsonBody = JSON.stringify({ + var user = $("#user").val(); // Username + var pass = $("#pass").val(); // Password + var jsonBody = JSON.stringify({ // Body of POST request 'user': user, 'pass': pass }); + userName = user; + httpRequest('POST', 'api-login/login', jsonBody, 'Login WRONG', function successCallback(response) { console.warn(userName + ' login'); $("#name-user").text(user); @@ -147,26 +148,30 @@ function logOut() { } function getSessionIdAndToken(callback) { - nickName = $("#participantName").val(); - sessionName = $("#sessionName").val(); - var jsonBody = JSON.stringify({ + sessionName = $("#sessionName").val(); // Video-call chosen by the user + nickName = $("#participantName").val(); // Nickname chosen by the user + + var jsonBody = JSON.stringify({ // Body of POST request 'session': sessionName }); + // Send POST request httpRequest('POST', 'api-sessions/get-sessionid-token', jsonBody, 'Request of SESSIONID and TOKEN gone WRONG:', function successCallback(response) { - sessionId = response[0]; - token = response[1]; + sessionId = response[0]; // Get sessionId from response + token = response[1]; // Get token from response console.warn('Request of SESSIONID and TOKEN gone WELL (SESSIONID:' + sessionId + ", TOKEN:" + token + ")"); - callback(); + callback(); // Continue the join operation }); } function removeUser() { + // Body of POST request with the name of the session and the token of the leaving user var jsonBody = JSON.stringify({ 'sessionName': sessionName, 'token': token }); + // Send POST request httpRequest('POST', 'api-sessions/remove-user', jsonBody, 'User couldn\'t be removed from session', function successCallback(response) { console.warn(userName + " correctly removed from session"); }); @@ -195,7 +200,7 @@ function httpRequest(method, url, body, errorMsg, callback) { } } -/* APPLICATION BACKEND METHODS */ +/* APPLICATION REST METHODS */ diff --git a/openvidu-js-node/public/app.js b/openvidu-js-node/public/app.js index 1814000c..a5f9437e 100644 --- a/openvidu-js-node/public/app.js +++ b/openvidu-js-node/public/app.js @@ -27,11 +27,11 @@ function joinSession() { // Subscribe to the Stream to receive it // HTML video will be appended to element with 'video-container' id var subscriber = session.subscribe(event.stream, 'video-container'); - + // When the HTML video has been appended to DOM... subscriber.on('videoElementCreated', function (event) { - - // Add a new HTML element for the user's name and nickname over its video + + // Add a new

element for the user's name and nickname just below its video appendUserData(event.element, subscriber.stream.connection); }); }); @@ -42,6 +42,7 @@ function joinSession() { removeUserData(event.stream.connection); }); + // --- 3) Connect to the session passing the retrieved token and some more data from // the client (in this case a JSON with the nickname chosen by the user) --- @@ -73,7 +74,7 @@ function joinSession() { }; initMainVideo(event.element, userData); appendUserData(event.element, userData); - $(event.element).prop('muted', true); + $(event.element).prop('muted', true); // Mute lcoal video }); @@ -116,18 +117,19 @@ function leaveSession() { -/* APPLICATION BACKEND METHODS */ +/* APPLICATION REST METHODS */ function logIn() { - var user = $("#user").val(); - userName = user; - var pass = $("#pass").val(); - var jsonBody = JSON.stringify({ + var user = $("#user").val(); // Username + var pass = $("#pass").val(); // Password + var jsonBody = JSON.stringify({ // Body of POST request 'user': user, 'pass': pass }); - httpRequest('POST', 'api-login/login', jsonBody, 'Login WRONG', function successCallback(response) { + userName = user; + + httpRequest('POST', '/api-login/login', jsonBody, 'Login WRONG', function successCallback(response){ // Send POST request console.warn(userName + ' login'); $("#name-user").text(user); $("#not-logged").hide(); @@ -147,26 +149,29 @@ function logOut() { } function getSessionIdAndToken(callback) { - nickName = $("#participantName").val(); - sessionName = $("#sessionName").val(); - var jsonBody = JSON.stringify({ + sessionName = $("#sessionName").val(); // Video-call chosen by the user + nickName = $("#participantName").val(); // Nickname chosen by the user + var jsonBody = JSON.stringify({ // Body of POST request 'session': sessionName }); + // Send POST request httpRequest('POST', 'api-sessions/get-sessionid-token', jsonBody, 'Request of SESSIONID and TOKEN gone WRONG:', function successCallback(response) { - sessionId = response[0]; - token = response[1]; + sessionId = response[0]; // Get sessionId from response + token = response[1]; // Get token from response console.warn('Request of SESSIONID and TOKEN gone WELL (SESSIONID:' + sessionId + ", TOKEN:" + token + ")"); - callback(); + callback(); // Continue the join operation }); } function removeUser() { + // Body of POST request with the name of the session and the token of the leaving user var jsonBody = JSON.stringify({ 'sessionName': sessionName, 'token': token }); + // Send POST request httpRequest('POST', 'api-sessions/remove-user', jsonBody, 'User couldn\'t be removed from session', function successCallback(response) { console.warn(userName + " correctly removed from session"); }); @@ -195,7 +200,7 @@ function httpRequest(method, url, body, errorMsg, callback) { } } -/* APPLICATION BACKEND METHODS */ +/* APPLICATION REST METHODS */ diff --git a/openvidu-js-node/server.js b/openvidu-js-node/server.js index d5b7af84..c64b697f 100644 --- a/openvidu-js-node/server.js +++ b/openvidu-js-node/server.js @@ -60,15 +60,17 @@ var users = [{ }]; -// Environment variables +// Environment variable: URL where our OpenVidu server is listening var OPENVIDU_URL = process.argv[2]; +// Environment variable: secret shared with our OpenVidu server var OPENVIDU_SECRET = process.argv[3]; -// OpenVidu object +// OpenVidu object to ask openvidu-server for sessionId and token var OV = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET); -// Objects for storing active sessions and users +// Collection to pair session names and OpenVidu Session objects var mapSessionNameSession = {}; +// Collection to pair sessionId's (identifiers of Session objects) and tokens var mapSessionIdTokens = {}; /* CONFIGURATION */ @@ -79,15 +81,20 @@ var mapSessionIdTokens = {}; // Login app.post('/api-login/login', function (req, res) { + + // Retrieve params from POST body var user = req.body.user; var pass = req.body.pass; console.log("Logging in | {user, pass}={" + user + ", " + pass + "}"); - if (login(user, pass)) { + if (login(user, pass)) { // Correct user-pass + // Validate session and return OK + // Value stored in req.session allows us to identify the user in future requests console.log("'" + user + "' has logged in"); req.session.loggedUser = user; res.status(200).send(); - } else { + } else { // Wrong user-pass + // Invalidate session and return error console.log("'" + user + "' invalid credentials"); req.session.destroy(); res.status(401).send('User/Pass incorrect'); @@ -107,22 +114,40 @@ app.post('/api-sessions/get-sessionid-token', function (req, res) { req.session.destroy(); res.status(401).send('User not logged'); } else { + // The video-call to connect ("TUTORIAL") var sessionName = req.body.session; + + // Role associated to this user var role = users.find(u => (u.user === req.session.loggedUser)).role; + + // Optional data to be passed to other users when this user connects to the video-call + // In this case, a JSON with the value we stored in the req.session object on login var serverData = '{"serverData": "' + req.session.loggedUser + '"}'; console.log("Getting sessionId and token | {sessionName}={" + sessionName + "}"); - + + // Build tokenOptions object with the serverData and the role var tokenOptions = new TokenOptions.Builder() .data(serverData) .role(role) .build(); if (mapSessionNameSession[sessionName]) { + // Session already exists: return existing sessionId and a new token console.log('Existing session ' + sessionName); + + // Get the existing Session from the collection var mySession = mapSessionNameSession[sessionName]; + + // Generate a new token asynchronously with the recently created tokenOptions mySession.generateToken(tokenOptions, function (token) { + + // Get the existing sessionId var sessionId = mySession.getSessionId(); + + // Store the new token in the collection of tokens mapSessionIdTokens[sessionId].push(token); + + // Return the sessionId and token to the client console.log('SESSIONID: ' + sessionId); console.log('TOKEN: ' + token); res.status(200).send({ @@ -130,17 +155,28 @@ app.post('/api-sessions/get-sessionid-token', function (req, res) { 1: token }); }); - } else { + } else { // New session: return a new sessionId and a new token + // Create a new OpenVidu Session console.log('New session ' + sessionName); var mySession = OV.createSession(); + + // Get the sessionId asynchronously mySession.getSessionId(function (sessionId) { + + // Store the new Session in the collection of Sessions mapSessionNameSession[sessionName] = mySession; + // Store a new empty array in the collection of tokens mapSessionIdTokens[sessionId] = []; - + + // Generate a new token asynchronously with the recently created tokenOptions mySession.generateToken(tokenOptions, function (token) { + + // Store the new token in the collection of tokens mapSessionIdTokens[sessionId].push(token); console.log('SESSIONID: ' + sessionId); console.log('TOKEN: ' + token); + + // Return the sessionId and token to the client res.status(200).send({ 0: sessionId, 1: token @@ -157,16 +193,21 @@ app.post('/api-sessions/remove-user', function (req, res) { req.session.destroy(); res.status(401).send('User not logged'); } else { + // Retrieve params from POST body var sessionName = req.body.sessionName; var token = req.body.token; console.log('Removing user | {sessionName, token}={' + sessionName + ", " + token + '}'); - + + // If the session exists ("TUTORIAL" in this case) var mySession = mapSessionNameSession[sessionName]; if (mySession) { var tokens = mapSessionIdTokens[mySession.getSessionId()]; if (tokens) { var index = tokens.indexOf(token); - if (index !== -1) { // User left the session + + // If the token exists + if (index !== -1) { + // Token removed! tokens.splice(index, 1); console.log(sessionName + ': ' + mapSessionIdTokens[mySession.getSessionId()].toString()); } else { @@ -174,7 +215,8 @@ app.post('/api-sessions/remove-user', function (req, res) { console.log(msg); res.status(500).send(msg); } - if (mapSessionIdTokens[mySession.getSessionId()].length == 0) { // Last user left the session + if (mapSessionIdTokens[mySession.getSessionId()].length == 0) { + // Last user left: session must be removed console.log(sessionName + ' empty!'); delete mapSessionNameSession[sessionName]; } diff --git a/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/LoginController.java b/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/LoginController.java index 812f1748..00ed026d 100644 --- a/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/LoginController.java +++ b/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/LoginController.java @@ -49,20 +49,30 @@ public class LoginController { @RequestMapping(value = "/dashboard", method = { RequestMethod.GET, RequestMethod.POST }) public String login(@RequestParam(name = "user", required = false) String user, - @RequestParam(name = "pass", required = false) String pass, Model model, HttpSession httpSession) { + @RequestParam(name = "pass", required = false) String pass, + Model model, HttpSession httpSession) { + // Check if the user is already logged in String userName = (String) httpSession.getAttribute("loggedUser"); - if (userName != null) { // User is already logged + if (userName != null) { + // User is already logged. Immediately return dashboard model.addAttribute("username", userName); return "dashboard"; } - System.out.println("Logging in | {user, pass}={" + user + ", " + pass + "}"); - if (login(user, pass)) { // User is logging in - System.out.println("'" + user + "' has logged in"); + + // User wasn't logged and wants to + if (login(user, pass)) { // Correct user-pass + + // Validate session and return OK + // Value stored in HttpSession allows us to identify the user in future requests httpSession.setAttribute("loggedUser", user); model.addAttribute("username", user); + + // Return dashboard.html template return "dashboard"; - } else { + + } else { // Wrong user-pass + // Invalidate session and redirect to index.html httpSession.invalidate(); return "redirect:/"; } diff --git a/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/SessionController.java b/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/SessionController.java index 24299aa9..5d4c3b60 100644 --- a/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/SessionController.java +++ b/openvidu-mvc-java/src/main/java/io/openvidu/mvc/java/SessionController.java @@ -20,12 +20,17 @@ import io.openvidu.java.client.TokenOptions; @Controller public class SessionController { - OpenVidu openVidu; + // OpenVidu object to ask openvidu-server for sessionId and token + private OpenVidu openVidu; + // Collection to pair session names and OpenVidu Session objects private Map mapSessions = new ConcurrentHashMap<>(); + // Collection to pair sessionId's and tokens (the inner Map pairs tokens and role associated) private Map> mapSessionIdsTokens = new ConcurrentHashMap<>(); + // URL where our OpenVidu server is listening private String OPENVIDU_URL; + // Secret shared with our OpenVidu server private String SECRET; public SessionController(@Value("${openvidu.secret}") String secret, @Value("${openvidu.url}") String openviduUrl) { @@ -45,51 +50,74 @@ public class SessionController { } System.out.println("Getting sessionId and token | {sessionName}={" + sessionName + "}"); + // Role associated to this user OpenViduRole role = LoginController.users.get(httpSession.getAttribute("loggedUser")).role; + + // Optional data to be passed to other users when this user connects to the video-call + // In this case, a JSON with the value we stored in the HttpSession object on login String serverData = "{\"serverData\": \"" + httpSession.getAttribute("loggedUser") + "\"}"; + + // Build tokenOptions object with the serverData and the role TokenOptions tokenOptions = new TokenOptions.Builder().data(serverData).role(role).build(); if (this.mapSessions.get(sessionName) != null) { // Session already exists: return existing sessionId and a new token System.out.println("Existing session " + sessionName); try { + + // Get the existing sessionId from our collection with + // the sessionName param ("TUTORIAL") String sessionId = this.mapSessions.get(sessionName).getSessionId(); + // Generate a new token with the recently created tokenOptions String token = this.mapSessions.get(sessionName).generateToken(tokenOptions); + // Update our collection storing the new token this.mapSessionIdsTokens.get(sessionId).put(token, role); + // Add all the needed attributes to the template model.addAttribute("sessionId", sessionId); model.addAttribute("token", token); model.addAttribute("nickName", clientData); model.addAttribute("userName", httpSession.getAttribute("loggedUser")); model.addAttribute("sessionName", sessionName); + // Return session.html template return "session"; + } catch (Exception e) { + // If error just return dashboard.html template model.addAttribute("username", httpSession.getAttribute("loggedUser")); return "dashboard"; } - } else { - // New session: return a new sessionId and token + // New session: return a new sessionId and a new token System.out.println("New session " + sessionName); try { + + // Create a new OpenVidu Session Session session = this.openVidu.createSession(); + // Get the sessionId String sessionId = session.getSessionId(); + // Generate a new token with the recently created tokenOptions String token = session.generateToken(tokenOptions); + // Store the session and the token in our collections this.mapSessions.put(sessionName, session); this.mapSessionIdsTokens.put(sessionId, new ConcurrentHashMap<>()); this.mapSessionIdsTokens.get(sessionId).put(token, role); + // Add all the needed attributes to the template model.addAttribute("sessionId", sessionId); model.addAttribute("token", token); model.addAttribute("nickName", clientData); model.addAttribute("userName", httpSession.getAttribute("loggedUser")); model.addAttribute("sessionName", sessionName); + // Return session.html template return "session"; + } catch (Exception e) { + // If error just return dashboard.html template model.addAttribute("username", httpSession.getAttribute("loggedUser")); return "dashboard"; } @@ -107,29 +135,33 @@ public class SessionController { } System.out.println("Removing user | sessioName=" + sessionName + ", token=" + token); + // If the session exists if (this.mapSessions.get(sessionName) != null) { String sessionId = this.mapSessions.get(sessionName).getSessionId(); if (this.mapSessionIdsTokens.containsKey(sessionId)) { + // If the token exists if (this.mapSessionIdsTokens.get(sessionId).remove(token) != null) { System.out.println(sessionName + ": " + this.mapSessionIdsTokens.get(sessionId).toString()); // User left the session if (this.mapSessionIdsTokens.get(sessionId).isEmpty()) { - // Last user left the session + // Last user left: session must be removed this.mapSessions.remove(sessionName); System.out.println(sessionName + " empty!"); } - model.addAttribute("sessionId", sessionId); return "redirect:/dashboard"; } else { + // The TOKEN wasn't valid System.out.println("Problems in the app server: the TOKEN wasn't valid"); return "redirect:/dashboard"; } } else { + // The SESSIONID wasn't valid System.out.println("Problems in the app server: the SESSIONID wasn't valid"); return "redirect:/dashboard"; } } else { + // The SESSION does not exist System.out.println("Problems in the app server: the SESSION does not exist"); return "redirect:/dashboard"; } diff --git a/openvidu-mvc-java/src/main/resources/templates/index.html b/openvidu-mvc-java/src/main/resources/templates/index.html index ba94b58e..63e3ced1 100644 --- a/openvidu-mvc-java/src/main/resources/templates/index.html +++ b/openvidu-mvc-java/src/main/resources/templates/index.html @@ -44,10 +44,12 @@

- + +

- + +

diff --git a/openvidu-mvc-java/src/main/resources/templates/session.html b/openvidu-mvc-java/src/main/resources/templates/session.html index 4c2097be..69f4b370 100644 --- a/openvidu-mvc-java/src/main/resources/templates/session.html +++ b/openvidu-mvc-java/src/main/resources/templates/session.html @@ -136,7 +136,7 @@ }; initMainVideo(event.element, userData); appendUserData(event.element, userData); - $(event.element).prop('muted', true); + $(event.element).prop('muted', true); // Mute local video }); diff --git a/openvidu-mvc-node/server.js b/openvidu-mvc-node/server.js index 6ff69a31..3ebb44fe 100644 --- a/openvidu-mvc-node/server.js +++ b/openvidu-mvc-node/server.js @@ -60,15 +60,17 @@ var users = [{ role: OpenViduRole.SUBSCRIBER }]; -// Environment variables +// Environment variable: URL where our OpenVidu server is listening var OPENVIDU_URL = process.argv[2]; +// Environment variable: secret shared with our OpenVidu server var OPENVIDU_SECRET = process.argv[3]; -// OpenVidu object +// OpenVidu object to ask openvidu-server for sessionId and token var OV = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET); -// Objects for storing active sessions and users +// Collection to pair session names and OpenVidu Session objects var mapSessionNameSession = {}; +// Collection to pair sessionId's (identifiers of Session objects) and tokens var mapSessionIdTokens = {}; /* CONFIGURATION */ @@ -100,28 +102,36 @@ app.get('/dashboard', dashboardController); function dashboardController(req, res) { - if (isLogged(req.session)) { - user = req.session.loggedUser; - res.render('dashboard.ejs', { - user: user - }); - } else { - var user = req.body.user; + // Check if the user is already logged in + if (isLogged(req.session)) { + // User is already logged. Immediately return dashboard + user = req.session.loggedUser; + res.render('dashboard.ejs', { + user: user + }); + } else { + // User wasn't logged and wants to + + // Retrieve params from POST body + var user = req.body.user; var pass = req.body.pass; console.log("Logging in | {user, pass}={" + user + ", " + pass + "}"); - - if (login(user, pass)) { + + if (login(user, pass)) { // Correct user-pass + // Validate session and return OK + // Value stored in req.session allows us to identify the user in future requests console.log("'" + user + "' has logged in"); - req.session.loggedUser = user; - res.render('dashboard.ejs', { - user: user - }); - } else { + req.session.loggedUser = user; + res.render('dashboard.ejs', { + user: user + }); + } else { // Wrong user-pass + // Invalidate session and return index template console.log("'" + user + "' invalid credentials"); - req.session.destroy(); - res.redirect('/'); - } - } + req.session.destroy(); + res.redirect('/'); + } + } } app.post('/session', (req, res) => { @@ -129,23 +139,43 @@ app.post('/session', (req, res) => { req.session.destroy(); res.redirect('/'); } else { + // The nickname sent by the client var clientData = req.body.data; + // The video-call to connect ("TUTORIAL") var sessionName = req.body.sessionname; + + // Role associated to this user var role = users.find(u => (u.user === req.session.loggedUser)).role; + + // Optional data to be passed to other users when this user connects to the video-call + // In this case, a JSON with the value we stored in the req.session object on login var serverData = '{"serverData": "' + req.session.loggedUser + '"}'; + console.log("Getting sessionId and token | {sessionName}={" + sessionName + "}"); + // Build tokenOptions object with the serverData and the role var tokenOptions = new TokenOptions.Builder() .data(serverData) .role(role) .build(); if (mapSessionNameSession[sessionName]) { + // Session already exists: return existing sessionId and a new token console.log('Existing session ' + sessionName); + + // Get the existing Session from the collection var mySession = mapSessionNameSession[sessionName]; + + // Generate a new token asynchronously with the recently created tokenOptions mySession.generateToken(tokenOptions, function (token) { + + // Get the existing sessionId var sessionId = mySession.getSessionId(); + + // Store the new token in the collection of tokens mapSessionIdTokens[sessionId].push(token); + + // Return session template with all the needed attributes console.log('SESSIONID: ' + sessionId); console.log('TOKEN: ' + token); res.render('session.ejs', { @@ -156,15 +186,27 @@ app.post('/session', (req, res) => { sessionName: sessionName }); }); - } else { + } else { // New session: return a new sessionId and a new token console.log('New session ' + sessionName); - var mySession = OV.createSession(); - mySession.getSessionId(function (sessionId) { - mapSessionNameSession[sessionName] = mySession; - mapSessionIdTokens[sessionId] = []; + // Create a new OpenVidu Session + var mySession = OV.createSession(); + + // Get the sessionId asynchronously + mySession.getSessionId(function (sessionId) { + + // Store the new Session in the collection of Sessions + mapSessionNameSession[sessionName] = mySession; + // Store a new empty array in the collection of tokens + mapSessionIdTokens[sessionId] = []; + + // Generate a new token asynchronously with the recently created tokenOptions mySession.generateToken(tokenOptions, function (token) { + + // Store the new token in the collection of tokens mapSessionIdTokens[sessionId].push(token); + + // Return session template with all the needed attributes console.log('SESSIONID: ' + sessionId); console.log('TOKEN: ' + token); res.render('session.ejs', { @@ -185,16 +227,21 @@ app.post('/leave-session', (req, res) => { req.session.destroy(); res.render('index.ejs'); } else { + // Retrieve params from POST body var sessionName = req.body.sessionname; var token = req.body.token; console.log('Removing user | {sessionName, token}={' + sessionName + ', ' + token + '}'); - + + // If the session exists var mySession = mapSessionNameSession[sessionName]; if (mySession) { var tokens = mapSessionIdTokens[mySession.getSessionId()]; if (tokens) { var index = tokens.indexOf(token); - if (index !== -1) { // User left the session + + // If the token exists + if (index !== -1) { + // Token removed! tokens.splice(index, 1); console.log(sessionName + ': ' + mapSessionIdTokens[mySession.getSessionId()].toString()); } else { @@ -202,7 +249,8 @@ app.post('/leave-session', (req, res) => { console.log(msg); res.redirect('/dashboard'); } - if (mapSessionIdTokens[mySession.getSessionId()].length == 0) { // Last user left the session + if (mapSessionIdTokens[mySession.getSessionId()].length == 0) { + // Last user left: session must be removed console.log(sessionName + ' empty!'); delete mapSessionNameSession[sessionName]; } diff --git a/openvidu-mvc-node/views/index.ejs b/openvidu-mvc-node/views/index.ejs index 7f3bccbd..b4eb9629 100644 --- a/openvidu-mvc-node/views/index.ejs +++ b/openvidu-mvc-node/views/index.ejs @@ -44,10 +44,12 @@

- + +

- + +

diff --git a/openvidu-mvc-node/views/session.ejs b/openvidu-mvc-node/views/session.ejs index 2da7c891..ca5212b3 100644 --- a/openvidu-mvc-node/views/session.ejs +++ b/openvidu-mvc-node/views/session.ejs @@ -92,7 +92,7 @@ // When the HTML video has been appended to DOM... subscriber.on('videoElementCreated', function (event) { - // Add a new HTML element for the user's name and nickname over its video + // Add a new HTML element for the user's name and nickname just below its video appendUserData(event.element, subscriber.stream.connection); }); }); @@ -106,6 +106,7 @@ // --- 3) Connect to the session passing the retrieved token and some more data from // the client (in this case a JSON with the nickname chosen by the user) --- + session.connect(token, '{"clientData": "' + nickName + '"}', function (error) { // If the connection is successful, initialize a publisher and publish to the session @@ -118,7 +119,7 @@ if (isPublisher()) { // --- 4) Get your own camera stream --- - + var publisher = OV.initPublisher('video-container', { audio: true, video: true, @@ -134,12 +135,12 @@ }; initMainVideo(event.element, userData); appendUserData(event.element, userData); - $(event.element).prop('muted', true); + $(event.element).prop('muted', true); // Mute local video }); // --- 5) Publish your stream --- - + session.publish(publisher); } else {