From 83edc43299790a0ea2d7ceb7288f83f827699ce3 Mon Sep 17 00:00:00 2001 From: pabloFuente Date: Wed, 14 Jun 2017 15:45:22 +0200 Subject: [PATCH] openvidu-server support 'local', 'ngtok' and custom URL mode --- .../io/openvidu/server/InfoSocketConfig.java | 3 +- .../io/openvidu/server/OpenViduServer.java | 196 ++++++++++-------- .../io/openvidu/server/core/RoomManager.java | 21 +- .../openvidu/server/rest/NgrokController.java | 76 ++++++- .../security/OpenviduConfiguration.java | 37 ++++ .../server/security/SecurityConfig.java | 7 +- .../resources/application-ngrok.properties | 3 +- .../src/main/resources/application.properties | 3 +- .../resources/static/inline.bundle.js.map | 2 +- .../src/main/resources/static/main.bundle.js | 4 +- .../main/resources/static/main.bundle.js.map | 2 +- 11 files changed, 236 insertions(+), 118 deletions(-) create mode 100644 openvidu-server/src/main/java/io/openvidu/server/security/OpenviduConfiguration.java diff --git a/openvidu-server/src/main/java/io/openvidu/server/InfoSocketConfig.java b/openvidu-server/src/main/java/io/openvidu/server/InfoSocketConfig.java index 4eef928a..e65ff924 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/InfoSocketConfig.java +++ b/openvidu-server/src/main/java/io/openvidu/server/InfoSocketConfig.java @@ -12,8 +12,7 @@ public class InfoSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(infoHandler(), "/info"); - //.setAllowedOrigins("*"); + registry.addHandler(infoHandler(), "/info").setAllowedOrigins("*"); } @Bean diff --git a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java index 7a0fdce5..1dcececa 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java +++ b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java @@ -46,6 +46,7 @@ import io.openvidu.server.kms.FixedOneKmsManager; import io.openvidu.server.rest.NgrokController; import io.openvidu.server.rpc.JsonRpcNotificationService; import io.openvidu.server.rpc.JsonRpcUserControl; +import io.openvidu.server.security.OpenviduConfiguration; /** * Room server application. @@ -55,113 +56,126 @@ import io.openvidu.server.rpc.JsonRpcUserControl; * @author Radu Tom Vlad (rvlad@naevatec.com) * @since 1.0.0 */ -@Import({JsonRpcConfiguration.class, InfoSocketConfig.class}) +@Import({ JsonRpcConfiguration.class, InfoSocketConfig.class }) @SpringBootApplication public class OpenViduServer implements JsonRpcConfigurer { - public static final String KMSS_URIS_PROPERTY = "kms.uris"; - public static final String KMSS_URIS_DEFAULT = "[ \"ws://localhost:8888/kurento\" ]"; - - @Value("${kms.uris}") - private String KMSS_CUSTOM_URIS; + public static final String KMSS_URIS_PROPERTY = "kms.uris"; + public static final String KMSS_URIS_DEFAULT = "[ \"ws://localhost:8888/kurento\" ]"; - private static final Logger log = LoggerFactory.getLogger(OpenViduServer.class); + @Value("${kms.uris}") + private String KMSS_CUSTOM_URIS; - @Bean - @ConditionalOnMissingBean - public KurentoClientProvider kmsManager() { + public static String publicUrl; - JsonArray kmsUris = getPropertyJson(KMSS_URIS_PROPERTY, KMSS_URIS_DEFAULT, JsonArray.class); - List kmsWsUris = JsonUtils.toStringList(kmsUris); - - if ((KMSS_CUSTOM_URIS != null) && (!KMSS_CUSTOM_URIS.isEmpty())) { - List uris = new Gson().fromJson( KMSS_CUSTOM_URIS, List.class ); - kmsWsUris.addAll(0, uris); - } + private static final Logger log = LoggerFactory.getLogger(OpenViduServer.class); - if (kmsWsUris.isEmpty()) { - throw new IllegalArgumentException(KMSS_URIS_PROPERTY - + " should contain at least one kms url"); - } + @Bean + @ConditionalOnMissingBean + public KurentoClientProvider kmsManager() { - String firstKmsWsUri = kmsWsUris.get(0); + JsonArray kmsUris = getPropertyJson(KMSS_URIS_PROPERTY, KMSS_URIS_DEFAULT, JsonArray.class); + List kmsWsUris = JsonUtils.toStringList(kmsUris); - if (firstKmsWsUri.equals("autodiscovery")) { - log.info("Using autodiscovery rules to locate KMS on every pipeline"); - return new AutodiscoveryKurentoClientProvider(); - } else { - log.info("Configuring Kurento Room Server to use first of the following kmss: " + kmsWsUris); - return new FixedOneKmsManager(firstKmsWsUri); - } - } + if ((KMSS_CUSTOM_URIS != null) && (!KMSS_CUSTOM_URIS.isEmpty())) { + List uris = new Gson().fromJson(KMSS_CUSTOM_URIS, List.class); + kmsWsUris.addAll(0, uris); + } - @Bean - @ConditionalOnMissingBean - public JsonRpcNotificationService notificationService() { - return new JsonRpcNotificationService(); - } + if (kmsWsUris.isEmpty()) { + throw new IllegalArgumentException(KMSS_URIS_PROPERTY + " should contain at least one kms url"); + } - @Bean - @ConditionalOnMissingBean - public NotificationRoomHandler defaultNotificationRoomHandler() { - return new DefaultNotificationRoomHandler(notificationService()); - } - - @Bean - @ConditionalOnMissingBean - public RoomManager roomManager() { - return new RoomManager(); - } + String firstKmsWsUri = kmsWsUris.get(0); - @Bean - @ConditionalOnMissingBean - public NotificationRoomManager notificationRoomManager() { - return new NotificationRoomManager(); - } + if (firstKmsWsUri.equals("autodiscovery")) { + log.info("Using autodiscovery rules to locate KMS on every pipeline"); + return new AutodiscoveryKurentoClientProvider(); + } else { + log.info("Configuring Kurento Room Server to use first of the following kmss: " + kmsWsUris); + return new FixedOneKmsManager(firstKmsWsUri); + } + } - @Bean - @ConditionalOnMissingBean - public JsonRpcUserControl userControl() { - return new JsonRpcUserControl(); - } + @Bean + @ConditionalOnMissingBean + public JsonRpcNotificationService notificationService() { + return new JsonRpcNotificationService(); + } - @Bean - @ConditionalOnMissingBean - public RoomJsonRpcHandler roomHandler() { - return new RoomJsonRpcHandler(); - } + @Bean + @ConditionalOnMissingBean + public NotificationRoomHandler defaultNotificationRoomHandler() { + return new DefaultNotificationRoomHandler(notificationService()); + } - @Override - public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) { - registry.addHandler(roomHandler().withPingWatchdog(true), "/room"); - } + @Bean + @ConditionalOnMissingBean + public RoomManager roomManager() { + return new RoomManager(); + } - @Bean - public ServletServerContainerFactoryBean createWebSocketContainer() { - ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); - container.setMaxTextMessageBufferSize(1000000); // chars - container.setMaxBinaryMessageBufferSize(1000000); // bytes - return container; - } + @Bean + @ConditionalOnMissingBean + public NotificationRoomManager notificationRoomManager() { + return new NotificationRoomManager(); + } - public static void main(String[] args) throws Exception { - start(args); - try { - NgrokController ngrok = new NgrokController(); - System.out.println(); - System.out.println(" PUBLIC IP "); - System.out.println("-------------------------"); - System.out.println(ngrok.getNgrokPublicUrl()); - System.out.println("-------------------------"); - System.out.println(); - } catch(Exception e) { - System.out.println(" No ngrok connection "); - } - } + @Bean + @ConditionalOnMissingBean + public JsonRpcUserControl userControl() { + return new JsonRpcUserControl(); + } - public static ConfigurableApplicationContext start(String[] args) { - log.info("Using /dev/urandom for secure random generation"); - System.setProperty("java.security.egd", "file:/dev/./urandom"); - return SpringApplication.run(OpenViduServer.class, args); - } + @Bean + @ConditionalOnMissingBean + public RoomJsonRpcHandler roomHandler() { + return new RoomJsonRpcHandler(); + } + + @Override + public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) { + registry.addHandler(roomHandler().withPingWatchdog(true), "/room"); + } + + @Bean + public ServletServerContainerFactoryBean createWebSocketContainer() { + ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); + container.setMaxTextMessageBufferSize(1000000); // chars + container.setMaxBinaryMessageBufferSize(1000000); // bytes + return container; + } + + public static void main(String[] args) throws Exception { + ConfigurableApplicationContext context = start(args); + OpenviduConfiguration openviduConf = context.getBean(OpenviduConfiguration.class); + OpenViduServer.publicUrl = "wss://localhost:" + openviduConf.getServerPort(); + + if (openviduConf.getOpenViduPublicUrl().equals("ngrok")) { + try { + NgrokController ngrok = new NgrokController(); + System.out.println(); + System.out.println(" PUBLIC IP "); + System.out.println("-------------------------"); + System.out.println(ngrok.getNgrokAppUrl()); + System.out.println("-------------------------"); + System.out.println(); + OpenViduServer.publicUrl = ngrok.getNgrokServerUrl().replaceFirst("https://", "wss://"); + } catch (Exception e) { + System.out.println(" No ngrok connection "); + } + } else if (!openviduConf.getOpenViduPublicUrl().equals("local")) { + System.out.println("CUSTOM URL"); + OpenViduServer.publicUrl = openviduConf.getOpenViduPublicUrl().replaceFirst("https://", "wss://"); + if (!OpenViduServer.publicUrl.startsWith("wss://")) { + OpenViduServer.publicUrl = "wss://" + OpenViduServer.publicUrl; + } + } + } + + public static ConfigurableApplicationContext start(String[] args) { + log.info("Using /dev/urandom for secure random generation"); + System.setProperty("java.security.egd", "file:/dev/./urandom"); + return SpringApplication.run(OpenViduServer.class, args); + } } diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/RoomManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/RoomManager.java index cd5914c5..900829dc 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/core/RoomManager.java +++ b/openvidu-server/src/main/java/io/openvidu/server/core/RoomManager.java @@ -37,11 +37,10 @@ import org.kurento.client.WebRtcEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import io.openvidu.client.OpenViduException; import io.openvidu.client.OpenViduException.Code; -import io.openvidu.server.InfoHandler; +import io.openvidu.server.OpenViduServer; import io.openvidu.server.core.api.KurentoClientProvider; import io.openvidu.server.core.api.KurentoClientSessionInfo; import io.openvidu.server.core.api.MutedMediaType; @@ -50,6 +49,7 @@ import io.openvidu.server.core.api.pojo.UserParticipant; import io.openvidu.server.core.endpoint.SdpType; import io.openvidu.server.core.internal.Participant; import io.openvidu.server.core.internal.Room; +import io.openvidu.server.security.OpenviduConfiguration; import io.openvidu.server.security.ParticipantRole; import io.openvidu.server.security.Token; @@ -82,13 +82,13 @@ public class RoomManager { @Autowired private KurentoClientProvider kcProvider; + + @Autowired + private OpenviduConfiguration openviduConf; private final ConcurrentMap rooms = new ConcurrentHashMap(); private final ConcurrentMap> sessionidTokenTokenobj = new ConcurrentHashMap<>(); private final ConcurrentMap> sessionidUsernameToken = new ConcurrentHashMap<>(); - - @Value("${openvidu.security}") - private boolean SECURITY_ENABLED; private volatile boolean closed = false; @@ -963,7 +963,7 @@ public class RoomManager { } public boolean isParticipantInRoom(String token, String roomId) throws OpenViduException { - if (SECURITY_ENABLED) { + if (openviduConf.getOpenViduSecurity()) { if (this.sessionidTokenTokenobj.get(roomId) != null) { return this.sessionidTokenTokenobj.get(roomId).containsKey(token); } else{ @@ -979,7 +979,7 @@ public class RoomManager { } public boolean isPublisherInRoom(String userName, String roomId) { - if (SECURITY_ENABLED) { + if (openviduConf.getOpenViduSecurity()) { if (this.sessionidUsernameToken.get(roomId) != null){ String token = this.sessionidUsernameToken.get(roomId).get(userName); if (token != null){ @@ -1035,7 +1035,8 @@ public class RoomManager { } public String newSessionId(){ - String sessionId = new BigInteger(130, new SecureRandom()).toString(32); + String sessionId = OpenViduServer.publicUrl; + sessionId += "/" + new BigInteger(130, new SecureRandom()).toString(32); this.sessionidTokenTokenobj.put(sessionId, new ConcurrentHashMap<>()); this.sessionidUsernameToken.put(sessionId, new ConcurrentHashMap<>()); @@ -1048,7 +1049,7 @@ public class RoomManager { if (this.sessionidUsernameToken.get(roomId) != null && this.sessionidTokenTokenobj.get(roomId) != null) { if(metadataFormatCorrect(metadata)){ String token = new BigInteger(130, new SecureRandom()).toString(32); - if (SECURITY_ENABLED) { // Store the token only if security is enabled + if (openviduConf.getOpenViduSecurity()) { // Store the token only if security is enabled this.sessionidTokenTokenobj.get(roomId).put(token, new Token(token, role, metadata)); } showMap(); @@ -1065,7 +1066,7 @@ public class RoomManager { } public String newRandomUserName(String token, String roomId) { - if (SECURITY_ENABLED) { + if (openviduConf.getOpenViduSecurity()) { if (this.sessionidUsernameToken.get(roomId) != null && this.sessionidTokenTokenobj.get(roomId) != null) { if (this.sessionidTokenTokenobj.get(roomId).get(token) != null) { return this.generateAndStoreUserName(token, roomId); diff --git a/openvidu-server/src/main/java/io/openvidu/server/rest/NgrokController.java b/openvidu-server/src/main/java/io/openvidu/server/rest/NgrokController.java index eca40276..25c82c87 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/rest/NgrokController.java +++ b/openvidu-server/src/main/java/io/openvidu/server/rest/NgrokController.java @@ -10,16 +10,81 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; public class NgrokController { private final String NGROK_URL = "http://localhost:4040/api/tunnels"; + private final String NGROK_APP_NAME = "app"; + private final String NGROK_SERVER_NAME = "server"; + + private String appUrl = ""; + private String serverUrl = ""; + private JsonObject json; HttpClient client = HttpClientBuilder.create().build(); - public String getNgrokPublicUrl() throws ClientProtocolException, IOException { + public String getNgrokAppUrl() throws ClientProtocolException, IOException { + + if (this.appUrl != null && !this.appUrl.isEmpty()) { + return this.appUrl; + } + + if (this.json == null) { + this.json = this.httpRequest(); + } + + String appPublicUrl = ""; + + JsonArray array = this.json.getAsJsonArray("tunnels"); + for (JsonElement el : array) { + JsonObject elObj = el.getAsJsonObject(); + String name = elObj.get("name").getAsString(); + if (name.equals(NGROK_APP_NAME)) { + appPublicUrl = elObj.get("public_url").getAsString(); + appPublicUrl = appPublicUrl.replaceFirst("http://", "https://"); + break; + } + } + + this.appUrl = appPublicUrl; + + return appPublicUrl; + } + + public String getNgrokServerUrl() throws ClientProtocolException, IOException { + + if (this.serverUrl != null && !this.serverUrl.isEmpty()) { + return this.serverUrl; + } + + if (this.json == null) { + this.json = this.httpRequest(); + } + + String serverPublicUrl = ""; + + JsonArray array = this.json.getAsJsonArray("tunnels"); + for (JsonElement el : array) { + JsonObject elObj = el.getAsJsonObject(); + String name = elObj.get("name").getAsString(); + if (name.equals(NGROK_SERVER_NAME)) { + serverPublicUrl = elObj.get("public_url").getAsString(); + serverPublicUrl = serverPublicUrl.replaceFirst("http://", "https://"); + break; + } + } + + this.serverUrl = serverPublicUrl; + + return serverPublicUrl; + } + + private JsonObject httpRequest() throws ClientProtocolException, IOException { + HttpClient client = HttpClientBuilder.create().build(); HttpGet request = new HttpGet(NGROK_URL); @@ -31,11 +96,10 @@ public class NgrokController { while ((line = rd.readLine()) != null) { result.append(line); } - JsonObject json = (JsonObject) new JsonParser().parse(result.toString()); - String publicUrl = json.getAsJsonArray("tunnels").get(0).getAsJsonObject().get("public_url").getAsString(); - publicUrl = publicUrl.replaceFirst("http://", "https://"); - - return publicUrl; + + JsonObject responseJson = (JsonObject) new JsonParser().parse(result.toString()); + + return responseJson; } } diff --git a/openvidu-server/src/main/java/io/openvidu/server/security/OpenviduConfiguration.java b/openvidu-server/src/main/java/io/openvidu/server/security/OpenviduConfiguration.java new file mode 100644 index 00000000..90792b06 --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/security/OpenviduConfiguration.java @@ -0,0 +1,37 @@ +package io.openvidu.server.security; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class OpenviduConfiguration { + + @Value("${openvidu.publicurl}") + private String openviduPublicUrl; //local, ngrok, FINAL_URL + + @Value("${server.port}") + private String serverPort; + + @Value("${openvidu.secret}") + private String openviduSecret; + + @Value("${openvidu.security}") + private boolean openviduSecurity; // true, false + + public String getOpenViduPublicUrl() { + return this.openviduPublicUrl; + } + + public String getServerPort() { + return this.serverPort; + } + + public String getOpenViduSecret() { + return this.openviduSecret; + } + + public boolean getOpenViduSecurity() { + return this.openviduSecurity; + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/security/SecurityConfig.java b/openvidu-server/src/main/java/io/openvidu/server/security/SecurityConfig.java index 9b49bf68..c3d46202 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/security/SecurityConfig.java +++ b/openvidu-server/src/main/java/io/openvidu/server/security/SecurityConfig.java @@ -1,7 +1,6 @@ package io.openvidu.server.security; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -14,13 +13,13 @@ import org.springframework.security.config.http.SessionCreationPolicy; @EnableGlobalAuthentication public class SecurityConfig extends WebSecurityConfigurerAdapter { - @Value("${openvidu.secret}") - private String SECRET; + @Autowired + OpenviduConfiguration openviduConf; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() - .withUser("OPENVIDUAPP").password(SECRET).roles("ADMIN"); + .withUser("OPENVIDUAPP").password(openviduConf.getOpenViduSecret()).roles("ADMIN"); } @Override diff --git a/openvidu-server/src/main/resources/application-ngrok.properties b/openvidu-server/src/main/resources/application-ngrok.properties index db04d524..5eb48751 100644 --- a/openvidu-server/src/main/resources/application-ngrok.properties +++ b/openvidu-server/src/main/resources/application-ngrok.properties @@ -7,4 +7,5 @@ server.address: 0.0.0.0 kms.uris=[\"ws://localhost:8888/kurento\"] openvidu.secret: MY_SECRET -openvidu.security: false \ No newline at end of file +openvidu.security: false +openvidu.publicurl: ngrok \ No newline at end of file diff --git a/openvidu-server/src/main/resources/application.properties b/openvidu-server/src/main/resources/application.properties index 7ea60a71..dcd86aec 100644 --- a/openvidu-server/src/main/resources/application.properties +++ b/openvidu-server/src/main/resources/application.properties @@ -9,4 +9,5 @@ server.ssl.key-alias: openvidu-selfsigned kms.uris=[\"ws://localhost:8888/kurento\"] openvidu.secret: MY_SECRET -openvidu.security: true \ No newline at end of file +openvidu.security: true +openvidu.publicurl: local \ No newline at end of file diff --git a/openvidu-server/src/main/resources/static/inline.bundle.js.map b/openvidu-server/src/main/resources/static/inline.bundle.js.map index 8ee93828..d3b392c4 100644 --- a/openvidu-server/src/main/resources/static/inline.bundle.js.map +++ b/openvidu-server/src/main/resources/static/inline.bundle.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap 98fc6d34013f219a638d"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA,kDAA0C,oBAAoB,WAAW","file":"inline.bundle.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length)\n \t\t\tresolves.shift()();\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t4: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn Promise.resolve();\n\n \t\t// an Promise means \"currently loading\".\n \t\tif(installedChunks[chunkId]) {\n \t\t\treturn installedChunks[chunkId][2];\n \t\t}\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = 'text/javascript';\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"\" + chunkId + \".chunk.js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunks[chunkId][2] = promise;\n\n \t\thead.appendChild(script);\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 98fc6d34013f219a638d"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/bootstrap 6884041f471fcb0e9354"],"names":[],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAQ,oBAAoB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA,kDAA0C,oBAAoB,WAAW","file":"inline.bundle.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [], result;\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);\n \t\twhile(resolves.length)\n \t\t\tresolves.shift()();\n \t\tif(executeModules) {\n \t\t\tfor(i=0; i < executeModules.length; i++) {\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = executeModules[i]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// objects to store loaded and loading chunks\n \tvar installedChunks = {\n \t\t4: 0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId) {\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn Promise.resolve();\n\n \t\t// an Promise means \"currently loading\".\n \t\tif(installedChunks[chunkId]) {\n \t\t\treturn installedChunks[chunkId][2];\n \t\t}\n \t\t// start chunk loading\n \t\tvar head = document.getElementsByTagName('head')[0];\n \t\tvar script = document.createElement('script');\n \t\tscript.type = 'text/javascript';\n \t\tscript.charset = 'utf-8';\n \t\tscript.async = true;\n \t\tscript.timeout = 120000;\n\n \t\tif (__webpack_require__.nc) {\n \t\t\tscript.setAttribute(\"nonce\", __webpack_require__.nc);\n \t\t}\n \t\tscript.src = __webpack_require__.p + \"\" + chunkId + \".chunk.js\";\n \t\tvar timeout = setTimeout(onScriptComplete, 120000);\n \t\tscript.onerror = script.onload = onScriptComplete;\n \t\tfunction onScriptComplete() {\n \t\t\t// avoid mem leaks in IE.\n \t\t\tscript.onerror = script.onload = null;\n \t\t\tclearTimeout(timeout);\n \t\t\tvar chunk = installedChunks[chunkId];\n \t\t\tif(chunk !== 0) {\n \t\t\t\tif(chunk) chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));\n \t\t\t\tinstalledChunks[chunkId] = undefined;\n \t\t\t}\n \t\t};\n\n \t\tvar promise = new Promise(function(resolve, reject) {\n \t\t\tinstalledChunks[chunkId] = [resolve, reject];\n \t\t});\n \t\tinstalledChunks[chunkId][2] = promise;\n\n \t\thead.appendChild(script);\n \t\treturn promise;\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// on error function for async loading\n \t__webpack_require__.oe = function(err) { console.error(err); throw err; };\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 6884041f471fcb0e9354"],"sourceRoot":""} \ No newline at end of file diff --git a/openvidu-server/src/main/resources/static/main.bundle.js b/openvidu-server/src/main/resources/static/main.bundle.js index bc12981a..2c654495 100644 --- a/openvidu-server/src/main/resources/static/main.bundle.js +++ b/openvidu-server/src/main/resources/static/main.bundle.js @@ -59,7 +59,9 @@ var AppComponent = (function () { } AppComponent.prototype.ngOnInit = function () { var _this = this; - this.websocket = new WebSocket('wss://' + location.hostname + ':8443/info'); + var protocol = location.protocol.includes('https') ? 'wss://' : 'ws://'; + var port = (location.port) ? (':' + location.port) : ''; + this.websocket = new WebSocket(protocol + location.hostname + port + '/info'); this.websocket.onopen = function (event) { console.log('Info websocket connected'); }; diff --git a/openvidu-server/src/main/resources/static/main.bundle.js.map b/openvidu-server/src/main/resources/static/main.bundle.js.map index 292b9b81..8c0988fe 100644 --- a/openvidu-server/src/main/resources/static/main.bundle.js.map +++ b/openvidu-server/src/main/resources/static/main.bundle.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///./src async","webpack:///./src/main.ts","webpack:///./src/app/app.component.ts","webpack:///./src/app/app.material.module.ts","webpack:///./src/app/app.module.ts","webpack:///./src/app/app.routing.ts","webpack:///./src/environments/environment.ts","webpack:///./src/app/app.component.css","webpack:///./src/app/components/dashboard/dashboard.component.css","webpack:///./src/app/components/session-details/session-details.component.css","webpack:///./src/app/app.component.html","webpack:///./src/app/components/dashboard/dashboard.component.html","webpack:///./src/app/components/session-details/session-details.component.html","webpack:///./src/app/services/info.service.ts","webpack:///./src/app/components/dashboard/dashboard.component.ts","webpack:///./src/app/components/session-details/session-details.component.ts"],"names":[],"mappings":"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","file":"main.bundle.js","sourcesContent":["function webpackEmptyContext(req) {\n\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n}\nwebpackEmptyContext.keys = function() { return []; };\nwebpackEmptyContext.resolve = webpackEmptyContext;\nmodule.exports = webpackEmptyContext;\nwebpackEmptyContext.id = 100;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src async\n// module id = 100\n// module chunks = 1","import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n enableProdMode();\n}\n\nplatformBrowserDynamic().bootstrapModule(AppModule);\n\n\n\n// WEBPACK FOOTER //\n// ./src/main.ts","import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';\nimport { Router } from '@angular/router';\n\nimport { InfoService } from 'app/services/info.service';\n\n@Component({\n selector: 'app-root',\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.css']\n})\nexport class AppComponent implements OnInit, OnDestroy {\n\n websocket: WebSocket;\n\n constructor(private infoService: InfoService) { }\n\n ngOnInit() {\n this.websocket = new WebSocket('wss://' + location.hostname + ':8443/info');\n\n this.websocket.onopen = (event) => {\n console.log('Info websocket connected');\n };\n this.websocket.onclose = (event) => {\n console.log('Info websocket closed');\n };\n this.websocket.onerror = (event) => {\n console.log('Info websocket error');\n };\n this.websocket.onmessage = (event) => {\n console.log('Info websocket message');\n console.log(event.data);\n this.infoService.updateInfo(event.data);\n\n };\n }\n\n ngOnDestroy() {\n this.websocket.close();\n }\n\n @HostListener('window:beforeunload', ['$event'])\n beforeUnloadHander(event) {\n console.warn('Closing info websocket');\n this.websocket.close();\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.component.ts","import { NgModule } from '@angular/core';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport {\n MdButtonModule,\n MdCheckboxModule,\n MdCardModule,\n MdInputModule\n} from '@angular/material';\n\n@NgModule({\n imports: [BrowserAnimationsModule, MdButtonModule, MdCheckboxModule, MdCardModule, MdInputModule],\n exports: [BrowserAnimationsModule, MdButtonModule, MdCheckboxModule, MdCardModule, MdInputModule],\n})\nexport class AppMaterialModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.material.module.ts","import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { HttpModule } from '@angular/http';\nimport { RouterModule } from '@angular/router';\n\nimport { routing } from './app.routing';\nimport { AppMaterialModule } from 'app/app.material.module';\n\nimport { InfoService } from './services/info.service';\n\nimport { AppComponent } from './app.component';\nimport { DashboardComponent } from './components/dashboard/dashboard.component';\nimport { SessionDetailsComponent } from './components/session-details/session-details.component';\n\n\n@NgModule({\n declarations: [\n AppComponent,\n DashboardComponent,\n SessionDetailsComponent\n ],\n imports: [\n BrowserModule,\n FormsModule,\n HttpModule,\n routing,\n AppMaterialModule\n ],\n providers: [InfoService],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.module.ts","import { ModuleWithProviders } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport { DashboardComponent } from 'app/components/dashboard/dashboard.component';\nimport { SessionDetailsComponent } from 'app/components/session-details/session-details.component';\n\nconst appRoutes: Routes = [\n {\n path: '',\n component: DashboardComponent\n },\n {\n path: 'session/:id',\n component: SessionDetailsComponent\n }\n];\n\nexport const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.routing.ts","// The file contents for the current environment will overwrite these during build.\n// The build system defaults to the dev environment which uses `environment.ts`, but if you do\n// `ng build --env=prod` then `environment.prod.ts` will be used instead.\n// The list of which env maps to which file can be found in `.angular-cli.json`.\n\nexport const environment = {\n production: false\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/environments/environment.ts","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.css\n// module id = 169\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"#log {\\n height: 100%;\\n}\\n\\n#log-content {\\n height: 90%;\\n font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;\\n overflow-y: auto;\\n overflow-x: hidden\\n}\\n\\nul {\\n margin: 0;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/dashboard/dashboard.component.css\n// module id = 170\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/session-details/session-details.component.css\n// module id = 171\n// module chunks = 1","module.exports = \"
\\n \\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.html\n// module id = 172\n// module chunks = 1","module.exports = \"\\n Server events\\n \\n \\n \\n \\n

