276 lines
12 KiB
Java
276 lines
12 KiB
Java
package io.gitlab.jfronny.inceptum.util;
|
|
|
|
import io.gitlab.jfronny.commons.*;
|
|
import io.gitlab.jfronny.commons.io.MultiAccessFileSystem;
|
|
import io.gitlab.jfronny.commons.log.Logger;
|
|
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
|
|
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
|
|
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
|
|
import io.gitlab.jfronny.inceptum.util.cache.GsonFileCache;
|
|
|
|
import java.awt.*;
|
|
import java.io.*;
|
|
import java.lang.reflect.Type;
|
|
import java.net.*;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.*;
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
|
import java.util.*;
|
|
import java.util.List;
|
|
import java.util.function.Predicate;
|
|
import java.util.regex.Pattern;
|
|
import java.util.stream.Stream;
|
|
|
|
public class Utils {
|
|
public static final Pattern VALID_FILENAME = Pattern.compile("[a-zA-Z0-9_\\-.][a-zA-Z0-9 _\\-.]*[a-zA-Z0-9_\\-.]");
|
|
public static final Logger LOGGER = Logger.forName("Inceptum");
|
|
private static ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
|
|
private static final GsonFileCache OBJECT_CACHE = new GsonFileCache(MetaHolder.CACHE_DIR);
|
|
|
|
public static byte[] downloadData(String url) throws IOException, URISyntaxException {
|
|
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
|
|
return is.readAllBytes();
|
|
}
|
|
}
|
|
|
|
public static byte[] downloadData(String url, String sha1) throws IOException, URISyntaxException {
|
|
byte[] buf = downloadData(url);
|
|
if (sha1 == null) return buf;
|
|
if (!HashUtils.sha1(buf).equals(sha1)) throw new IOException("Invalid hash");
|
|
return buf;
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, Class<T> type) throws IOException {
|
|
return downloadObject(url, type, true);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, Class<T> type, boolean cache) throws IOException {
|
|
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, Type type) throws IOException {
|
|
return downloadObject(url, type, true);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, Type type, String apiKey) throws IOException {
|
|
return downloadObject(url, () -> HttpUtils.get(url).header("x-api-key", apiKey).sendString(), type, true);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, Type type, boolean cache) throws IOException {
|
|
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, String sha1, Class<T> type) throws IOException {
|
|
return downloadObject(url, sha1, type, true);
|
|
}
|
|
|
|
public static <T> T downloadObject(String url, String sha1, Class<T> type, boolean cache) throws IOException {
|
|
return downloadObject(url, () -> downloadString(url, sha1), type, cache);
|
|
}
|
|
|
|
private static <T> T downloadObject(String url, ThrowingSupplier<String, Exception> sourceString, Type type, boolean cache) throws IOException {
|
|
try {
|
|
ThrowingSupplier<T, Exception> builder = () -> GsonHolder.getGson().fromJson(sourceString.get(), type);
|
|
return cache ? OBJECT_CACHE.get(HashUtils.sha1(url.getBytes(StandardCharsets.UTF_8)), builder, type) : builder.get();
|
|
} catch (Exception e) {
|
|
throw new IOException("Could not download object and no cache exists", e);
|
|
}
|
|
}
|
|
|
|
public static String buildUrl(String host, String url, Map<String, String> params) {
|
|
StringBuilder res = new StringBuilder(host);
|
|
if (res.toString().endsWith("/")) res = new StringBuilder(res.substring(0, res.length() - 1));
|
|
if (url.startsWith("/")) res.append(url);
|
|
else res.append("/").append(url);
|
|
int i = 0;
|
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
|
res.append(i++ == 0 ? '?' : '&')
|
|
.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
|
|
.append('=')
|
|
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
|
|
}
|
|
return res.toString();
|
|
}
|
|
|
|
public static <T> T loadObject(Path file, Class<T> type) throws IOException {
|
|
try (BufferedReader br = Files.newBufferedReader(file)) {
|
|
return GsonHolder.getGson().fromJson(br, type);
|
|
}
|
|
}
|
|
|
|
public static <T> T loadObject(Path file, Type type) throws IOException {
|
|
try (BufferedReader br = Files.newBufferedReader(file)) {
|
|
return GsonHolder.getGson().fromJson(br, type);
|
|
}
|
|
}
|
|
|
|
public static <T> void writeObject(Path file, T object) throws IOException {
|
|
try (BufferedWriter bw = Files.newBufferedWriter(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
|
GsonHolder.getGson().toJson(object, bw);
|
|
}
|
|
}
|
|
|
|
public static String downloadString(String url, String sha1) throws IOException, URISyntaxException {
|
|
return new String(downloadData(url, sha1), StandardCharsets.UTF_8);
|
|
}
|
|
|
|
public static void downloadFile(String url, Path path) throws IOException, URISyntaxException {
|
|
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
|
|
Files.write(path, downloadData(url));
|
|
}
|
|
|
|
public static void downloadFile(String url, String sha1, Path path) throws IOException, URISyntaxException {
|
|
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
|
|
Files.write(path, downloadData(url, sha1));
|
|
}
|
|
|
|
public static void clearDirectory(Path path) throws IOException {
|
|
clearDirectory(path, p -> true);
|
|
}
|
|
|
|
public static void clearDirectory(Path path, Predicate<Path> shouldDelete) throws IOException {
|
|
if (!Files.exists(path)) return;
|
|
try {
|
|
Utils.ls(path, p -> {
|
|
if (Files.isDirectory(p)) {
|
|
try {
|
|
if (shouldDelete.test(p))
|
|
deleteRecursive(p, shouldDelete);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
if (shouldDelete.test(p))
|
|
Files.delete(p);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
});
|
|
} catch (Throwable t) {
|
|
throw new IOException("Could not clear directory", t);
|
|
}
|
|
}
|
|
|
|
public static void deleteRecursive(Path path) throws IOException {
|
|
deleteRecursive(path, p -> true);
|
|
}
|
|
|
|
public static void deleteRecursive(Path path, Predicate<Path> shouldDelete) throws IOException {
|
|
if (Files.isDirectory(path)) {
|
|
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;
|
|
if (shouldDelete.test(file))
|
|
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;
|
|
if (shouldDelete.test(dir) && ls(dir).isEmpty()) {
|
|
Files.delete(dir);
|
|
}
|
|
return FileVisitResult.CONTINUE;
|
|
}
|
|
});
|
|
}
|
|
else Files.delete(path);
|
|
}
|
|
|
|
public static void copyContent(Path source, Path destination) throws IOException {
|
|
copyContent(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
|
|
}
|
|
|
|
public static void copyContent(Path source, Path destination, CopyOption... copyOptions) throws IOException {
|
|
if (!Files.exists(destination)) Files.createDirectories(destination);
|
|
if (Files.isDirectory(source)) {
|
|
try (Stream<Path> paths = Files.walk(source)) {
|
|
for (Path path : paths.toList()) {
|
|
if (source.equals(path)) continue;
|
|
Path d = destination.resolve(source.relativize(path).toString());
|
|
if (Files.exists(d)) continue;
|
|
if (Files.isDirectory(d)) Files.createDirectories(d);
|
|
else Files.copy(path, d);
|
|
}
|
|
}
|
|
} 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());
|
|
}
|
|
}
|
|
|
|
public static void openWebBrowser(URI uri) {
|
|
try {
|
|
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
|
|
Runtime.getRuntime().exec(new String[]{"xdg-open", uri.toString()});
|
|
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
|
Desktop.getDesktop().browse(uri);
|
|
}
|
|
} catch (Exception e) {
|
|
Utils.LOGGER.error("Error opening web browser!", e);
|
|
}
|
|
}
|
|
|
|
public static void openFile(File file) {
|
|
try {
|
|
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
|
|
Runtime.getRuntime().exec(new String[]{"xdg-open", file.getAbsoluteFile().toString()});
|
|
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
|
Desktop.getDesktop().open(file);
|
|
}
|
|
} catch (Exception e) {
|
|
Utils.LOGGER.error("Error opening web browser!", e);
|
|
}
|
|
}
|
|
|
|
public static List<Path> ls(Path dir) throws IOException {
|
|
try (Stream<Path> sp = Files.list(dir)) {
|
|
return sp.toList();
|
|
}
|
|
}
|
|
|
|
public static String[] lsVi(Path dir) throws IOException {
|
|
try (Stream<Path> sp = Files.list(dir)) {
|
|
return sp.map(p -> Files.isDirectory(p) ? p.getFileName().toString() + "/" : p.getFileName().toString()).toArray(String[]::new);
|
|
}
|
|
}
|
|
|
|
public static List<Path> ls(Path dir, Predicate<Path> predicate) throws IOException {
|
|
try (Stream<Path> sp = Files.list(dir); Stream<Path> fi = sp.filter(predicate)) {
|
|
return fi.toList();
|
|
}
|
|
}
|
|
|
|
public static <TEx extends Exception> void ls(Path dir, ThrowingConsumer<Path, TEx> consumer) throws IOException, TEx {
|
|
try (Stream<Path> sp = Files.list(dir)) {
|
|
for (Path path : sp.toList()) consumer.accept(path);
|
|
}
|
|
}
|
|
|
|
private static final Map<Path, MultiAccessFileSystem> zipFsCache = new HashMap<>();
|
|
public static FileSystem openZipFile(Path zip, boolean create) throws IOException, URISyntaxException {
|
|
synchronized (zipFsCache) {
|
|
if (!zipFsCache.containsKey(zip) || zipFsCache.get(zip).isClosed()) {
|
|
URI fileUri = zip.toUri();
|
|
zipFsCache.put(zip, MultiAccessFileSystem.create(new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null), create ? Map.of("create", "true") : Map.of(), SYSTEM_LOADER));
|
|
}
|
|
return zipFsCache.get(zip).createLens();
|
|
}
|
|
}
|
|
|
|
public static void setSystemLoader(ClassLoader loader) {
|
|
SYSTEM_LOADER = loader;
|
|
}
|
|
}
|