ctbrec-5.3.2-experimental/common/src/main/java/ctbrec/Config.java

205 lines
7.8 KiB
Java

package ctbrec;
import static java.nio.file.StandardOpenOption.*;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.io.FileJsonAdapter;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.io.PostProcessorJsonAdapter;
import ctbrec.recorder.postprocessing.PostProcessor;
import ctbrec.sites.Site;
public class Config {
private static final Logger LOG = LoggerFactory.getLogger(Config.class);
private static Config instance;
private Settings settings;
private String filename;
private List<Site> sites;
private File configDir;
public static final String RECORDING_DATE_FORMAT = "yyyy-MM-dd_HH-mm-ss_SSS";
private Config(List<Site> sites) {
this.sites = sites;
if(System.getProperty("ctbrec.config.dir") != null) {
configDir = new File(System.getProperty("ctbrec.config.dir"));
} else {
configDir = OS.getConfigDir();
}
if(System.getProperty("ctbrec.config") != null) {
filename = System.getProperty("ctbrec.config");
} else {
filename = "settings.json";
}
}
private void load() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(Model.class, new ModelJsonAdapter(sites))
.add(PostProcessor.class, new PostProcessorJsonAdapter())
.add(File.class, new FileJsonAdapter())
.build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class).lenient();
File configFile = new File(configDir, filename);
LOG.info("Loading config from {}", configFile.getAbsolutePath());
if (configFile.exists()) {
try {
byte[] fileContent = Files.readAllBytes(configFile.toPath());
if (fileContent[0] == -17 && fileContent[1] == -69 && fileContent[2] == -65) {
// found BOM (byte order mark)
LOG.debug("Removing BOM from config file");
fileContent[0] = ' ';
fileContent[1] = ' ';
fileContent[2] = ' ';
}
String json = new String(fileContent, StandardCharsets.UTF_8.name()).trim();
settings = adapter.fromJson(json);
settings.httpTimeout = Math.max(settings.httpTimeout, 10_000);
if (settings.recordingsDir.endsWith("/")) {
settings.recordingsDir = settings.recordingsDir.substring(0, settings.recordingsDir.length() - 1);
}
} catch (Exception e) {
settings = OS.getDefaultSettings();
for (Site site : sites) {
site.setEnabled(!settings.disabledSites.contains(site.getName()));
}
makeBackup(configFile);
throw e;
}
} else {
LOG.error("Config file does not exist. Falling back to default values.");
settings = OS.getDefaultSettings();
}
for (Site site : sites) {
site.setEnabled(!settings.disabledSites.contains(site.getName()));
}
if(settings.minimumResolution == settings.maximumResolution && settings.minimumResolution == 0) {
settings.minimumResolution = 0;
settings.maximumResolution = 8640;
}
}
private void makeBackup(File source) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String timestamp = sdf.format(new Date());
String backup = source.getName() + '.' + timestamp;
File target = new File(source.getParentFile(), backup);
Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
LOG.error("Couldn't create backup of settings file", e);
}
}
public static synchronized void init(List<Site> sites) throws IOException {
if (instance == null) {
instance = new Config(sites);
instance.load();
}
}
public static synchronized Config getInstance() {
if (instance == null) {
throw new IllegalStateException("Config not initialized, call init() first");
}
return instance;
}
public Settings getSettings() {
return settings;
}
public void save() throws IOException {
Moshi moshi = new Moshi.Builder()
.add(Model.class, new ModelJsonAdapter())
.add(PostProcessor.class, new PostProcessorJsonAdapter())
.add(File.class, new FileJsonAdapter())
.build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class).indent(" ");
String json = adapter.toJson(settings);
File configFile = new File(configDir, filename);
LOG.debug("Saving config to {}", configFile.getAbsolutePath());
Files.createDirectories(configDir.toPath());
Files.write(configFile.toPath(), json.getBytes("utf-8"), CREATE, WRITE, TRUNCATE_EXISTING);
}
public static boolean isServerMode() {
return Objects.equals(System.getProperty("ctbrec.server.mode"), "1");
}
public static boolean isDevMode() {
return Objects.equals(System.getenv("CTBREC_DEV"), "1");
}
public File getConfigDir() {
return configDir;
}
public File getFileForRecording(Model model, String suffix, Instant startTime) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(RECORDING_DATE_FORMAT);
LocalDateTime startDateTime = LocalDateTime.ofInstant(startTime, ZoneId.systemDefault());
String formattedDate = dateTimeFormatter.format(startDateTime);
File dirForRecording = getDirForRecording(model, formattedDate);
File targetFile = new File(dirForRecording, model.getSanitizedNamed() + '_' + formattedDate + '.' + suffix);
return targetFile;
}
private File getDirForRecording(Model model, String formattedDate) {
switch (getSettings().recordingsDirStructure) {
case ONE_PER_MODEL:
return new File(getSettings().recordingsDir, model.getSanitizedNamed());
case ONE_PER_RECORDING:
File modelDir = new File(getSettings().recordingsDir, model.getSanitizedNamed());
return new File(modelDir, formattedDate);
case FLAT:
default:
return new File(getSettings().recordingsDir);
}
}
public String getServerUrl() {
String scheme = getSettings().transportLayerSecurity ? "https" : "http";
// int port = getSettings().transportLayerSecurity ? getSettings().httpSecurePort : getSettings().httpPort;
int port = getSettings().httpPort;
String baseUrl = scheme + "://" + getSettings().httpServer + ":" + port + getContextPath();
return baseUrl;
}
public String getContextPath() {
String context = Optional.ofNullable(getSettings().servletContext).orElse("");
if (!context.startsWith("/") && !context.isEmpty()) {
context = '/' + context;
}
if (context.endsWith("/")) {
context = context.substring(0, context.length() - 1);
}
return context;
}
public String getModelNotes(Model m) {
return Config.getInstance().getSettings().modelNotes.getOrDefault(m.getUrl(), "");
}
}