openvidu-server: OpenviduConfig refactoring

pull/370/head
pabloFuente 2019-10-08 17:12:22 +02:00
parent de2153fe0f
commit 3ed4ae0856
5 changed files with 474 additions and 204 deletions

View File

@ -18,12 +18,9 @@
package io.openvidu.server;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.kurento.jsonrpc.internal.server.config.JsonRpcConfiguration;
import org.kurento.jsonrpc.server.JsonRpcConfigurer;
import org.kurento.jsonrpc.server.JsonRpcHandlerRegistry;
@ -38,8 +35,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.EventListener;
import io.openvidu.client.OpenViduException;
import io.openvidu.client.OpenViduException.Code;
import io.openvidu.server.cdr.CDRLogger;
import io.openvidu.server.cdr.CDRLoggerFile;
import io.openvidu.server.cdr.CallDetailRecord;
@ -81,26 +76,45 @@ public class OpenViduServer implements JsonRpcConfigurer {
private static final Logger log = LoggerFactory.getLogger(OpenViduServer.class);
public static final String WS_PATH = "/openvidu";
public static String publicurlType;
public static String wsUrl;
public static String httpUrl;
@Autowired
OpenviduConfig openviduConfig;
public static final String KMSS_URIS_PROPERTY = "kms.uris";
public static String wsUrl;
public static String httpUrl;
@Bean
@ConditionalOnMissingBean
public KmsManager kmsManager() {
if (openviduConfig.getKmsUris().isEmpty()) {
throw new IllegalArgumentException(KMSS_URIS_PROPERTY + " should contain at least one kms url");
throw new IllegalArgumentException("'kms.uris' should contain at least one KMS url");
}
String firstKmsWsUri = openviduConfig.getKmsUris().get(0);
log.info("OpenVidu Server using one KMS: {}", firstKmsWsUri);
return new FixedOneKmsManager();
}
@Bean
@ConditionalOnMissingBean
public CallDetailRecord cdr() {
List<CDRLogger> loggers = new ArrayList<>();
if (openviduConfig.isCdrEnabled()) {
log.info("OpenVidu CDR is enabled");
loggers.add(new CDRLoggerFile());
}
if (openviduConfig.isWebhookEnabled()) {
loggers.add(new CDRLoggerWebhook(openviduConfig));
}
return new CallDetailRecord(loggers);
}
@Bean
@ConditionalOnMissingBean
public CoturnCredentialsService coturnCredentialsService() {
return new CoturnCredentialsServiceFactory().getCoturnCredentialsService(openviduConfig.getSpringProfile());
}
@Bean
@ConditionalOnMissingBean
public LoadManager loadManager() {
@ -131,20 +145,6 @@ public class OpenViduServer implements JsonRpcConfigurer {
return new KurentoSessionEventsHandler();
}
@Bean
@ConditionalOnMissingBean
public CallDetailRecord cdr() {
List<CDRLogger> loggers = new ArrayList<>();
if (openviduConfig.isCdrEnabled()) {
log.info("OpenVidu CDR is enabled");
loggers.add(new CDRLoggerFile());
}
if (openviduConfig.isWebhookEnabled()) {
loggers.add(new CDRLoggerWebhook(openviduConfig));
}
return new CallDetailRecord(loggers);
}
@Bean
@ConditionalOnMissingBean
public KurentoParticipantEndpointConfig kurentoEndpointConfig() {
@ -169,12 +169,6 @@ public class OpenViduServer implements JsonRpcConfigurer {
return new DummyRecordingDownloader();
}
@Bean
@ConditionalOnMissingBean
public CoturnCredentialsService coturnCredentialsService() {
return new CoturnCredentialsServiceFactory().getCoturnCredentialsService(openviduConfig.getSpringProfile());
}
@Bean
@ConditionalOnMissingBean
public GeoLocationByIp geoLocationByIp() {
@ -190,10 +184,10 @@ public class OpenViduServer implements JsonRpcConfigurer {
@Override
public void registerJsonRpcHandlers(JsonRpcHandlerRegistry registry) {
registry.addHandler(rpcHandler().withPingWatchdog(true).withInterceptors(new HttpHandshakeInterceptor()),
"/openvidu");
WS_PATH);
}
private static String getContainerIp() throws IOException, InterruptedException {
public static String getContainerIp() throws IOException, InterruptedException {
return CommandExecutor.execCommand("/bin/sh", "-c", "hostname -i | awk '{print $1}'");
}
@ -203,86 +197,14 @@ public class OpenViduServer implements JsonRpcConfigurer {
SpringApplication.run(OpenViduServer.class, args);
}
@PostConstruct
public void init() throws MalformedURLException, InterruptedException {
String publicUrl = this.openviduConfig.getOpenViduPublicUrl();
String type = publicUrl;
switch (publicUrl) {
case "docker":
try {
String containerIp = getContainerIp();
OpenViduServer.wsUrl = "wss://" + containerIp + ":" + openviduConfig.getServerPort();
} catch (Exception e) {
log.error("Docker container IP was configured, but there was an error obtaining IP: "
+ e.getClass().getName() + " " + e.getMessage());
log.error("Fallback to local URL");
OpenViduServer.wsUrl = null;
}
break;
case "local":
break;
case "":
break;
default:
type = "custom";
if (publicUrl.startsWith("https://")) {
OpenViduServer.wsUrl = publicUrl.replace("https://", "wss://");
} else if (publicUrl.startsWith("http://")) {
OpenViduServer.wsUrl = publicUrl.replace("http://", "wss://");
}
if (!OpenViduServer.wsUrl.startsWith("wss://")) {
OpenViduServer.wsUrl = "wss://" + OpenViduServer.wsUrl;
}
}
if (OpenViduServer.wsUrl == null) {
type = "local";
OpenViduServer.wsUrl = "wss://localhost:" + openviduConfig.getServerPort();
}
if (OpenViduServer.wsUrl.endsWith("/")) {
OpenViduServer.wsUrl = OpenViduServer.wsUrl.substring(0, OpenViduServer.wsUrl.length() - 1);
}
if (this.openviduConfig.isRecordingModuleEnabled()) {
try {
this.recordingManager().initializeRecordingManager();
} catch (OpenViduException e) {
String finalErrorMessage = "";
if (e.getCodeValue() == Code.DOCKER_NOT_FOUND.getValue()) {
finalErrorMessage = "Error connecting to Docker daemon. Enabling OpenVidu recording module requires Docker";
} else if (e.getCodeValue() == Code.RECORDING_PATH_NOT_VALID.getValue()) {
finalErrorMessage = "Error initializing recording path \""
+ this.openviduConfig.getOpenViduRecordingPath()
+ "\" set with system property \"openvidu.recording.path\"";
} else if (e.getCodeValue() == Code.RECORDING_FILE_EMPTY_ERROR.getValue()) {
finalErrorMessage = "Error initializing recording custom layouts path \""
+ this.openviduConfig.getOpenviduRecordingCustomLayout()
+ "\" set with system property \"openvidu.recording.custom-layout\"";
}
log.error(finalErrorMessage + ". Shutting down OpenVidu Server");
System.exit(1);
}
}
String finalUrl = OpenViduServer.wsUrl.replaceFirst("wss://", "https://").replaceFirst("ws://", "http://");
openviduConfig.setFinalUrl(finalUrl);
httpUrl = openviduConfig.getFinalUrl();
log.info("OpenVidu Server using " + type + " URL: [" + OpenViduServer.wsUrl + "]");
}
@EventListener(ApplicationReadyEvent.class)
public void whenReady() {
log.info("OpenVidu Server listening for client websocket connections on"
+ (OpenViduServer.publicurlType.isEmpty() ? "" : (" " + OpenViduServer.publicurlType)) + " url "
+ OpenViduServer.wsUrl + WS_PATH);
final String NEW_LINE = System.lineSeparator();
String str = NEW_LINE + NEW_LINE + " ACCESS IP " + NEW_LINE + "-------------------------"
+ NEW_LINE + httpUrl + NEW_LINE + "-------------------------" + NEW_LINE;
String str = NEW_LINE + NEW_LINE + " OPENVIDU SERVER IP " + NEW_LINE + "--------------------------"
+ NEW_LINE + httpUrl + NEW_LINE + "--------------------------" + NEW_LINE;
log.info(str);
}

View File

@ -19,12 +19,18 @@ package io.openvidu.server.config;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.PostConstruct;
@ -46,18 +52,42 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.openvidu.java.client.OpenViduRole;
import io.openvidu.server.OpenViduServer;
import io.openvidu.server.cdr.CDREventName;
import io.openvidu.server.recording.RecordingNotification;
@Component
public class OpenviduConfig {
private static final Logger log = LoggerFactory.getLogger(OpenviduConfig.class);
public static final List<String> OPENVIDU_STRING_PROPERTIES = Arrays.asList(new String[] { "openvidu.secret",
"openvidu.publicurl", "openvidu.recording.path", "openvidu.recording.notification",
"openvidu.recording.custom-layout", "openvidu.webhook.endpoint" });
public static final List<String> OPENVIDU_INTEGER_PROPERTIES = Arrays
.asList(new String[] { "openvidu.recording.autostop-timeout", "openvidu.streams.video.max-recv-bandwidth",
"openvidu.streams.video.min-recv-bandwidth", "openvidu.streams.video.max-send-bandwidth",
"openvidu.streams.video.min-send-bandwidth" });
public static final List<String> OPENVIDU_BOOLEAN_PROPERTIES = Arrays.asList(new String[] { "openvidu.cdr",
"openvidu.recording", "openvidu.recording.public-access", "openvidu.webhook", });
public static final List<String> OPENVIDU_ARRAY_PROPERTIES = Arrays
.asList(new String[] { "kms.uris", "openvidu.webhook.headers", "openvidu.webhook.events", });
public static final List<String> OPENVIDU_PROPERTIES = Stream.of(OPENVIDU_STRING_PROPERTIES,
OPENVIDU_INTEGER_PROPERTIES, OPENVIDU_BOOLEAN_PROPERTIES, OPENVIDU_ARRAY_PROPERTIES)
.flatMap(Collection::stream).collect(Collectors.toList());
public static final List<String> OPENVIDU_VALID_PUBLICURL_VALUES = Arrays
.asList(new String[] { "local", "docker", "" });
@Value("#{'${spring.config.additional-location:}'.length() > 0 ? '${spring.config.additional-location:}' : \"\"}")
private String springConfigLocation;
@Autowired
BuildProperties buildProperties;
private BuildProperties buildProperties;
@Value("${kms.uris}")
private String kmsUris;
@ -87,7 +117,7 @@ public class OpenviduConfig {
private boolean openviduRecordingPublicAccess;
@Value("${openvidu.recording.notification}")
private String openviduRecordingNotification;
private RecordingNotification openviduRecordingNotification;
@Value("${openvidu.recording.custom-layout}")
private String openviduRecordingCustomLayout;
@ -144,72 +174,9 @@ public class OpenviduConfig {
private List<String> kmsUrisList;
private List<Header> webhookHeadersList;
private List<CDREventName> webhookEventsList;
private Properties externalizedProperties;
@PostConstruct
public void init() {
if (!this.springConfigLocation.isEmpty()) {
// Properties file has been manually configured in certain path
FileSystemResource resource = new FileSystemResource(this.springConfigLocation);
try {
this.externalizedProperties = PropertiesLoaderUtils.loadProperties(resource);
log.info("Properties file found at \"{}\". Content: {}", this.springConfigLocation,
externalizedProperties);
} catch (IOException e) {
log.error("Error in 'spring.config.additional-location' system property: {}", e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
// Check OpenVidu Server write permissions in properties path
if (!Files.isWritable(Paths.get(this.springConfigLocation))) {
log.warn(
"The properties path '{}' set with property 'spring.config.additional-location' is not valid. Reason: OpenVidu Server needs write permissions. Try running command \"sudo chmod 777 {}\". If not, OpenVidu won't be able to overwrite preexisting properties on reboot",
this.springConfigLocation, this.springConfigLocation);
} else {
log.info("OpenVidu Server has write permissions on properties path: {}", this.springConfigLocation);
}
}
try {
this.kmsUrisList = this.kmsUrisStringToList(this.kmsUris);
} catch (Exception e) {
log.error("Error in 'kms.uris' system property: " + e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
if (this.isWebhookEnabled()) {
log.info("OpenVidu Webhook service enabled");
try {
if (this.openviduWebhookEndpoint == null || this.openviduWebhookEndpoint.isEmpty()) {
log.error(
"If OpenVidu Webhook service is enabled property 'openvidu.webhook.endpoint' must be defined");
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
this.initiateOpenViduWebhookEndpoint(this.openviduWebhookEndpoint);
} catch (Exception e) {
log.error("Error in 'openvidu.webhook.endpoint' system property. " + e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
try {
this.initiateOpenViduWebhookHeaders(this.openviduWebhookHeaders);
} catch (Exception e) {
log.error("Error in 'openvidu.webhook.headers' system property: " + e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
try {
this.initiateOpenViduWebhookEvents(this.openviduWebhookEvents);
} catch (Exception e) {
log.error("Error in 'openvidu.webhook.events' system property: " + e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
}
}
public List<String> getKmsUris() {
return this.kmsUrisList;
}
@ -311,7 +278,7 @@ public class OpenviduConfig {
return this.coturnRedisDbname;
}
public String getOpenViduRecordingNotification() {
public RecordingNotification getOpenViduRecordingNotification() {
return this.openviduRecordingNotification;
}
@ -338,16 +305,16 @@ public class OpenviduConfig {
public OpenViduRole[] getRolesFromRecordingNotification() {
OpenViduRole[] roles;
switch (this.openviduRecordingNotification) {
case "none":
case none:
roles = new OpenViduRole[0];
break;
case "moderator":
case moderator:
roles = new OpenViduRole[] { OpenViduRole.MODERATOR };
break;
case "publisher_moderator":
case publisher_moderator:
roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
break;
case "all":
case all:
roles = new OpenViduRole[] { OpenViduRole.SUBSCRIBER, OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
break;
default:
@ -380,6 +347,256 @@ public class OpenviduConfig {
return this.externalizedProperties;
}
public void checkWebsocketUri(String uri) throws Exception {
try {
if (!uri.startsWith("ws://") || uri.startsWith("wss://")) {
throw new Exception("WebSocket protocol not found");
}
String parsedUri = uri.replaceAll("^ws://", "http://").replaceAll("^wss://", "https://");
new URL(parsedUri).toURI();
} catch (Exception e) {
throw new Exception("URI '" + uri + "' has not a valid WebSocket endpoint format: " + e.getMessage());
}
}
public void checkConfigurationParameters(Map<String, ?> parameters, Collection<String> validKeys) throws Exception {
parameters = this.filterValidParameters(parameters, validKeys);
log.info("Checking configuration parameters: {}", parameters.keySet());
for (String parameter : parameters.keySet()) {
switch (parameter) {
case "openvidu.secret":
String secret = checkString(parameters, parameter);
if (secret.isEmpty()) {
throw new Exception("Property 'openvidu.secret' cannot be empty");
}
break;
case "openvidu.publicurl":
String publicurl = checkString(parameters, parameter);
if (!OPENVIDU_VALID_PUBLICURL_VALUES.contains(publicurl)) {
// Must be a valid URL
try {
new URL(publicurl).toURI();
} catch (MalformedURLException | URISyntaxException e) {
throw new Exception(
"Property 'openvidu.publicurl' has not a valid URL format: " + e.getMessage());
}
}
break;
case "openvidu.cdr":
checkBoolean(parameters, parameter);
break;
case "openvidu.recording":
checkBoolean(parameters, parameter);
break;
case "openvidu.recording.public-access":
checkBoolean(parameters, parameter);
break;
case "openvidu.recording.autostop-timeout":
checkIntegerNonNegative(parameters, parameter);
break;
case "openvidu.recording.notification":
String recordingNotif = checkString(parameters, parameter);
try {
RecordingNotification.valueOf(recordingNotif);
} catch (IllegalArgumentException e) {
throw new Exception("Property 'openvidu.recording.notification' has not a valid value ('"
+ recordingNotif + "'). Must be one of " + Arrays.asList(RecordingNotification.values()));
}
break;
case "openvidu.webhook":
checkBoolean(parameters, parameter);
break;
case "openvidu.webhook.endpoint":
String webhookEndpoint = checkString(parameters, parameter);
try {
checkWebhookEndpoint(webhookEndpoint);
} catch (Exception e) {
throw new Exception("Property 'openvidu.webhook.endpoint' is not valid: " + e.getMessage());
}
break;
case "openvidu.streams.video.max-recv-bandwidth":
checkIntegerNonNegative(parameters, parameter);
break;
case "openvidu.streams.video.min-recv-bandwidth":
checkIntegerNonNegative(parameters, parameter);
break;
case "openvidu.streams.video.max-send-bandwidth":
checkIntegerNonNegative(parameters, parameter);
break;
case "openvidu.streams.video.min-send-bandwidth":
checkIntegerNonNegative(parameters, parameter);
break;
case "kms.uris":
String kmsUris;
try {
// First check if castable to a List
List<?> list = checkArray(parameters, parameter);
String elementString;
for (Object element : list) {
try {
// Check every object is a String value
elementString = (String) element;
} catch (ClassCastException e) {
throw new Exception("Property 'kms.uris' is an array, but contains a value (" + element
+ ") that is not a string: " + e.getMessage());
}
}
kmsUris = list.toString();
} catch (Exception e) {
// If it is not a list, try casting to String
kmsUris = checkString(parameters, parameter);
}
// Finally check all strings have a valid WebSocket URI format
try {
kmsUrisStringToList(kmsUris);
} catch (Exception e) {
throw new Exception(
"Property 'kms.uris' is an array of strings, but contains some value that has not a valid WbeSocket URI format: "
+ e.getMessage());
}
break;
case "openvidu.webhook.headers":
String webhookHeaders;
try {
// First check if castable to a List
List<?> list = checkArray(parameters, parameter);
String elementString;
for (Object element : list) {
try {
// Check every object is a String value
elementString = (String) element;
} catch (ClassCastException e) {
throw new Exception(
"Property 'openvidu.webhook.headers' is an array, but contains a value (" + element
+ ") that is not a string: " + e.getMessage());
}
}
webhookHeaders = list.toString();
} catch (Exception e) {
// If it is not a list, try casting to String
webhookHeaders = checkString(parameters, parameter);
}
try {
checkWebhookHeaders(webhookHeaders);
} catch (Exception e) {
throw new Exception(
"Property 'openvidu.webhook.headers' contains a value not valid: " + e.getMessage());
}
break;
case "openvidu.webhook.events":
String webhookEvents;
try {
// First check if castable to a List
List<?> list = checkArray(parameters, parameter);
String elementString;
for (Object element : list) {
try {
// Check every object is a String value
elementString = (String) element;
} catch (ClassCastException e) {
throw new Exception("Property 'openvidu.webhook.events' is an array, but contains a value ("
+ element + ") that is not a string: " + e.getMessage());
}
}
webhookEvents = list.toString();
} catch (Exception e) {
// If it is not a list, try casting to String
webhookEvents = checkString(parameters, parameter);
}
try {
checkWebhookEvents(webhookEvents);
} catch (Exception e) {
throw new Exception(
"Property 'openvidu.webhook.events' contains a value not valid: " + e.getMessage());
}
break;
case "openvidu.recording.path":
checkString(parameters, parameter);
break;
case "openvidu.recording.custom-layout":
checkString(parameters, parameter);
break;
default:
log.warn("Unknown configuration parameter '{}'", parameter);
}
}
}
public String checkString(Map<String, ?> parameters, String key) throws Exception {
try {
String stringValue = (String) parameters.get(key);
return stringValue;
} catch (ClassCastException e) {
throw new Exception("Property '" + key + "' must be a string: " + e.getMessage());
}
}
public boolean checkBoolean(Map<String, ?> parameters, String key) throws Exception {
try {
boolean booleanValue = Boolean.parseBoolean((String) parameters.get(key));
return booleanValue;
} catch (ClassCastException e) {
throw new Exception("Property '" + key + "' must be a boolean: " + e.getMessage());
}
}
public Integer checkIntegerNonNegative(Map<String, ?> parameters, String key) throws Exception {
try {
Integer integerValue = Integer.parseInt((String) parameters.get(key));
if (integerValue < 0) {
throw new Exception("Property '" + key + "' is an integer but cannot be less than 0 (current value: "
+ integerValue + ")");
}
return integerValue;
} catch (ClassCastException e) {
throw new Exception("Property '" + key + "' must be an integer: " + e.getMessage());
}
}
public List<?> checkArray(Map<String, ?> parameters, String key) throws Exception {
try {
List<String> list = (List<String>) parameters.get(key);
return list;
} catch (ClassCastException e) {
throw new Exception("Property '" + key + "' must be an array: " + e.getMessage());
}
}
public Map<String, ?> filterValidParameters(Map<String, ?> parameters, Collection<String> validKeys) {
return parameters.entrySet().stream().filter(x -> validKeys.contains(x.getKey()))
.collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
}
public Properties retrieveExternalizedProperties() throws Exception {
if (this.springConfigLocation.isEmpty()) {
throw new Exception(
"Externalized properties file not found. Path must be set with configuration parameter 'spring.config.additional-location'");
}
Properties externalizedProps = null;
FileSystemResource resource = new FileSystemResource(this.springConfigLocation);
try {
externalizedProps = PropertiesLoaderUtils.loadProperties(resource);
log.info("Properties file found at \"{}\". Content: {}", this.springConfigLocation, externalizedProps);
} catch (IOException e) {
throw new Exception("Error in 'spring.config.additional-location' system property. Cannot load properties: "
+ e.getMessage());
}
// Check OpenVidu Server write permissions in properties path
if (!Files.isWritable(Paths.get(this.springConfigLocation))) {
log.warn(
"The properties path '{}' set with property 'spring.config.additional-location' is missconfigured. Reason: OpenVidu Server needs write permissions. Try running command \"sudo chmod 777 {}\". If not, OpenVidu won't be able to overwrite preexisting properties",
this.springConfigLocation, this.springConfigLocation);
} else {
log.info("OpenVidu Server has write permissions on properties path {}", this.springConfigLocation);
}
return externalizedProps;
}
public List<String> kmsUrisStringToList(String kmsUris) throws Exception {
kmsUris = kmsUris.replaceAll("\\s", ""); // Remove all white spaces
kmsUris = kmsUris.replaceAll("\\\\", ""); // Remove previous escapes
@ -392,7 +609,6 @@ public class OpenviduConfig {
List<String> list = JsonUtils.toStringList(kmsUrisArray);
if (list.size() == 1 && list.get(0).isEmpty()) {
log.warn("Array kms.uris is empty");
list = new ArrayList<>();
} else {
for (String uri : list) {
@ -402,20 +618,20 @@ public class OpenviduConfig {
return list;
}
public void initiateOpenViduWebhookEndpoint(String endpoint) throws Exception {
private void checkWebhookEndpoint(String endpoint) throws Exception {
try {
new URL(endpoint);
new URL(endpoint).toURI();
log.info("OpenVidu Webhook endpoint is {}", endpoint);
} catch (MalformedURLException e) {
} catch (MalformedURLException | URISyntaxException e) {
throw new Exception("Webhook endpoint '" + endpoint + "' is not correct. Malformed URL: " + e.getMessage());
}
}
public void initiateOpenViduWebhookHeaders(String headers) throws Exception {
private List<Header> checkWebhookHeaders(String headers) throws Exception {
JsonParser parser = new JsonParser();
JsonElement elem = parser.parse(headers);
JsonArray headersJsonArray = elem.getAsJsonArray();
this.webhookHeadersList = new ArrayList<>();
List<Header> headerList = new ArrayList<>();
for (JsonElement jsonElement : headersJsonArray) {
String headerString = jsonElement.getAsString();
@ -434,37 +650,112 @@ public class OpenviduConfig {
throw new Exception(
"HTTP header '" + headerString + "' syntax is not correct. Header value cannot be empty");
}
this.webhookHeadersList.add(new BasicHeader(headerName, headerValue));
headerList.add(new BasicHeader(headerName, headerValue));
}
log.info("OpenVidu Webhook headers: {}", this.getOpenViduWebhookHeaders().toString());
return headerList;
}
public void initiateOpenViduWebhookEvents(String events) throws Exception {
private List<CDREventName> checkWebhookEvents(String events) throws Exception {
JsonParser parser = new JsonParser();
JsonElement elem = parser.parse(events);
JsonArray eventsJsonArray = elem.getAsJsonArray();
this.webhookEventsList = new ArrayList<>();
List<CDREventName> eventList = new ArrayList<>();
for (JsonElement jsonElement : eventsJsonArray) {
String eventString = jsonElement.getAsString();
try {
CDREventName.valueOf(eventString);
} catch (IllegalArgumentException e) {
throw new Exception("Event name '" + eventString + "' does not exist");
throw new Exception("Event '" + eventString + "' does not exist");
}
this.webhookEventsList.add(CDREventName.valueOf(eventString));
eventList.add(CDREventName.valueOf(eventString));
}
log.info("OpenVidu Webhook events: {}", this.getOpenViduWebhookEvents().toString());
return eventList;
}
public void checkWebsocketUri(String uri) throws MalformedURLException {
try {
String parsedUri = uri.replaceAll("^ws://", "http://").replaceAll("^wss://", "https://");
new URL(parsedUri);
} catch (MalformedURLException e) {
log.error("URI {} is not a valid WebSocket endpoint", uri);
throw e;
@PostConstruct
public void init() {
// Check configuration parameters
Map<String, ?> props = null;
if (!this.springConfigLocation.isEmpty()) {
try {
this.externalizedProperties = this.retrieveExternalizedProperties();
props = (Map) this.externalizedProperties;
} catch (Exception e) {
log.error(e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
} else {
props = (Map) System.getProperties();
}
try {
this.checkConfigurationParameters(props, OPENVIDU_PROPERTIES);
} catch (Exception e) {
log.error(e.getMessage());
log.error("Shutting down OpenVidu Server");
System.exit(1);
}
try {
this.kmsUrisList = this.kmsUrisStringToList(this.kmsUris);
if (this.isWebhookEnabled()) {
this.webhookHeadersList = this.checkWebhookHeaders(this.openviduWebhookHeaders);
this.webhookEventsList = this.checkWebhookEvents(this.openviduWebhookEvents);
log.info("OpenVidu Webhook endpoint: {}", this.openviduWebhookEndpoint);
log.info("OpenVidu Webhook headers: {}", this.getOpenViduWebhookHeaders().toString());
log.info("OpenVidu Webhook events: {}", this.getOpenViduWebhookEvents().toString());
}
} catch (Exception e) {
log.error("Unexpected exception when setting final value of configuration parameters: {}", e.getMessage());
}
// Generate final public url
String publicUrl = this.getOpenViduPublicUrl();
String type = "";
switch (publicUrl) {
case "docker":
try {
String containerIp = OpenViduServer.getContainerIp();
OpenViduServer.wsUrl = "wss://" + containerIp + ":" + this.getServerPort();
} catch (Exception e) {
log.error("Docker container IP was configured, but there was an error obtaining IP: "
+ e.getClass().getName() + " " + e.getMessage());
log.error("Fallback to local URL");
OpenViduServer.wsUrl = null;
}
break;
case "local":
break;
case "":
break;
default:
if (publicUrl.startsWith("https://")) {
OpenViduServer.wsUrl = publicUrl.replace("https://", "wss://");
} else if (publicUrl.startsWith("http://")) {
OpenViduServer.wsUrl = publicUrl.replace("http://", "wss://");
}
if (!OpenViduServer.wsUrl.startsWith("wss://")) {
OpenViduServer.wsUrl = "wss://" + OpenViduServer.wsUrl;
}
}
if (OpenViduServer.wsUrl == null) {
type = "local";
OpenViduServer.wsUrl = "wss://localhost:" + this.getServerPort();
}
if (OpenViduServer.wsUrl.endsWith("/")) {
OpenViduServer.wsUrl = OpenViduServer.wsUrl.substring(0, OpenViduServer.wsUrl.length() - 1);
}
String finalUrl = OpenViduServer.wsUrl.replaceFirst("wss://", "https://").replaceFirst("ws://", "http://");
this.setFinalUrl(finalUrl);
OpenViduServer.httpUrl = this.getFinalUrl();
OpenViduServer.publicurlType = type;
}
}

View File

@ -0,0 +1,31 @@
package io.openvidu.server.recording;
/**
* Defines which users should receive the Session recording notifications on the
* client side (recordingStarted, recordingStopped)
*
* @author Pablo Fuente (pablofuenteperez@gmail.com)
*/
public enum RecordingNotification {
/*
* No user of the session will receive recording events
*/
none,
/*
* Only users with role MODERATOR will receive recording events
*/
moderator,
/*
* Users with role MODERATOR or PUBLISHER will receive recording events
*/
publisher_moderator,
/*
* All users of to the session will receive recording events
*/
all
}

View File

@ -36,6 +36,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.apache.commons.io.FileUtils;
import org.kurento.client.ErrorEvent;
import org.kurento.client.EventListener;
@ -116,6 +118,30 @@ public class RecordingManager {
.asList(new EndReason[] { EndReason.disconnect, EndReason.forceDisconnectByUser,
EndReason.forceDisconnectByServer, EndReason.networkDisconnect });
@PostConstruct
public void init() {
if (this.openviduConfig.isRecordingModuleEnabled()) {
try {
this.initializeRecordingManager();
} catch (OpenViduException e) {
String finalErrorMessage = "";
if (e.getCodeValue() == Code.DOCKER_NOT_FOUND.getValue()) {
finalErrorMessage = "Error connecting to Docker daemon. Enabling OpenVidu recording module requires Docker";
} else if (e.getCodeValue() == Code.RECORDING_PATH_NOT_VALID.getValue()) {
finalErrorMessage = "Error initializing recording path \""
+ this.openviduConfig.getOpenViduRecordingPath()
+ "\" set with system property \"openvidu.recording.path\"";
} else if (e.getCodeValue() == Code.RECORDING_FILE_EMPTY_ERROR.getValue()) {
finalErrorMessage = "Error initializing recording custom layouts path \""
+ this.openviduConfig.getOpenviduRecordingCustomLayout()
+ "\" set with system property \"openvidu.recording.custom-layout\"";
}
log.error(finalErrorMessage + ". Shutting down OpenVidu Server");
System.exit(1);
}
}
}
public void initializeRecordingManager() throws OpenViduException {
RecordingManager.IMAGE_TAG = openviduConfig.getOpenViduRecordingVersion();

View File

@ -48,7 +48,7 @@ public class ConfigRestController {
private static final Logger log = LoggerFactory.getLogger(ConfigRestController.class);
@Autowired
protected OpenviduConfig openviduConfig;
private OpenviduConfig openviduConfig;
@RequestMapping(value = "/openvidu-version", method = RequestMethod.GET)
public String getOpenViduServerVersion() {
@ -108,7 +108,7 @@ public class ConfigRestController {
json.addProperty("openviduRecordingVersion", openviduConfig.getOpenViduRecordingVersion());
json.addProperty("openviduRecordingPath", openviduConfig.getOpenViduRecordingPath());
json.addProperty("openviduRecordingPublicAccess", openviduConfig.getOpenViduRecordingPublicAccess());
json.addProperty("openviduRecordingNotification", openviduConfig.getOpenViduRecordingNotification());
json.addProperty("openviduRecordingNotification", openviduConfig.getOpenViduRecordingNotification().name());
json.addProperty("openviduRecordingCustomLayout", openviduConfig.getOpenviduRecordingCustomLayout());
json.addProperty("openviduRecordingAutostopTimeout", openviduConfig.getOpenviduRecordingAutostopTimeout());
}