{{i}}

\\n
\\n
\\n
\\n
\\n\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/dashboard/dashboard.component.html\n// module id = 173\n// module chunks = 1","module.exports = \"

\\n session-details works!\\n

\\n\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/session-details/session-details.component.html\n// module id = 174\n// module chunks = 1","import { Injectable } from '@angular/core';\nimport { Subject } from 'rxjs/Subject';\n\n@Injectable()\nexport class InfoService {\n\n info: string;\n newInfo$: Subject;\n\n constructor() {\n this.newInfo$ = new Subject();\n }\n\n getInfo() {\n return this.info;\n }\n\n updateInfo(info: string) {\n this.info = info;\n this.newInfo$.next(info);\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/services/info.service.ts","import { Component, OnInit, AfterViewChecked, ViewChild, ElementRef } from '@angular/core';\nimport { Subscription } from 'rxjs/Subscription';\n\nimport { InfoService } from '../../services/info.service';\n\n@Component({\n selector: 'app-dashboard',\n templateUrl: './dashboard.component.html',\n styleUrls: ['./dashboard.component.css'],\n})\nexport class DashboardComponent implements OnInit, AfterViewChecked {\n\n @ViewChild('scrollMe') private myScrollContainer: ElementRef;\n\n infoSubscription: Subscription;\n info = [];\n\n constructor(private infoService: InfoService) {\n\n // Subscription to info updated event raised by InfoService\n this.infoSubscription = this.infoService.newInfo$.subscribe(\n info => {\n this.info.push(info);\n });\n }\n\n ngOnInit() {\n\n }\n\n ngAfterViewChecked() {\n this.scrollToBottom();\n }\n\n scrollToBottom(): void {\n try {\n this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;\n } catch (err) {\n console.log('[Error]:' + err.toString());\n }\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/components/dashboard/dashboard.component.ts","import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-session-details',\n templateUrl: './session-details.component.html',\n styleUrls: ['./session-details.component.css']\n})\nexport class SessionDetailsComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/components/session-details/session-details.component.ts"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///./src async","webpack:///./src/main.ts","webpack:///./src/app/app.component.ts","webpack:///./src/app/app.material.module.ts","webpack:///./src/app/app.module.ts","webpack:///./src/app/app.routing.ts","webpack:///./src/environments/environment.ts","webpack:///./src/app/app.component.css","webpack:///./src/app/components/dashboard/dashboard.component.css","webpack:///./src/app/components/session-details/session-details.component.css","webpack:///./src/app/app.component.html","webpack:///./src/app/components/dashboard/dashboard.component.html","webpack:///./src/app/components/session-details/session-details.component.html","webpack:///./src/app/services/info.service.ts","webpack:///./src/app/components/dashboard/dashboard.component.ts","webpack:///./src/app/components/session-details/session-details.component.ts"],"names":[],"mappings":"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","file":"main.bundle.js","sourcesContent":["function webpackEmptyContext(req) {\n\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n}\nwebpackEmptyContext.keys = function() { return []; };\nwebpackEmptyContext.resolve = webpackEmptyContext;\nmodule.exports = webpackEmptyContext;\nwebpackEmptyContext.id = 100;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src async\n// module id = 100\n// module chunks = 1","import { enableProdMode } from '@angular/core';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { AppModule } from './app/app.module';\nimport { environment } from './environments/environment';\n\nif (environment.production) {\n enableProdMode();\n}\n\nplatformBrowserDynamic().bootstrapModule(AppModule);\n\n\n\n// WEBPACK FOOTER //\n// ./src/main.ts","import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';\nimport { Router } from '@angular/router';\n\nimport { InfoService } from 'app/services/info.service';\n\n@Component({\n selector: 'app-root',\n templateUrl: './app.component.html',\n styleUrls: ['./app.component.css']\n})\nexport class AppComponent implements OnInit, OnDestroy {\n\n websocket: WebSocket;\n\n constructor(private infoService: InfoService) { }\n\n ngOnInit() {\n\n const protocol = location.protocol.includes('https') ? 'wss://' : 'ws://';\n const port = (location.port) ? (':' + location.port) : '';\n\n this.websocket = new WebSocket(protocol + location.hostname + port + '/info');\n\n this.websocket.onopen = (event) => {\n console.log('Info websocket connected');\n };\n this.websocket.onclose = (event) => {\n console.log('Info websocket closed');\n };\n this.websocket.onerror = (event) => {\n console.log('Info websocket error');\n };\n this.websocket.onmessage = (event) => {\n console.log('Info websocket message');\n console.log(event.data);\n this.infoService.updateInfo(event.data);\n\n };\n }\n\n ngOnDestroy() {\n this.websocket.close();\n }\n\n @HostListener('window:beforeunload', ['$event'])\n beforeUnloadHander(event) {\n console.warn('Closing info websocket');\n this.websocket.close();\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.component.ts","import { NgModule } from '@angular/core';\nimport { BrowserAnimationsModule } from '@angular/platform-browser/animations';\nimport {\n MdButtonModule,\n MdCheckboxModule,\n MdCardModule,\n MdInputModule\n} from '@angular/material';\n\n@NgModule({\n imports: [BrowserAnimationsModule, MdButtonModule, MdCheckboxModule, MdCardModule, MdInputModule],\n exports: [BrowserAnimationsModule, MdButtonModule, MdCheckboxModule, MdCardModule, MdInputModule],\n})\nexport class AppMaterialModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.material.module.ts","import { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { HttpModule } from '@angular/http';\nimport { RouterModule } from '@angular/router';\n\nimport { routing } from './app.routing';\nimport { AppMaterialModule } from 'app/app.material.module';\n\nimport { InfoService } from './services/info.service';\n\nimport { AppComponent } from './app.component';\nimport { DashboardComponent } from './components/dashboard/dashboard.component';\nimport { SessionDetailsComponent } from './components/session-details/session-details.component';\n\n\n@NgModule({\n declarations: [\n AppComponent,\n DashboardComponent,\n SessionDetailsComponent\n ],\n imports: [\n BrowserModule,\n FormsModule,\n HttpModule,\n routing,\n AppMaterialModule\n ],\n providers: [InfoService],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.module.ts","import { ModuleWithProviders } from '@angular/core';\nimport { Routes, RouterModule } from '@angular/router';\n\nimport { DashboardComponent } from 'app/components/dashboard/dashboard.component';\nimport { SessionDetailsComponent } from 'app/components/session-details/session-details.component';\n\nconst appRoutes: Routes = [\n {\n path: '',\n component: DashboardComponent\n },\n {\n path: 'session/:id',\n component: SessionDetailsComponent\n }\n];\n\nexport const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/app.routing.ts","// The file contents for the current environment will overwrite these during build.\n// The build system defaults to the dev environment which uses `environment.ts`, but if you do\n// `ng build --env=prod` then `environment.prod.ts` will be used instead.\n// The list of which env maps to which file can be found in `.angular-cli.json`.\n\nexport const environment = {\n production: false\n};\n\n\n\n// WEBPACK FOOTER //\n// ./src/environments/environment.ts","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.css\n// module id = 169\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"#log {\\n height: 100%;\\n}\\n\\n#log-content {\\n height: 90%;\\n font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;\\n overflow-y: auto;\\n overflow-x: hidden\\n}\\n\\nul {\\n margin: 0;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/dashboard/dashboard.component.css\n// module id = 170\n// module chunks = 1","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"\", \"\"]);\n\n// exports\n\n\n/*** EXPORTS FROM exports-loader ***/\nmodule.exports = module.exports.toString();\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/session-details/session-details.component.css\n// module id = 171\n// module chunks = 1","module.exports = \"
\\n \\n
\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/app.component.html\n// module id = 172\n// module chunks = 1","module.exports = \"\\n Server events\\n \\n \\n \\n \\n

