From 0d2fcfbff7c7ecc14d7ddccf82b6750fa47d1353 Mon Sep 17 00:00:00 2001 From: micaelgallego Date: Wed, 8 Apr 2020 03:20:08 +0200 Subject: [PATCH] Prepare for updating .env config file in PRO --- .../io/openvidu/server/OpenViduServer.java | 14 +- .../io/openvidu/server/config/Dotenv.java | 147 ++++++++++++++++++ .../server/config/OpenviduConfig.java | 26 +++- .../io/openvidu/server/config/DotenvTest.java | 85 ++++++++++ openvidu-server/src/test/resources/.env | 5 + 5 files changed, 269 insertions(+), 8 deletions(-) create mode 100644 openvidu-server/src/main/java/io/openvidu/server/config/Dotenv.java create mode 100644 openvidu-server/src/test/java/io/openvidu/server/config/DotenvTest.java create mode 100644 openvidu-server/src/test/resources/.env 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 fd4cb5f5..64407141 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java +++ b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java @@ -242,12 +242,16 @@ public class OpenViduServer implements JsonRpcConfigurer { String msg = "\n\n\n" + " Configuration errors\n" + " --------------------\n" + "\n"; for (Error error : config.getConfigErrors()) { - msg += " * Property " + config.getPropertyName(error.getProperty()); - if (error.getValue() == null || error.getValue().equals("")) { - msg += " is not set. "; - } else { - msg += "=" + error.getValue() + ". "; + msg += " * "; + if(error.getProperty() != null) { + msg += "Property " + config.getPropertyName(error.getProperty()); + if (error.getValue() == null || error.getValue().equals("")) { + msg += " is not set. "; + } else { + msg += "=" + error.getValue() + ". "; + } } + msg += error.getMessage() + "\n"; } diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/Dotenv.java b/openvidu-server/src/main/java/io/openvidu/server/config/Dotenv.java new file mode 100644 index 00000000..b5ff822a --- /dev/null +++ b/openvidu-server/src/main/java/io/openvidu/server/config/Dotenv.java @@ -0,0 +1,147 @@ +package io.openvidu.server.config; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Dotenv { + + public static class DotenvFormatException extends Exception { + + private static final long serialVersionUID = -7280645547648990756L; + + public DotenvFormatException(String msg) { + super(msg); + } + } + + private static Logger log = LoggerFactory.getLogger(Dotenv.class); + + private List lines; + private Map properties; + + private Path envFile; + + private List additionalProperties = new ArrayList<>(); + + public void read() throws IOException, DotenvFormatException { + read(Paths.get(".env")); + } + + public String get(String property) { + return properties.get(property); + } + + public Path getEnvFile() { + return envFile; + } + + public void write() throws IOException { + write(envFile); + } + + public void write(Path envFile) throws IOException { + + List outLines = new ArrayList<>(); + + for (String line : lines) { + + try { + + Pair propValue = parseLine(envFile, line); + if(propValue == null) { + outLines.add(line); + } else { + outLines.add(propValue.getKey()+"="+properties.get(propValue.getKey())); + } + + } catch (DotenvFormatException e) { + log.error("Previously parsed line is producing a parser error", e); + } + } + + if(!additionalProperties.isEmpty()) { + for(String prop : additionalProperties) { + outLines.add(prop+"="+properties.get(prop)); + } + } + + Files.write(envFile, outLines, Charset.defaultCharset(), StandardOpenOption.CREATE); + + } + + public void read(Path envFile) throws IOException, DotenvFormatException { + + this.envFile = envFile; + + lines = Files.readAllLines(envFile); + + properties = new HashMap<>(); + for (String line : lines) { + + log.debug("Reading line '{}'", line); + + Pair propValue = parseLine(envFile, line); + + if (propValue != null) { + + log.debug("Setting property {}={}", propValue.getKey(), propValue.getValue()); + + properties.put(propValue.getKey(), propValue.getValue()); + } + } + } + + private Pair parseLine(Path envFile, String line) throws DotenvFormatException { + + if (isWhitespace(line) || isComment(line)) { + return null; + } + + int index = line.indexOf("="); + + if (index == -1) { + throw new DotenvFormatException("File " + envFile + " has a malformed line with content \"" + line + "\""); + } + + String property = line.substring(0, index).trim(); + + if (property.equals("")) { + throw new DotenvFormatException("File " + envFile + " has a malformed line with content \"" + line + "\""); + } + + String value = line.substring(index + 1); + + return ImmutablePair.of(property, value); + } + + private boolean isComment(String line) { + return line.startsWith("#") || line.startsWith("//"); + } + + private boolean isWhitespace(String line) { + return line.trim().equals(""); + } + + public void set(String property, String value) { + + if (!properties.containsKey(property)) { + additionalProperties.add(property); + } + + this.properties.put(property, value); + } + +} diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java index deca9b0e..ad94b3fc 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java +++ b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java @@ -18,6 +18,7 @@ package io.openvidu.server.config; import java.io.File; +import java.io.IOException; import java.net.Inet6Address; import java.net.MalformedURLException; import java.net.URI; @@ -50,6 +51,7 @@ import com.google.gson.JsonSyntaxException; import io.openvidu.java.client.OpenViduRole; import io.openvidu.server.OpenViduServer; import io.openvidu.server.cdr.CDREventName; +import io.openvidu.server.config.Dotenv.DotenvFormatException; import io.openvidu.server.recording.RecordingNotification; @Component @@ -96,6 +98,8 @@ public class OpenviduConfig { @Autowired protected Environment env; + protected Dotenv dotenv; + @Value("#{'${spring.profiles.active:}'.length() > 0 ? '${spring.profiles.active:}'.split(',') : \"default\"}") protected String springProfile; @@ -371,7 +375,17 @@ public class OpenviduConfig { @PostConstruct protected void checkConfigurationProperties() { - + + dotenv = new Dotenv(); + + try { + dotenv.read(); + } catch (IOException e) { + log.warn("Exception reading .env file. "+ e.getClass()+":"+e.getMessage()); + } catch (DotenvFormatException e) { + log.warn("Format error in .env file. "+ e.getClass()+":"+e.getMessage()); + } + try { this.checkConfigurationParameters(); } catch (Exception e) { @@ -556,8 +570,15 @@ public class OpenviduConfig { } public List checkKmsUris() { + String property = "kms.uris"; - String kmsUris = getConfigValue(property); + + return asKmsUris(property, getConfigValue(property)); + + } + + public List asKmsUris(String property, String kmsUris) { + if (kmsUris == null || kmsUris.isEmpty()) { return Arrays.asList(); } @@ -577,7 +598,6 @@ public class OpenviduConfig { addError(property, uri + " is not a valid WebSocket URL"); } } - return kmsUrisArray; } diff --git a/openvidu-server/src/test/java/io/openvidu/server/config/DotenvTest.java b/openvidu-server/src/test/java/io/openvidu/server/config/DotenvTest.java new file mode 100644 index 00000000..fc7a9f87 --- /dev/null +++ b/openvidu-server/src/test/java/io/openvidu/server/config/DotenvTest.java @@ -0,0 +1,85 @@ +package io.openvidu.server.config; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import org.junit.jupiter.api.Test; + +import io.openvidu.server.config.Dotenv.DotenvFormatException; + +class DotenvTest { + + @Test + void loadTest() throws IOException, DotenvFormatException { + + // Given + Path envFile = createDotenvTestFile(); + + Dotenv dotenv = new Dotenv(); + + // When + dotenv.read(envFile); + + // Then + assertEquals("value1", dotenv.get("PROPERTY_ONE")); + assertEquals("value2", dotenv.get("PROPERTY_TWO")); + } + + @Test + void writeSameFileTest() throws IOException, DotenvFormatException { + + // Given + Path envFile = createDotenvTestFile(); + String originalEnvContent = new String(Files.readAllBytes(envFile)); + + Dotenv dotenv = new Dotenv(); + + // When + dotenv.read(envFile); + + Files.delete(envFile); + + dotenv.write(); + String recreatedEnvContent = new String(Files.readAllBytes(envFile)); + + // Then + assertEquals(originalEnvContent, recreatedEnvContent); + } + + @Test + void writeModifiedFileTest() throws IOException, DotenvFormatException { + + // Given + Path envFile = createDotenvTestFile(); + + Dotenv dotenv = new Dotenv(); + + // When + dotenv.read(envFile); + + dotenv.set("PROPERTY_ONE", "value_one"); + dotenv.set("PROPERTY_TWO", "value_two"); + dotenv.set("PROPERTY_THREE", "value_three"); + + dotenv.write(); + + Dotenv updDotenv = new Dotenv(); + updDotenv.read(envFile); + + // Then + assertEquals("value_one", updDotenv.get("PROPERTY_ONE")); + assertEquals("value_two", updDotenv.get("PROPERTY_TWO")); + assertEquals("value_three", updDotenv.get("PROPERTY_THREE")); + } + + private Path createDotenvTestFile() throws IOException { + Path envFile = Files.createTempFile("env", ".tmp"); + Files.copy(getClass().getResourceAsStream("/.env"), envFile, StandardCopyOption.REPLACE_EXISTING); + return envFile; + } + +} diff --git a/openvidu-server/src/test/resources/.env b/openvidu-server/src/test/resources/.env new file mode 100644 index 00000000..9562c7a9 --- /dev/null +++ b/openvidu-server/src/test/resources/.env @@ -0,0 +1,5 @@ +# Comment 1 +PROPERTY_ONE=value1 + +# Comment 2 +PROPERTY_TWO=value2