From 8d48895d2a0cb9d3e1a741ffc9c9e72702d0c927 Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Thu, 15 Jun 2017 17:55:01 +0200 Subject: [PATCH] openvidu-mvc-java README updated --- openvidu-js-java/README.md | 29 +- openvidu-mvc-java/README.md | 403 ++++++++++++++++++ .../io/openvidu/mvc/java/LoginController.java | 1 + .../openvidu/mvc/java/SessionController.java | 2 + .../main/resources/templates/dashboard.html | 8 +- .../src/main/resources/templates/index.html | 2 +- .../src/main/resources/templates/session.html | 4 +- 7 files changed, 430 insertions(+), 19 deletions(-) diff --git a/openvidu-js-java/README.md b/openvidu-js-java/README.md index 735570f1..700d7eb4 100644 --- a/openvidu-js-java/README.md +++ b/openvidu-js-java/README.md @@ -44,11 +44,11 @@ OpenVidu is composed by the modules displayed on the image above. docker run -p 8443:8443 --rm -e KMS_STUN_IP=193.147.51.12 -e KMS_STUN_PORT=3478 -e openvidu.secret=MY_SECRET openvidu/openvidu-server-kms ``` -5. Go to [`https://localhost:5000`](https://localhost:5000) to test the app once the server is running. The first time you use the docker container, an alert message will suggest you accept the self-signed certificate of _openvidu-server_ when you first try to join a video-call. +5. Go to [`https://localhost:5000`](https://localhost:5000) to test the app once the server is running. The first time you use the docker container, an alert message will suggest you accept the self-signed certificate of _openvidu-server_ when you first try to join a video-call. To test two users in the same computer, use a standard window and an incognito window. ## Understanding the code -This is a very basic web application with a pretty simple vanilla JS/HTML/CSS frontend and a straightforward Java backend. OpenVidu assumes you can identify your users so you can tell which users can connect to which video-calls, and what role each one of them will have in them. You can do this as you prefer. Here our backend will manage the users and their sessions by using the non-intrusive _HttpSession_ API. In these posts multiple options for user session management in Java are explained, inlcuding the one used in this tutorial: [journaldev.com](http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url-rewriting), [studytonight.com](http://www.studytonight.com/servlet/session-management.php). +This is a very basic web application with a pretty simple vanilla JS/HTML/CSS frontend and a straightforward Java backend. OpenVidu assumes you can identify your users so you can tell which users can connect to which video-calls, and what role (and therefore what permissions) each one of them will have in the calls. You can do this as you prefer. Here our backend will manage the users and their sessions by using the non-intrusive _HttpSession_ API. In these posts multiple options for user session management in Java are explained, inlcuding the one used in this tutorial: [journaldev.com](http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url-rewriting), [studytonight.com](http://www.studytonight.com/servlet/session-management.php). - Backend: SpringBoot app with the following classes (`src/main/java` path, `io.openvidu.js.java` package) - `App.java` : entrypoint for the app @@ -56,9 +56,9 @@ This is a very basic web application with a pretty simple vanilla JS/HTML/CSS fr - `SessionController.java` : rest controller for getting sessionId's and tokens. It also stores our active video-calls and the users connected to them - Frontend: Pure JS/HTML/CSS files (`src/main/resources/static`) - - `OpenVidu.js`: openvidu-browser library. You don't have to manipulate this file. - - `app.js`: sample application main JavaScritp file, which makes use of _OpenVidu.js_. - - `index.html`: HTML code for the form to login, the form to connect to a video-call and for the video-call itself. + - `OpenVidu.js` : openvidu-browser library. You don't have to manipulate this file. + - `app.js` : sample application main JavaScritp file, which makes use of _OpenVidu.js_. + - `index.html` : HTML code for the form to login, the form to connect to a video-call and for the video-call itself. It has two links to both JavaScript files: ```html @@ -162,7 +162,7 @@ Let's describe the code following this scenario: a user logs in to the app and c }); } ``` - Here is the second time we must call our `httpRequest()` method, sending the session we want to connect ("TUTORIAL") and waiting to get a _sessionId_ and a _token_ as response. The interesting part here is in `SessionController.java`. First of all there are some important attributes in this controller we must mention: + Here is the second time we must call our `httpRequest()` method, sending the session we want to connect ("TUTORIAL") and waiting to get a _sessionId_ and a _token_ as response. The interesting part here is in `SessionController.java`. First of all there are some important attributes in this class we must mention: ```java // OpenVidu object to ask openvidu-server for sessionId and token @@ -185,6 +185,7 @@ Let's describe the code following this scenario: a user logs in to the app and c @RequestMapping(value = "/api-sessions/get-sessionid-token", method = RequestMethod.POST) public ResponseEntity getSessionIdToken(@RequestBody String sessionNameParam, HttpSession httpSession) throws ParseException { + // Check the user is logged ... JSONObject sessionJSON = (JSONObject) new JSONParser().parse(sessionNameParam); @@ -266,7 +267,7 @@ Let's describe the code following this scenario: a user logs in to the app and c // On every Stream destroyed... session.on('streamDestroyed', function (event) { - // Delete the HTML element with the user's nickname + // Delete the HTML element with the user's name and nickname removeUserData(event.stream.connection); }); @@ -313,7 +314,8 @@ Let's describe the code following this scenario: a user logs in to the app and c 3. **Another user connects to the video-call** -The process would be exactly the same as before until `SessionController.java` executes `getSessionIdAndToken()` method. Now session 'TUTORIAL' already exists, so in the _if-else_ statement the _if_ branch would be the one executed: + + The process would be exactly the same as before until `SessionController.java` executes `getSessionIdAndToken()` method. Now session 'TUTORIAL' already exists, so in the _if-else_ statement the _if_ branch would be the one executed: ```java if (this.mapSessions.get(sessionName) != null) { @@ -344,12 +346,12 @@ The process would be exactly the same as before until `SessionController.java` e } } ``` - The code executed in `app.js` would be also the same. After the `Session.publish()` method has been succesful, both users will be seeing each other's video, as well as the username and the nickname below it. + The code executed in `app.js` would also be the same. After the `Session.publish()` method has been succesful, both users will be seeing each other's video, as well as the username and the nickname below it. 4. **Users leave the video-call** - After a while both users decide to leave the session. Here is where the last HTTP operation takes place: we must let the backend know that certain user has left the session so it can update the collections with the active sessions and tokens. - In `app.js` we run the following HTTP POST operation: + After a while both users decide to leave the session. Apart from calling `leaveSession()` (and therefore `session.disconnect()`) to destroy the connection on openvidu-server, we need to run the last HTTP operation: we must let the backend know that certain user has left the session so it can update the collections with the active sessions and tokens. To sum up, `session.disconnect()` updates our openvidu-server and the POST operation updates our backend. + For the POST operation, in `app.js` we run: ```javascript function removeUser() { @@ -372,6 +374,7 @@ The process would be exactly the same as before until `SessionController.java` e @RequestMapping(value = "/api-sessions/remove-user", method = RequestMethod.POST) public ResponseEntity removeUser(@RequestBody String sessionNameToken, HttpSession httpSession) throws Exception { + // Check the user is logged ... // Retrieve the params from BODY JSONObject sessionNameTokenJSON = (JSONObject) new JSONParser().parse(sessionNameToken); @@ -409,4 +412,6 @@ The process would be exactly the same as before until `SessionController.java` e --- -> At this point we have covered all the important code from the tutorial. With this scenario we have seen the most common use-case, but you can modify whatever you want to suit your needs. And remember that this is one single approach, using certain technologies: **you can implement your frontend and your backend as you want**. The only actual requirements are getting ***sessionId*** and ***token*** params from ***openvidu-server*** and using them along with ***openvidu-browser*** to connect your clients to the sessions. \ No newline at end of file +> At this point we have covered all the important code from the tutorial. With this scenario we have seen the most common use-case, but you can modify whatever you want to suit your needs. And remember that this is just one of the many possible approaches: **you can implement your frontend and your backend as you want**. +> +> The only actual requirements are getting ***sessionId*** and ***token*** params from ***openvidu-server*** (by using one of the available clients or with the REST API) and using them along with ***openvidu-browser*** to connect your clients to the sessions. \ No newline at end of file diff --git a/openvidu-mvc-java/README.md b/openvidu-mvc-java/README.md index 6e022f28..5a782b25 100644 --- a/openvidu-mvc-java/README.md +++ b/openvidu-mvc-java/README.md @@ -1 +1,404 @@ # openvidu-mvc-java + +A secure OpenVidu sample app with a Java backend and a traditional MVC frontend. With regard to the use of OpenVidu, it is identical to [openvidu-js-java](https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-js-java). This tutorial is intended for developers who feel more comfortable with MVC web architectures for their frontends. [Thymeleaf](http://www.thymeleaf.org/) is the template engine of choice for this tutorial. + +## Understanding this example + +