{{i}}

\\n
\\n
\\n
\\n
\\n\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/dashboard/dashboard.component.html\n// module id = 173\n// module chunks = 1","module.exports = \"

\\n session-details works!\\n

\\n\"\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/app/components/session-details/session-details.component.html\n// module id = 174\n// module chunks = 1","import { Injectable } from '@angular/core';\nimport { Subject } from 'rxjs/Subject';\n\n@Injectable()\nexport class InfoService {\n\n info: string;\n newInfo$: Subject;\n\n constructor() {\n this.newInfo$ = new Subject();\n }\n\n getInfo() {\n return this.info;\n }\n\n updateInfo(info: string) {\n this.info = info;\n this.newInfo$.next(info);\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/services/info.service.ts","import { Component, OnInit, AfterViewChecked, ViewChild, ElementRef } from '@angular/core';\nimport { Subscription } from 'rxjs/Subscription';\n\nimport { InfoService } from '../../services/info.service';\n\n@Component({\n selector: 'app-dashboard',\n templateUrl: './dashboard.component.html',\n styleUrls: ['./dashboard.component.css'],\n})\nexport class DashboardComponent implements OnInit, AfterViewChecked {\n\n @ViewChild('scrollMe') private myScrollContainer: ElementRef;\n\n infoSubscription: Subscription;\n info = [];\n\n constructor(private infoService: InfoService) {\n\n // Subscription to info updated event raised by InfoService\n this.infoSubscription = this.infoService.newInfo$.subscribe(\n info => {\n this.info.push(info);\n });\n }\n\n ngOnInit() {\n\n }\n\n ngAfterViewChecked() {\n this.scrollToBottom();\n }\n\n scrollToBottom(): void {\n try {\n this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;\n } catch (err) {\n console.log('[Error]:' + err.toString());\n }\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/components/dashboard/dashboard.component.ts","import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'app-session-details',\n templateUrl: './session-details.component.html',\n styleUrls: ['./session-details.component.css']\n})\nexport class SessionDetailsComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit() {\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/app/components/session-details/session-details.component.ts"],"sourceRoot":""} \ No newline at end of file