2021-10-29 22:50:42 +02:00
|
|
|
package io.gitlab.jfronny.inceptum.util;
|
2021-10-27 22:00:08 +02:00
|
|
|
|
2021-10-29 22:50:42 +02:00
|
|
|
import io.gitlab.jfronny.inceptum.Inceptum;
|
2021-10-27 22:00:08 +02:00
|
|
|
|
2021-10-29 22:50:42 +02:00
|
|
|
import java.awt.*;
|
2021-10-27 22:00:08 +02:00
|
|
|
import java.io.*;
|
2021-10-29 22:50:42 +02:00
|
|
|
import java.lang.reflect.Type;
|
|
|
|
import java.net.URI;
|
2021-10-27 22:00:08 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2021-10-28 20:19:09 +02:00
|
|
|
import java.nio.file.*;
|
|
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
2021-10-27 22:00:08 +02:00
|
|
|
import java.security.MessageDigest;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
2021-10-30 16:12:39 +02:00
|
|
|
import java.util.Arrays;
|
2021-10-27 22:00:08 +02:00
|
|
|
import java.util.Formatter;
|
|
|
|
import java.util.Locale;
|
2021-10-30 14:22:07 +02:00
|
|
|
import java.util.function.Function;
|
2021-10-28 20:19:09 +02:00
|
|
|
import java.util.regex.Pattern;
|
2021-10-27 22:00:08 +02:00
|
|
|
|
|
|
|
public class Utils {
|
2021-10-28 20:19:09 +02:00
|
|
|
public static final Pattern VALID_FILENAME = Pattern.compile("[a-zA-Z0-9_\\-.][a-zA-Z0-9 _\\-.]*[a-zA-Z0-9_\\-.]");
|
|
|
|
public static final String OS;
|
|
|
|
static {
|
|
|
|
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ROOT);
|
|
|
|
if ((os.contains("mac")) || (os.contains("darwin"))) {
|
|
|
|
OS = "osx";
|
|
|
|
} else if (os.contains("win")) {
|
|
|
|
OS = "windows";
|
|
|
|
} else if (os.contains("nux")) {
|
|
|
|
OS = "linux";
|
|
|
|
} else {
|
|
|
|
throw new RuntimeException("Unrecognized OS");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-27 22:00:08 +02:00
|
|
|
public static String hash(byte[] data) {
|
|
|
|
Formatter formatter = new Formatter();
|
|
|
|
try {
|
|
|
|
for (byte b : MessageDigest.getInstance("SHA-1").digest(data))
|
|
|
|
formatter.format("%02x", b);
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
throw new RuntimeException("Could not hash using SHA1", e);
|
|
|
|
}
|
|
|
|
return formatter.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] downloadData(String url) throws IOException {
|
2021-10-29 22:50:42 +02:00
|
|
|
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
|
2021-10-27 22:00:08 +02:00
|
|
|
return is.readAllBytes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] downloadData(String url, String sha1) throws IOException {
|
|
|
|
byte[] buf = downloadData(url);
|
2021-10-30 14:22:07 +02:00
|
|
|
if (sha1 == null) return buf;
|
2021-10-27 22:00:08 +02:00
|
|
|
if (!Utils.hash(buf).equals(sha1)) throw new IOException("Invalid hash");
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> T downloadObject(String url, Class<T> type) throws IOException {
|
2021-10-30 14:22:07 +02:00
|
|
|
return downloadObject(url, () -> HttpUtils.get(url).sendString(), s -> Inceptum.GSON.fromJson(s, type));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> T downloadObject(String url, Type type) throws IOException {
|
|
|
|
return downloadObject(url, () -> HttpUtils.get(url).sendString(), s -> Inceptum.GSON.fromJson(s, type));
|
2021-10-27 22:00:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> T downloadObject(String url, String sha1, Class<T> type) throws IOException {
|
2021-10-30 14:22:07 +02:00
|
|
|
return downloadObject(url, () -> downloadString(url, sha1), s -> Inceptum.GSON.fromJson(s, type));
|
2021-10-28 21:31:51 +02:00
|
|
|
}
|
|
|
|
|
2021-10-30 14:22:07 +02:00
|
|
|
private static <T> T downloadObject(String url, ThrowingSupplier<String, IOException> sourceString, Function<String, T> builder) throws IOException {
|
2021-10-29 22:50:42 +02:00
|
|
|
Path cache = Inceptum.CACHE_DIR.resolve(Integer.toString(url.hashCode()));
|
2021-10-27 22:00:08 +02:00
|
|
|
try {
|
2021-10-28 21:31:51 +02:00
|
|
|
String download = sourceString.get();
|
2021-10-27 22:00:08 +02:00
|
|
|
Files.writeString(cache, download);
|
2021-10-30 14:22:07 +02:00
|
|
|
return builder.apply(download);
|
2021-10-27 22:00:08 +02:00
|
|
|
} catch (IOException e) {
|
|
|
|
if (Files.exists(cache)) {
|
2021-10-29 22:50:42 +02:00
|
|
|
Inceptum.LOGGER.info("Using cache for " + url, e);
|
2021-10-30 14:22:07 +02:00
|
|
|
return builder.apply(Files.readString(cache));
|
2021-10-27 22:00:08 +02:00
|
|
|
} else
|
|
|
|
throw new IOException("Could not download object and no cache exists", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> T loadObject(Path file, Class<T> type) throws IOException {
|
|
|
|
try (BufferedReader br = Files.newBufferedReader(file)) {
|
2021-10-29 22:50:42 +02:00
|
|
|
return Inceptum.GSON.fromJson(br, type);
|
2021-10-27 22:00:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-29 22:50:42 +02:00
|
|
|
public static <T> T loadObject(Path file, Type type) throws IOException {
|
|
|
|
try (BufferedReader br = Files.newBufferedReader(file)) {
|
|
|
|
return Inceptum.GSON.fromJson(br, type);
|
2021-10-27 22:00:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-29 22:50:42 +02:00
|
|
|
public static <T> void writeObject(Path file, T object) throws IOException {
|
|
|
|
try (BufferedWriter bw = Files.newBufferedWriter(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
|
|
|
Inceptum.GSON.toJson(object, bw);
|
2021-10-27 22:00:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String downloadString(String url, String sha1) throws IOException {
|
|
|
|
return new String(downloadData(url, sha1), StandardCharsets.UTF_8);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void downloadFile(String url, String sha1, Path path) throws IOException {
|
|
|
|
Files.write(path, downloadData(url, sha1));
|
|
|
|
}
|
2021-10-28 20:19:09 +02:00
|
|
|
|
2021-10-30 19:26:59 +02:00
|
|
|
public static void clearDirectory(Path path) throws IOException {
|
|
|
|
if (!Files.exists(path)) return;
|
|
|
|
try {
|
|
|
|
Files.list(path).forEach(p -> {
|
|
|
|
if (Files.isDirectory(p)) {
|
|
|
|
try {
|
|
|
|
deleteRecursive(p);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
try {
|
|
|
|
Files.delete(p);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throw new IOException("Could not clear directory", t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-28 20:19:09 +02:00
|
|
|
public static void deleteRecursive(Path path) throws IOException {
|
|
|
|
Files.walkFileTree(path, new SimpleFileVisitor<>() {
|
|
|
|
@Override
|
|
|
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
|
|
FileVisitResult fv = super.visitFile(file, attrs);
|
|
|
|
if (fv != FileVisitResult.CONTINUE) return fv;
|
|
|
|
Files.delete(file);
|
|
|
|
return FileVisitResult.CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
|
|
|
FileVisitResult fv = super.postVisitDirectory(dir, exc);
|
|
|
|
if (fv != FileVisitResult.CONTINUE) return fv;
|
|
|
|
Files.delete(dir);
|
|
|
|
return FileVisitResult.CONTINUE;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-10-29 22:50:42 +02:00
|
|
|
|
2021-10-30 16:12:39 +02:00
|
|
|
public static void copyRecursive(Path source, Path destination) throws IOException {
|
|
|
|
copyRecursive(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void copyRecursive(Path source, Path destination, CopyOption... copyOptions) throws IOException {
|
|
|
|
if (!Files.exists(destination)) Files.createDirectories(destination);
|
|
|
|
if(Files.isDirectory(source)) {
|
|
|
|
/*Files.walk(source)
|
|
|
|
.forEach(sourcePath -> {
|
|
|
|
try {
|
|
|
|
Path destinationPath = destination.resolve(source.getFileName().toString());
|
|
|
|
Path targetPath = destinationPath.resolve(source.relativize(sourcePath).toString());
|
|
|
|
Files.copy(sourcePath, targetPath, copyOptions);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Inceptum.LOGGER.error("Could not recursively copy", e);
|
|
|
|
}
|
|
|
|
});*/
|
|
|
|
Files.list(source).forEach(sourcePath -> {
|
|
|
|
try {
|
|
|
|
copyRecursive(sourcePath, destination.resolve(sourcePath.getFileName().toString()), copyOptions);
|
|
|
|
} catch (IOException e) {
|
|
|
|
Inceptum.LOGGER.error("Could not recursively copy", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if(Files.exists(source)) {
|
|
|
|
Path target = destination.resolve(source.getFileName().toString());
|
|
|
|
if (!Files.exists(target)
|
|
|
|
|| Arrays.asList(copyOptions).contains(StandardCopyOption.REPLACE_EXISTING))
|
|
|
|
Files.copy(source, target, copyOptions);
|
|
|
|
} else {
|
|
|
|
throw new FileNotFoundException(source.toAbsolutePath().toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-10-29 22:50:42 +02:00
|
|
|
public static void openWebBrowser(URI uri) {
|
|
|
|
try {
|
|
|
|
if (OS.equals("linux") && Utils.executableInPath("xdg-open")) {
|
|
|
|
Runtime.getRuntime().exec("xdg-open " + uri);
|
|
|
|
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
|
|
|
Desktop.getDesktop().browse(uri);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Inceptum.LOGGER.error("Error opening web browser!", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean executableInPath(String executableName) {
|
|
|
|
try {
|
|
|
|
return java.util.stream.Stream
|
|
|
|
.of(System.getenv("PATH").split(java.util.regex.Pattern.quote(File.pathSeparator)))
|
|
|
|
.map(path -> path.replace("\"", "")).map(Paths::get)
|
|
|
|
.anyMatch(path -> Files.exists(path.resolve(executableName))
|
|
|
|
&& Files.isExecutable(path.resolve(executableName)));
|
|
|
|
} catch (Exception e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-10-30 19:26:59 +02:00
|
|
|
|
|
|
|
public static Path getJvmMain(Path jvmDir) {
|
|
|
|
Path f = jvmDir.resolve("bin");
|
|
|
|
Path t = f.resolve("java");
|
|
|
|
if (!Files.exists(t)) t = f.resolve("javaw");
|
|
|
|
if (!Files.exists(t)) t = f.resolve("java.exe");
|
|
|
|
if (!Files.exists(t)) t = f.resolve("javaw.exe");
|
|
|
|
return t;
|
|
|
|
}
|
2021-10-27 22:00:08 +02:00
|
|
|
}
|