mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2025-01-24 17:21:21 +01:00
Remove all usages of java.io.File and bad usages of Path.of()
This commit is contained in:
parent
ce25eb52e3
commit
d7dd8931a5
@ -200,7 +200,7 @@ private synchronized void loadMap(String id, MapConfig mapConfig) throws Configu
|
||||
dimension = DataPack.DIMENSION_THE_END;
|
||||
} else if (
|
||||
worldFolder.getNameCount() > 3 &&
|
||||
worldFolder.getName(worldFolder.getNameCount() - 3).equals(Path.of("dimensions"))
|
||||
worldFolder.getName(worldFolder.getNameCount() - 3).toString().equals("dimensions")
|
||||
) {
|
||||
String namespace = worldFolder.getName(worldFolder.getNameCount() - 2).toString();
|
||||
String value = worldFolder.getName(worldFolder.getNameCount() - 1).toString();
|
||||
|
@ -32,21 +32,15 @@
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.resources.adapter.ResourcesGson;
|
||||
import de.bluecolored.bluemap.core.util.FileHelper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class WebFilesManager {
|
||||
|
||||
@ -114,39 +108,17 @@ public boolean filesNeedUpdate() {
|
||||
}
|
||||
|
||||
public void updateFiles() throws IOException {
|
||||
URL fileResource = getClass().getResource("/de/bluecolored/bluemap/webapp.zip");
|
||||
File tempFile = File.createTempFile("bluemap_webroot_extraction", null);
|
||||
URL zippedWebapp = getClass().getResource("/de/bluecolored/bluemap/webapp.zip");
|
||||
if (zippedWebapp == null) throw new IOException("Failed to open bundled webapp.");
|
||||
|
||||
if (fileResource == null) throw new IOException("Failed to open bundled webapp.");
|
||||
// extract zip to webroot
|
||||
FileHelper.extractZipFile(zippedWebapp, webRoot, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
try {
|
||||
FileUtils.copyURLToFile(fileResource, tempFile, 10000, 10000);
|
||||
try (ZipFile zipFile = new ZipFile(tempFile)){
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
ZipEntry zipEntry = entries.nextElement();
|
||||
if (zipEntry.isDirectory()) {
|
||||
File dir = webRoot.resolve(zipEntry.getName()).toFile();
|
||||
FileUtils.forceMkdir(dir);
|
||||
} else {
|
||||
File target = webRoot.resolve(zipEntry.getName()).toFile();
|
||||
FileUtils.forceMkdirParent(target);
|
||||
FileUtils.copyInputStreamToFile(zipFile.getInputStream(zipEntry), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set version in index.html
|
||||
Path indexFile = webRoot.resolve("index.html");
|
||||
String indexContent = Files.readString(indexFile);
|
||||
indexContent = indexContent.replace("%version%", BlueMap.VERSION);
|
||||
Files.writeString(indexFile, indexContent);
|
||||
|
||||
} finally {
|
||||
if (!tempFile.delete()) {
|
||||
Logger.global.logWarning("Failed to delete file: " + tempFile);
|
||||
}
|
||||
}
|
||||
// set version in index.html
|
||||
Path indexFile = webRoot.resolve("index.html");
|
||||
String indexContent = Files.readString(indexFile);
|
||||
indexContent = indexContent.replace("%version%", BlueMap.VERSION);
|
||||
Files.writeString(indexFile, indexContent);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "unused", "MismatchedQueryAndUpdateOfCollection"})
|
||||
|
@ -40,7 +40,6 @@
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WebAppImpl implements WebApp {
|
||||
private static final Path IMAGE_ROOT_PATH = Path.of("data", "images");
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
@ -88,8 +87,8 @@ public String createImage(BufferedImage image, String path) throws IOException {
|
||||
Path webRoot = getWebRoot().toAbsolutePath();
|
||||
String separator = webRoot.getFileSystem().getSeparator();
|
||||
|
||||
Path imageRootFolder = webRoot.resolve(IMAGE_ROOT_PATH);
|
||||
Path imagePath = imageRootFolder.resolve(Path.of(path.replace("/", separator) + ".png")).toAbsolutePath();
|
||||
Path imageRootFolder = webRoot.resolve("data").resolve("images");
|
||||
Path imagePath = imageRootFolder.resolve(path.replace("/", separator) + ".png").toAbsolutePath();
|
||||
|
||||
FileHelper.createDirectories(imagePath.getParent());
|
||||
Files.deleteIfExists(imagePath);
|
||||
@ -108,7 +107,7 @@ public Map<String, String> availableImages() throws IOException {
|
||||
Path webRoot = getWebRoot().toAbsolutePath();
|
||||
String separator = webRoot.getFileSystem().getSeparator();
|
||||
|
||||
Path imageRootPath = webRoot.resolve("data").resolve(IMAGE_ROOT_PATH).toAbsolutePath();
|
||||
Path imageRootPath = webRoot.resolve("data").resolve("images").toAbsolutePath();
|
||||
|
||||
Map<String, String> availableImagesMap = new HashMap<>();
|
||||
|
||||
|
@ -46,6 +46,13 @@
|
||||
@Getter
|
||||
public class BlueMapConfigManager implements BlueMapConfiguration {
|
||||
|
||||
public static final String CORE_CONFIG_NAME = "core";
|
||||
public static final String WEBSERVER_CONFIG_NAME = "webserver";
|
||||
public static final String WEBAPP_CONFIG_NAME = "webapp";
|
||||
public static final String PLUGIN_CONFIG_NAME = "plugin";
|
||||
public static final String MAPS_CONFIG_FOLDER_NAME = "maps";
|
||||
public static final String STORAGES_CONFIG_FOLDER_NAME = "storages";
|
||||
|
||||
private final ConfigManager configManager;
|
||||
|
||||
private final CoreConfig coreConfig;
|
||||
@ -92,16 +99,15 @@ private BlueMapConfigManager(
|
||||
}
|
||||
|
||||
private CoreConfig loadCoreConfig(Path defaultDataFolder, boolean useMetricsConfig) throws ConfigurationException {
|
||||
Path configFileRaw = Path.of("core");
|
||||
Path configFile = configManager.findConfigPath(configFileRaw);
|
||||
Path configFile = configManager.resolveConfigFile(CORE_CONFIG_NAME);
|
||||
Path configFolder = configFile.getParent();
|
||||
|
||||
if (!Files.exists(configFile)) {
|
||||
try {
|
||||
FileHelper.createDirectories(configFolder);
|
||||
Files.writeString(
|
||||
configFolder.resolve("core.conf"),
|
||||
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/core.conf")
|
||||
configFile,
|
||||
configManager.loadConfigTemplate(CORE_CONFIG_NAME)
|
||||
.setConditional("metrics", useMetricsConfig)
|
||||
.setVariable("timestamp", LocalDateTime.now().withNano(0).toString())
|
||||
.setVariable("version", BlueMap.VERSION)
|
||||
@ -118,7 +124,7 @@ private CoreConfig loadCoreConfig(Path defaultDataFolder, boolean useMetricsConf
|
||||
}
|
||||
}
|
||||
|
||||
return configManager.loadConfig(configFileRaw, CoreConfig.class);
|
||||
return configManager.loadConfig(CORE_CONFIG_NAME, CoreConfig.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,16 +143,15 @@ private int suggestRenderThreadCount() {
|
||||
}
|
||||
|
||||
private WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot) throws ConfigurationException {
|
||||
Path configFileRaw = Path.of("webserver");
|
||||
Path configFile = configManager.findConfigPath(configFileRaw);
|
||||
Path configFile = configManager.resolveConfigFile(WEBSERVER_CONFIG_NAME);
|
||||
Path configFolder = configFile.getParent();
|
||||
|
||||
if (!Files.exists(configFile)) {
|
||||
try {
|
||||
FileHelper.createDirectories(configFolder);
|
||||
Files.writeString(
|
||||
configFolder.resolve("webserver.conf"),
|
||||
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webserver.conf")
|
||||
configFile,
|
||||
configManager.loadConfigTemplate(WEBSERVER_CONFIG_NAME)
|
||||
.setVariable("webroot", formatPath(defaultWebroot))
|
||||
.setVariable("logfile", formatPath(dataRoot.resolve("logs").resolve("webserver.log")))
|
||||
.setVariable("logfile-with-time", formatPath(dataRoot.resolve("logs").resolve("webserver_%1$tF_%1$tT.log")))
|
||||
@ -158,20 +163,19 @@ private WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot)
|
||||
}
|
||||
}
|
||||
|
||||
return configManager.loadConfig(configFileRaw, WebserverConfig.class);
|
||||
return configManager.loadConfig(WEBSERVER_CONFIG_NAME, WebserverConfig.class);
|
||||
}
|
||||
|
||||
private WebappConfig loadWebappConfig(Path defaultWebroot) throws ConfigurationException {
|
||||
Path configFileRaw = Path.of("webapp");
|
||||
Path configFile = configManager.findConfigPath(configFileRaw);
|
||||
Path configFile = configManager.resolveConfigFile(WEBAPP_CONFIG_NAME);
|
||||
Path configFolder = configFile.getParent();
|
||||
|
||||
if (!Files.exists(configFile)) {
|
||||
try {
|
||||
FileHelper.createDirectories(configFolder);
|
||||
Files.writeString(
|
||||
configFolder.resolve("webapp.conf"),
|
||||
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webapp.conf")
|
||||
configFile,
|
||||
configManager.loadConfigTemplate(WEBAPP_CONFIG_NAME)
|
||||
.setVariable("webroot", formatPath(defaultWebroot))
|
||||
.build(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
|
||||
@ -181,20 +185,19 @@ private WebappConfig loadWebappConfig(Path defaultWebroot) throws ConfigurationE
|
||||
}
|
||||
}
|
||||
|
||||
return configManager.loadConfig(configFileRaw, WebappConfig.class);
|
||||
return configManager.loadConfig(WEBAPP_CONFIG_NAME, WebappConfig.class);
|
||||
}
|
||||
|
||||
private PluginConfig loadPluginConfig() throws ConfigurationException {
|
||||
Path configFileRaw = Path.of("plugin");
|
||||
Path configFile = configManager.findConfigPath(configFileRaw);
|
||||
Path configFile = configManager.resolveConfigFile(PLUGIN_CONFIG_NAME);
|
||||
Path configFolder = configFile.getParent();
|
||||
|
||||
if (!Files.exists(configFile)) {
|
||||
try {
|
||||
FileHelper.createDirectories(configFolder);
|
||||
Files.writeString(
|
||||
configFolder.resolve("plugin.conf"),
|
||||
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/plugin.conf")
|
||||
configFile,
|
||||
configManager.loadConfigTemplate(PLUGIN_CONFIG_NAME)
|
||||
.build(),
|
||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
|
||||
);
|
||||
@ -203,14 +206,13 @@ private PluginConfig loadPluginConfig() throws ConfigurationException {
|
||||
}
|
||||
}
|
||||
|
||||
return configManager.loadConfig(configFileRaw, PluginConfig.class);
|
||||
return configManager.loadConfig(PLUGIN_CONFIG_NAME, PluginConfig.class);
|
||||
}
|
||||
|
||||
private Map<String, MapConfig> loadMapConfigs(Collection<ServerWorld> autoConfigWorlds) throws ConfigurationException {
|
||||
Map<String, MapConfig> mapConfigs = new HashMap<>();
|
||||
|
||||
Path mapFolder = Paths.get("maps");
|
||||
Path mapConfigFolder = configManager.getConfigRoot().resolve(mapFolder);
|
||||
Path mapConfigFolder = configManager.getConfigRoot().resolve(MAPS_CONFIG_FOLDER_NAME);
|
||||
|
||||
if (!Files.exists(mapConfigFolder)){
|
||||
try {
|
||||
@ -290,8 +292,7 @@ private Map<String, MapConfig> loadMapConfigs(Collection<ServerWorld> autoConfig
|
||||
try (Stream<Path> configFiles = Files.list(mapConfigFolder)) {
|
||||
for (var configFile : configFiles.toArray(Path[]::new)) {
|
||||
if (!configManager.isConfigFile(configFile)) continue;
|
||||
Path rawConfig = configManager.getRaw(configFile);
|
||||
String id = sanitiseMapId(rawConfig.getFileName().toString());
|
||||
String id = sanitiseMapId(configManager.getConfigName(configFile));
|
||||
|
||||
if (mapConfigs.containsKey(id)) {
|
||||
throw new ConfigurationException("At least two of your map-config file-names result in ambiguous map-id's!\n" +
|
||||
@ -299,7 +300,7 @@ private Map<String, MapConfig> loadMapConfigs(Collection<ServerWorld> autoConfig
|
||||
"To resolve this issue, rename this file to something else.");
|
||||
}
|
||||
|
||||
MapConfig mapConfig = configManager.loadConfig(rawConfig, MapConfig.class);
|
||||
MapConfig mapConfig = configManager.loadConfig(configFile, MapConfig.class);
|
||||
mapConfigs.put(id, mapConfig);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@ -315,8 +316,7 @@ private Map<String, MapConfig> loadMapConfigs(Collection<ServerWorld> autoConfig
|
||||
private Map<String, StorageConfig> loadStorageConfigs(Path defaultWebroot) throws ConfigurationException {
|
||||
Map<String, StorageConfig> storageConfigs = new HashMap<>();
|
||||
|
||||
Path storageFolder = Paths.get("storages");
|
||||
Path storageConfigFolder = configManager.getConfigRoot().resolve(storageFolder);
|
||||
Path storageConfigFolder = configManager.getConfigRoot().resolve(STORAGES_CONFIG_FOLDER_NAME);
|
||||
|
||||
if (!Files.exists(storageConfigFolder)){
|
||||
try {
|
||||
@ -345,11 +345,10 @@ private Map<String, StorageConfig> loadStorageConfigs(Path defaultWebroot) throw
|
||||
try (Stream<Path> configFiles = Files.list(storageConfigFolder)) {
|
||||
for (var configFile : configFiles.toArray(Path[]::new)) {
|
||||
if (!configManager.isConfigFile(configFile)) continue;
|
||||
Path rawConfig = configManager.getRaw(configFile);
|
||||
String id = rawConfig.getFileName().toString();
|
||||
String id = configManager.getConfigName(configFile);
|
||||
|
||||
StorageConfig storageConfig = configManager.loadConfig(rawConfig, StorageConfig.Base.class); // load superclass
|
||||
storageConfig = configManager.loadConfig(rawConfig, storageConfig.getStorageType().getConfigType()); // load actual config type
|
||||
StorageConfig storageConfig = configManager.loadConfig(configFile, StorageConfig.Base.class); // load superclass
|
||||
storageConfig = configManager.loadConfig(configFile, storageConfig.getStorageType().getConfigType()); // load actual config type
|
||||
|
||||
storageConfigs.put(id, storageConfig);
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package de.bluecolored.bluemap.common.config;
|
||||
|
||||
import de.bluecolored.bluemap.core.util.Key;
|
||||
import de.bluecolored.bluemap.core.util.Keyed;
|
||||
import de.bluecolored.bluemap.core.util.Registry;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
|
||||
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
|
||||
import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface ConfigLoader extends Keyed {
|
||||
|
||||
ConfigLoader HOCON = new Impl(Key.bluemap("hocon"), ".conf", HoconConfigurationLoader::builder);
|
||||
ConfigLoader JSON = new Impl(Key.bluemap("json"), ".json", GsonConfigurationLoader::builder);
|
||||
|
||||
ConfigLoader DEFAULT = HOCON;
|
||||
|
||||
Registry<ConfigLoader> REGISTRY = new Registry<>(
|
||||
HOCON,
|
||||
JSON
|
||||
);
|
||||
|
||||
String getFileSuffix();
|
||||
|
||||
AbstractConfigurationLoader.Builder<?, ?> createLoaderBuilder();
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
class Impl implements ConfigLoader {
|
||||
|
||||
private final Key key;
|
||||
private final String fileSuffix;
|
||||
private final Supplier<AbstractConfigurationLoader.Builder<?, ?>> builderSupplier;
|
||||
|
||||
@Override
|
||||
public AbstractConfigurationLoader.Builder<?, ?> createLoaderBuilder() {
|
||||
return builderSupplier.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -32,8 +32,6 @@
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
|
||||
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
|
||||
import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
|
||||
import org.spongepowered.configurate.loader.ConfigurationLoader;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
@ -43,14 +41,11 @@
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private static final String[] CONFIG_FILE_ENDINGS = new String[] {
|
||||
".conf",
|
||||
".json"
|
||||
};
|
||||
private static final String CONFIG_TEMPLATE_RESOURCE_PATH = "/de/bluecolored/bluemap/config/";
|
||||
|
||||
private final Path configRoot;
|
||||
|
||||
@ -58,32 +53,63 @@ public ConfigManager(Path configRoot) {
|
||||
this.configRoot = configRoot;
|
||||
}
|
||||
|
||||
public <T> T loadConfig(Path rawPath, Class<T> type) throws ConfigurationException {
|
||||
Path path = findConfigPath(rawPath);
|
||||
ConfigurationNode configNode = loadConfigFile(path);
|
||||
public <T> T loadConfig(String name, Class<T> type) throws ConfigurationException {
|
||||
Path file = resolveConfigFile(name);
|
||||
return loadConfig(file, type);
|
||||
}
|
||||
|
||||
public <T> T loadConfig(Path file, Class<T> type) throws ConfigurationException {
|
||||
ConfigurationNode configNode = loadConfigFile(file);
|
||||
try {
|
||||
return Objects.requireNonNull(configNode.get(type));
|
||||
} catch (SerializationException | NullPointerException ex) {
|
||||
throw new ConfigurationException(
|
||||
"BlueMap failed to parse this file:\n" +
|
||||
path + "\n" +
|
||||
file + "\n" +
|
||||
"Check if the file is correctly formatted and all values are correct!",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigurationNode loadConfig(Path rawPath) throws ConfigurationException {
|
||||
Path path = findConfigPath(rawPath);
|
||||
return loadConfigFile(path);
|
||||
}
|
||||
|
||||
public ConfigTemplate loadConfigTemplate(String resource) throws IOException {
|
||||
public ConfigTemplate loadConfigTemplate(String name) throws IOException {
|
||||
String resource = CONFIG_TEMPLATE_RESOURCE_PATH + name + ConfigLoader.DEFAULT.getFileSuffix();
|
||||
InputStream in = BlueMap.class.getResourceAsStream(resource);
|
||||
if (in == null) throw new IOException("Resource not found: " + resource);
|
||||
String configTemplate = IOUtils.toString(in, StandardCharsets.UTF_8);
|
||||
return new ConfigTemplate(configTemplate);
|
||||
}
|
||||
|
||||
public Path resolveConfigFile(String name) {
|
||||
for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values()) {
|
||||
Path path = configRoot.resolve(name + configLoader.getFileSuffix());
|
||||
if (Files.isRegularFile(path)) return path;
|
||||
}
|
||||
|
||||
return configRoot.resolve(name + ConfigLoader.DEFAULT.getFileSuffix());
|
||||
}
|
||||
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isConfigFile(Path file) {
|
||||
String fileName = file.getFileName().toString();
|
||||
for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values())
|
||||
if (fileName.endsWith(configLoader.getFileSuffix())) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getConfigName(Path file) {
|
||||
String fileName = file.getFileName().toString();
|
||||
for (ConfigLoader configLoader : ConfigLoader.REGISTRY.values()) {
|
||||
String suffix = configLoader.getFileSuffix();
|
||||
if (fileName.endsWith(suffix))
|
||||
return fileName.substring(0, fileName.length() - suffix.length());
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public Path getConfigRoot() {
|
||||
return configRoot;
|
||||
}
|
||||
|
||||
private ConfigurationNode loadConfigFile(Path path) throws ConfigurationException {
|
||||
if (!Files.exists(path)) {
|
||||
throw new ConfigurationException(
|
||||
@ -110,58 +136,17 @@ private ConfigurationNode loadConfigFile(Path path) throws ConfigurationExceptio
|
||||
}
|
||||
}
|
||||
|
||||
public Path getConfigRoot() {
|
||||
return configRoot;
|
||||
}
|
||||
|
||||
public Path findConfigPath(Path rawPath) {
|
||||
if (!rawPath.startsWith(configRoot))
|
||||
rawPath = configRoot.resolve(rawPath);
|
||||
|
||||
for (String fileEnding : CONFIG_FILE_ENDINGS) {
|
||||
if (rawPath.getFileName().endsWith(fileEnding)) return rawPath;
|
||||
}
|
||||
|
||||
for (String fileEnding : CONFIG_FILE_ENDINGS) {
|
||||
Path path = rawPath.getParent().resolve(rawPath.getFileName() + fileEnding);
|
||||
if (Files.exists(path)) return path;
|
||||
}
|
||||
|
||||
return rawPath.getParent().resolve(rawPath.getFileName() + CONFIG_FILE_ENDINGS[0]);
|
||||
}
|
||||
|
||||
public boolean isConfigFile(Path path) {
|
||||
if (!Files.isRegularFile(path)) return false;
|
||||
|
||||
String fileName = path.getFileName().toString();
|
||||
for (String fileEnding : CONFIG_FILE_ENDINGS) {
|
||||
if (fileName.endsWith(fileEnding)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Path getRaw(Path path) {
|
||||
String fileName = path.getFileName().toString();
|
||||
String rawName = null;
|
||||
|
||||
for (String fileEnding : CONFIG_FILE_ENDINGS) {
|
||||
if (fileName.endsWith(fileEnding)) {
|
||||
rawName = fileName.substring(0, fileName.length() - fileEnding.length());
|
||||
private ConfigurationLoader<? extends ConfigurationNode> getLoader(Path path){
|
||||
AbstractConfigurationLoader.Builder<?, ?> builder = null;
|
||||
for (ConfigLoader loader : ConfigLoader.REGISTRY.values()) {
|
||||
if (path.getFileName().endsWith(loader.getFileSuffix())) {
|
||||
builder = loader.createLoaderBuilder();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rawName == null) return path;
|
||||
return path.getParent().resolve(rawName);
|
||||
}
|
||||
|
||||
private ConfigurationLoader<? extends ConfigurationNode> getLoader(Path path){
|
||||
AbstractConfigurationLoader.Builder<?, ?> builder;
|
||||
if (path.getFileName().endsWith(".json"))
|
||||
builder = GsonConfigurationLoader.builder();
|
||||
else
|
||||
builder = HoconConfigurationLoader.builder();
|
||||
if (builder == null)
|
||||
builder = ConfigLoader.DEFAULT.createLoaderBuilder();
|
||||
|
||||
return builder
|
||||
.path(path)
|
||||
|
@ -167,7 +167,7 @@ private void load(@Nullable ResourcePack preloadedResourcePack) throws IOExcepti
|
||||
|
||||
BlueMapConfiguration configProvider = blueMap.getConfig();
|
||||
if (configProvider instanceof BlueMapConfigManager) {
|
||||
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
|
||||
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().resolveConfigFile(BlueMapConfigManager.CORE_CONFIG_NAME).toAbsolutePath().normalize());
|
||||
}
|
||||
|
||||
Logger.global.logInfo("If you have changed the config you can simply reload the plugin using: /bluemap reload");
|
||||
|
@ -25,14 +25,15 @@
|
||||
package de.bluecolored.bluemap.common.web;
|
||||
|
||||
import de.bluecolored.bluemap.common.web.http.*;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Calendar;
|
||||
@ -54,10 +55,16 @@ public FileRequestHandler(Path webRoot) {
|
||||
public HttpResponse handle(HttpRequest request) {
|
||||
if (!request.getMethod().equalsIgnoreCase("GET"))
|
||||
return new HttpResponse(HttpStatusCode.BAD_REQUEST);
|
||||
return generateResponse(request);
|
||||
|
||||
try {
|
||||
return generateResponse(request);
|
||||
} catch (IOException e) {
|
||||
Logger.global.logError("Failed to serve file", e);
|
||||
return new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpResponse generateResponse(HttpRequest request) {
|
||||
private HttpResponse generateResponse(HttpRequest request) throws IOException {
|
||||
String path = request.getPath();
|
||||
|
||||
// normalize path
|
||||
@ -76,36 +83,34 @@ private HttpResponse generateResponse(HttpRequest request) {
|
||||
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
||||
}
|
||||
|
||||
File file = filePath.toFile();
|
||||
|
||||
// redirect to have correct relative paths
|
||||
if (file.isDirectory() && !request.getPath().endsWith("/")) {
|
||||
if (Files.isDirectory(filePath) && !request.getPath().endsWith("/")) {
|
||||
HttpResponse response = new HttpResponse(HttpStatusCode.SEE_OTHER);
|
||||
response.addHeader("Location", "/" + path + "/" + (request.getGETParamString().isEmpty() ? "" : "?" + request.getGETParamString()));
|
||||
return response;
|
||||
}
|
||||
|
||||
// default to index.html
|
||||
if (!file.exists() || file.isDirectory()){
|
||||
file = new File(filePath + "/index.html");
|
||||
if (!Files.exists(filePath) || Files.isDirectory(filePath)){
|
||||
filePath = filePath.resolve("/index.html");
|
||||
}
|
||||
|
||||
if (!file.exists() || file.isDirectory()) {
|
||||
if (!Files.exists(filePath) || Files.isDirectory(filePath)){
|
||||
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
||||
}
|
||||
|
||||
// don't send php files
|
||||
if (file.getName().endsWith(".php")) {
|
||||
if (filePath.getFileName().toString().endsWith(".php")) {
|
||||
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
||||
}
|
||||
|
||||
// check if file is still in web-root and is not a directory
|
||||
if (!file.toPath().normalize().startsWith(webRoot) || file.isDirectory()){
|
||||
if (!filePath.normalize().startsWith(webRoot) || Files.isDirectory(filePath)){
|
||||
return new HttpResponse(HttpStatusCode.FORBIDDEN);
|
||||
}
|
||||
|
||||
// check modified
|
||||
long lastModified = file.lastModified();
|
||||
long lastModified = Files.getLastModifiedTime(filePath).to(TimeUnit.MILLISECONDS);
|
||||
HttpHeader modHeader = request.getHeader("If-Modified-Since");
|
||||
if (modHeader != null){
|
||||
try {
|
||||
@ -117,7 +122,10 @@ private HttpResponse generateResponse(HttpRequest request) {
|
||||
}
|
||||
|
||||
//check ETag
|
||||
String eTag = Long.toHexString(file.length()) + Integer.toHexString(file.hashCode()) + Long.toHexString(lastModified);
|
||||
String eTag =
|
||||
Long.toHexString(Files.size(filePath)) +
|
||||
Integer.toHexString(filePath.hashCode()) +
|
||||
Long.toHexString(lastModified);
|
||||
HttpHeader etagHeader = request.getHeader("If-None-Match");
|
||||
if (etagHeader != null){
|
||||
if(etagHeader.getValue().equals(eTag)) {
|
||||
@ -133,7 +141,7 @@ private HttpResponse generateResponse(HttpRequest request) {
|
||||
response.addHeader("Cache-Control", "max-age=" + TimeUnit.DAYS.toSeconds(1));
|
||||
|
||||
//add content type header
|
||||
String filetype = file.getName();
|
||||
String filetype = filePath.getFileName().toString();
|
||||
int pointIndex = filetype.lastIndexOf('.');
|
||||
if (pointIndex >= 0) filetype = filetype.substring(pointIndex + 1);
|
||||
String contentType = toContentType(filetype);
|
||||
@ -141,7 +149,7 @@ private HttpResponse generateResponse(HttpRequest request) {
|
||||
|
||||
//send response
|
||||
try {
|
||||
response.setData(new FileInputStream(file));
|
||||
response.setData(Files.newInputStream(filePath));
|
||||
return response;
|
||||
} catch (FileNotFoundException e) {
|
||||
return new HttpResponse(HttpStatusCode.NOT_FOUND);
|
||||
@ -155,21 +163,21 @@ private static String timestampToString(long time){
|
||||
private static long stringToTimestamp(String timeString) throws IllegalArgumentException {
|
||||
try {
|
||||
int day = Integer.parseInt(timeString.substring(5, 7));
|
||||
|
||||
int month = Calendar.JANUARY;
|
||||
switch (timeString.substring(8, 11)){
|
||||
case "Feb" : month = Calendar.FEBRUARY; break;
|
||||
case "Mar" : month = Calendar.MARCH; break;
|
||||
case "Apr" : month = Calendar.APRIL; break;
|
||||
case "May" : month = Calendar.MAY; break;
|
||||
case "Jun" : month = Calendar.JUNE; break;
|
||||
case "Jul" : month = Calendar.JULY; break;
|
||||
case "Aug" : month = Calendar.AUGUST; break;
|
||||
case "Sep" : month = Calendar.SEPTEMBER; break;
|
||||
case "Oct" : month = Calendar.OCTOBER; break;
|
||||
case "Nov" : month = Calendar.NOVEMBER; break;
|
||||
case "Dec" : month = Calendar.DECEMBER; break;
|
||||
}
|
||||
int month = switch (timeString.substring(8, 11)) {
|
||||
case "Jan" -> Calendar.JANUARY;
|
||||
case "Feb" -> Calendar.FEBRUARY;
|
||||
case "Mar" -> Calendar.MARCH;
|
||||
case "Apr" -> Calendar.APRIL;
|
||||
case "May" -> Calendar.MAY;
|
||||
case "Jun" -> Calendar.JUNE;
|
||||
case "Jul" -> Calendar.JULY;
|
||||
case "Aug" -> Calendar.AUGUST;
|
||||
case "Sep" -> Calendar.SEPTEMBER;
|
||||
case "Oct" -> Calendar.OCTOBER;
|
||||
case "Nov" -> Calendar.NOVEMBER;
|
||||
case "Dec" -> Calendar.DECEMBER;
|
||||
default -> throw new IllegalArgumentException("Invalid timestamp format");
|
||||
};
|
||||
int year = Integer.parseInt(timeString.substring(12, 16));
|
||||
int hour = Integer.parseInt(timeString.substring(17, 19));
|
||||
int min = Integer.parseInt(timeString.substring(20, 22));
|
||||
@ -183,38 +191,21 @@ private static long stringToTimestamp(String timeString) throws IllegalArgumentE
|
||||
}
|
||||
|
||||
private static String toContentType(String fileEnding) {
|
||||
String contentType = "text/plain";
|
||||
switch (fileEnding) {
|
||||
case "json" :
|
||||
contentType = "application/json";
|
||||
break;
|
||||
case "png" :
|
||||
contentType = "image/png";
|
||||
break;
|
||||
case "jpg" :
|
||||
case "jpeg" :
|
||||
case "jpe" :
|
||||
contentType = "image/jpeg";
|
||||
break;
|
||||
case "svg" :
|
||||
contentType = "image/svg+xml";
|
||||
break;
|
||||
case "css" :
|
||||
contentType = "text/css";
|
||||
break;
|
||||
case "js" :
|
||||
contentType = "text/javascript";
|
||||
break;
|
||||
case "html" :
|
||||
case "htm" :
|
||||
case "shtml" :
|
||||
contentType = "text/html";
|
||||
break;
|
||||
case "xml" :
|
||||
contentType = "text/xml";
|
||||
break;
|
||||
}
|
||||
return contentType;
|
||||
return switch (fileEnding) {
|
||||
case "json" -> "application/json";
|
||||
case "png" -> "image/png";
|
||||
case "jpg",
|
||||
"jpeg",
|
||||
"jpe" -> "image/jpeg";
|
||||
case "svg" -> "image/svg+xml";
|
||||
case "css" -> "text/css";
|
||||
case "js" -> "text/javascript";
|
||||
case "html",
|
||||
"htm",
|
||||
"shtml" -> "text/html";
|
||||
case "xml" -> "text/xml";
|
||||
default -> "text/plain";
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package de.bluecolored.bluemap.core.util;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public class CopyingPathVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
private final Path targetPath;
|
||||
private final CopyOption[] options;
|
||||
|
||||
@Nullable private Path sourcePath;
|
||||
|
||||
public CopyingPathVisitor(Path target, CopyOption... options) {
|
||||
this.targetPath = target;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public CopyingPathVisitor(@Nullable Path source, Path target, CopyOption... options) {
|
||||
this.sourcePath = source;
|
||||
this.targetPath = target;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path source, BasicFileAttributes attributes) throws IOException {
|
||||
// the first directory we visit will be the sourcePath
|
||||
if (sourcePath == null) sourcePath = source;
|
||||
|
||||
Path target = resolveTarget(source);
|
||||
if (Files.notExists(target)) Files.createDirectory(target);
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path source, BasicFileAttributes attributes) throws IOException {
|
||||
Path target = resolveTarget(source);
|
||||
Files.copy(source, target, options);
|
||||
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the target file or directory using Path#toString() to make it compatible across different file-systems
|
||||
*/
|
||||
private Path resolveTarget(Path source) {
|
||||
if (sourcePath == null) return targetPath;
|
||||
return targetPath.resolve(sourcePath.relativize(source).toString());
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,9 @@
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
|
||||
@ -46,14 +48,14 @@ public static OutputStream createFilepartOutputStream(final Path file) throws IO
|
||||
return new OnCloseOutputStream(os, () -> {
|
||||
if (!Files.exists(partFile)) return;
|
||||
FileHelper.createDirectories(folder);
|
||||
FileHelper.move(partFile, file);
|
||||
FileHelper.atomicMove(partFile, file);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to move the file atomically, but fallbacks to a normal move operation if moving atomically fails
|
||||
*/
|
||||
public static void move(Path from, Path to) throws IOException {
|
||||
public static void atomicMove(Path from, Path to) throws IOException {
|
||||
try {
|
||||
Files.move(from, to, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (FileNotFoundException | NoSuchFileException ignore) {
|
||||
@ -77,4 +79,39 @@ public static Path createDirectories(Path dir, FileAttribute<?>... attrs) throws
|
||||
return Files.createDirectories(dir, attrs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the entire zip-file into the given target directory
|
||||
*/
|
||||
public static void extractZipFile(URL zipFile, Path targetDirectory, CopyOption... options) throws IOException {
|
||||
Path temp = Files.createTempFile(null, ".zip");
|
||||
FileHelper.copy(zipFile, temp);
|
||||
FileHelper.extractZipFile(temp, targetDirectory, options);
|
||||
Files.deleteIfExists(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the entire zip-file into the given target directory
|
||||
*/
|
||||
public static void extractZipFile(Path zipFile, Path targetDirectory, CopyOption... options) throws IOException {
|
||||
try (FileSystem webappZipFs = FileSystems.newFileSystem(zipFile, (ClassLoader) null)) {
|
||||
CopyingPathVisitor copyAction = new CopyingPathVisitor(targetDirectory, options);
|
||||
for (Path root : webappZipFs.getRootDirectories()) {
|
||||
Files.walkFileTree(root, copyAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies from a URL to a target-path
|
||||
*/
|
||||
public static void copy(URL source, Path target) throws IOException {
|
||||
try (
|
||||
InputStream in = source.openStream();
|
||||
OutputStream out = Files.newOutputStream(target)
|
||||
) {
|
||||
in.transferTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,17 +45,16 @@
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@ -162,25 +161,33 @@ private Region getRegion(Vector2i pos) {
|
||||
|
||||
@Override
|
||||
public Collection<Vector2i> listRegions() {
|
||||
File[] regionFiles = getRegionFolder().toFile().listFiles();
|
||||
if (regionFiles == null) return Collections.emptyList();
|
||||
try (Stream<Path> stream = Files.list(regionFolder)) {
|
||||
return stream
|
||||
.map(file -> {
|
||||
try {
|
||||
String fileName = file.getFileName().toString();
|
||||
|
||||
List<Vector2i> regions = new ArrayList<>(regionFiles.length);
|
||||
if (RegionType.forFileName(fileName) == null) return null;
|
||||
if (Files.size(file) <= 0) return null;
|
||||
|
||||
for (File file : regionFiles) {
|
||||
if (RegionType.forFileName(file.getName()) == null) continue;
|
||||
if (file.length() <= 0) continue;
|
||||
String[] filenameParts = fileName.split("\\.");
|
||||
int rX = Integer.parseInt(filenameParts[1]);
|
||||
int rZ = Integer.parseInt(filenameParts[2]);
|
||||
|
||||
try {
|
||||
String[] filenameParts = file.getName().split("\\.");
|
||||
int rX = Integer.parseInt(filenameParts[1]);
|
||||
int rZ = Integer.parseInt(filenameParts[2]);
|
||||
|
||||
regions.add(new Vector2i(rX, rZ));
|
||||
} catch (NumberFormatException ignore) {}
|
||||
return new Vector2i(rX, rZ);
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to read region-file: " + file, ex);
|
||||
return null;
|
||||
} catch (NumberFormatException ignore) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to list regions for world: '" + getId() + "'", ex);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,11 +48,11 @@
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.BindException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
@ -363,7 +363,7 @@ public static void main(String[] args) {
|
||||
if (blueMap != null) {
|
||||
BlueMapConfiguration configProvider = blueMap.getConfig();
|
||||
if (configProvider instanceof BlueMapConfigManager) {
|
||||
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().findConfigPath(Path.of("core")).toAbsolutePath().normalize());
|
||||
Logger.global.logWarning("Please check: " + ((BlueMapConfigManager) configProvider).getConfigManager().resolveConfigFile(BlueMapConfigManager.CORE_CONFIG_NAME).toAbsolutePath().normalize());
|
||||
}
|
||||
}
|
||||
System.exit(2);
|
||||
@ -461,19 +461,20 @@ private static void printHelp() {
|
||||
private static String getCliCommand() {
|
||||
String filename = "bluemap-cli.jar";
|
||||
try {
|
||||
File file = new File(BlueMapCLI.class.getProtectionDomain()
|
||||
Path file = Path.of(BlueMapCLI.class.getProtectionDomain()
|
||||
.getCodeSource()
|
||||
.getLocation()
|
||||
.getPath());
|
||||
.toURI());
|
||||
|
||||
if (file.isFile()) {
|
||||
if (Files.isRegularFile(file)) {
|
||||
try {
|
||||
filename = "." + File.separator + new File("").getCanonicalFile().toPath().relativize(file.toPath());
|
||||
filename = "." + file.getFileSystem().getSeparator() +
|
||||
Path.of("").toRealPath().relativize(file.toRealPath());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
filename = file.getAbsolutePath();
|
||||
filename = file.toAbsolutePath().toString();
|
||||
}
|
||||
}
|
||||
} catch (IOException ignore) {}
|
||||
} catch (Exception ignore) {}
|
||||
return "java -jar " + filename;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user