Remove all usages of java.io.File and bad usages of Path.of()

This commit is contained in:
Lukas Rieger (Blue) 2024-05-21 16:32:28 +02:00
parent ce25eb52e3
commit d7dd8931a5
No known key found for this signature in database
GPG Key ID: AA33883B1BBA03E6
12 changed files with 346 additions and 232 deletions

View File

@ -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();

View File

@ -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"})

View File

@ -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<>();

View File

@ -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);
}

View File

@ -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();
}
}
}

View File

@ -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)

View File

@ -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");

View File

@ -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";
};
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;
}