+ +

+ +OpenVidu is composed by the modules displayed on the image above. + +- **openvidu-browser**: JavaScript library for the browser. It allows you to manage your video-calls straight away from your clients +- **openvidu-java-client**: Java package to easily get the necessary params (sessionId's and tokens) from openvidu-server. Quick alternative to REST API +- **openvidu-server**: Java application that controls Kurento Media Server +- **Kurento Media Server**: server that handles low level operations of media flow transmissions + +> You will only have to make use of **openvidu-browser** and **openvidu-java-client** to get this sample app working + +## Executing this example + +1. Clone the repo: + + ```bash + git clone https://github.com/OpenVidu/openvidu-tutorials.git + ``` + +2. You will need _maven_ to build the project. You can install it with: + + ```bash + sudo apt-get install maven + ``` + +3. To run the sample application, execute the following command in the project: + + ```bash + cd openvidu-mvc-java + mvn package exec:java + ``` + +4. _openvidu-server_ and _Kurento Media Server_ must be up and running in your development machine. The easiest way is running this Docker container which wraps both of them (you will need [Docker CE](https://store.docker.com/search?type=edition&offering=community)): + + ```bash + docker run -p 8443:8443 --rm -e KMS_STUN_IP=193.147.51.12 -e KMS_STUN_PORT=3478 -e openvidu.secret=MY_SECRET openvidu/openvidu-server-kms + ``` + +5. Go to [`https://localhost:5000`](https://localhost:5000) to test the app once the server is running. The first time you use the docker container, an alert message will suggest you accept the self-signed certificate of _openvidu-server_ when you first try to join a video-call. To test two users in the same computer, use a standard window and an incognito window. + +## Understanding the code + +This is a very basic web application with a pretty simple vanilla JS/HTML/CSS frontend and a straightforward Java backend that serves HTML files with a MVC approach, building the templates with the help of [Thymeleaf](http://www.thymeleaf.org/). + +OpenVidu assumes you can identify your users so you can tell which users can connect to which video-calls, and what role (and therefore what permissions) each one of them will have in the calls. You can do this as you prefer. Here our backend will manage the users and their sessions by using the non-intrusive _HttpSession_ API. In these posts multiple options for user session management in Java are explained, inlcuding the one used in this tutorial: [journaldev.com](http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url-rewriting), [studytonight.com](http://www.studytonight.com/servlet/session-management.php). + +- **Backend**: SpringBoot app with the following classes (`src/main/java` path, `io.openvidu.js.java` package) + - `App.java` : entrypoint for the app + - `LoginController.java` : controller for handling login and logout operations + - `SessionController.java` : controller for getting sessionId's and tokens. It also stores our active video-calls and the users connected to them + +- **Frontend templates**: Pure JS/HTML/CSS files served by the backend (`src/main/resources/templates`) + - `index.html` : template with the login form + - `dashboard.html` : template with the form to join a video-call + - `session.html` : template of the video-call itself + +- **Frontend static files** (`src/main/resources/static`) + - `OpenVidu.js` : openvidu-browser library. You don't have to manipulate this file + - `style.css` : some CSS classes to style the templates + +Let's describe the code following this scenario: a user logs in to the app and connects to the video-call "TUTORIAL", where he publishes his webcam. A second user will connect to the same video-call just after that and publish its own webcam. Both of them will leave the call after a while. + +1. **User logs in** + + At path `/` a login form will be displayed: + +

+ +

+ + The form will execute a POST operation to path `/dashboard` whenever "Log in" button is clicked, passing the username and the password: + + ```html +
+

+ +

+

+ +

+

+ +

+
+ ``` + + `LoginController.java` first checks if the user is already logged (maybe he has just refreshed `/dashboard` page), and if so it just redirects to the dashboard itself. If the user is actually logging in, the method checks that the params are correct and if so sets an _HttpSession_ for the newly logged user (adding a "loggedUser" attribute with its username in the HttpSession object). Finally it returns `dashboard.html` template: + + ```java + @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) { + + // Check if the user is already logged in + String userName = (String) httpSession.getAttribute("loggedUser"); + if (userName != null) { + // User is already logged. Immediately return dashboard + model.addAttribute("username", userName); + return "dashboard"; + } + + // 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 { // Wrong user-pass + // Invalidate session and redirect to index.html + httpSession.invalidate(); + return "redirect:/"; + } + } + ``` + +2. **User connects to "TUTORIAL" video-call** + + `dashboard.html` template will display a form asking for the video-call to connect and the nickname the user wants to have in it. So our 'publisher1' user would write TUTORIAL in "Session" field: + +

+ +

+ + The form will execute a POST operation to path `/session` whenever "Join!" button is clicked, passing the nickname and the session name: + + ```html +
+

+ +

+

+ +

+

+ +

+
+ ``` + + When `SessionController.java` receives a request at `/session` path is when things get interesting. + First of all there are some important attributes in this class we must mention: + + ```java + // 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; + ``` + + Rest controller method receives both params sent by the client (whatever nickname the user has chosen and "TUTORIAL" as the sessionName). First it prepares two params we will need a little further on: `role` and `serverData`. + + ```java + @RequestMapping(value = "/session", method = RequestMethod.POST) + public String joinSession(@RequestParam(name = "data") String clientData, + @RequestParam(name = "session-name") String sessionName, + Model model, HttpSession httpSession) { + // Check the user is logged ... + + // 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") + "\"}"; + ``` + + Just after that an _if-else_ statement comes into play: does the session "TUTORIAL" already exitsts? + ```java + if (this.mapSessions.get(sessionName) != null) { ... + ``` + In this case it doesn't because 'publisher1' is the first user connecting to it. So we focus on the _else_ branch: + + ```java + else { + // New session: return a new sessionId and a new token + 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 retrieved serverData and role + String token = session.generateToken(new + TokenOptions.Builder().data(serverData).role(role).build()); + + // 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, OpenViduRole.PUBLISHER); + + // 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"; + } + } + ``` + We are almost there! Now in `session.html` JavaScript code (preceded by a tag ` diff --git a/openvidu-mvc-java/src/main/resources/templates/index.html b/openvidu-mvc-java/src/main/resources/templates/index.html index ed9fd6eb..b35b5e5f 100644 --- a/openvidu-mvc-java/src/main/resources/templates/index.html +++ b/openvidu-mvc-java/src/main/resources/templates/index.html @@ -10,7 +10,7 @@

- +

diff --git a/openvidu-mvc-java/src/main/resources/templates/session.html b/openvidu-mvc-java/src/main/resources/templates/session.html index c3737bbc..99cb3f22 100644 --- a/openvidu-mvc-java/src/main/resources/templates/session.html +++ b/openvidu-mvc-java/src/main/resources/templates/session.html @@ -35,8 +35,8 @@ sessionId + ", TOKEN:" + token + ")"); // 1) Get an OpenVidu object an initialize a Session - var OV = new OpenVidu("wss://" + location.hostname + ":8443/"); - var session = OV.initSession("apikey", sessionId); + var OV = new OpenVidu(); + var session = OV.initSession(sessionId); // 2) Specify the actions when events take place session.on('streamCreated', function (event) {