package io.gitlab.jfronny.inceptum.util; import io.gitlab.jfronny.inceptum.Inceptum; import java.awt.*; import java.io.*; import java.lang.reflect.Type; import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Formatter; import java.util.Locale; import java.util.regex.Pattern; 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 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"); } } 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 { try (InputStream is = HttpUtils.get(url).sendInputStream()) { return is.readAllBytes(); } } public static byte[] downloadData(String url, String sha1) throws IOException { byte[] buf = downloadData(url); if (!Utils.hash(buf).equals(sha1)) throw new IOException("Invalid hash"); return buf; } public static T downloadObject(String url, Class type) throws IOException { return downloadObject(url, () -> HttpUtils.get(url).sendString(), type); } public static T downloadObject(String url, String sha1, Class type) throws IOException { return downloadObject(url, () -> downloadString(url, sha1), type); } private static T downloadObject(String url, ThrowingSupplier sourceString, Class type) throws IOException { Path cache = Inceptum.CACHE_DIR.resolve(Integer.toString(url.hashCode())); try { String download = sourceString.get(); Files.writeString(cache, download); return Inceptum.GSON.fromJson(download, type); } catch (IOException e) { if (Files.exists(cache)) { Inceptum.LOGGER.info("Using cache for " + url, e); try (BufferedReader br = Files.newBufferedReader(cache)) { return Inceptum.GSON.fromJson(br, type); } catch (IOException ioE) { throw new IOException("Could not download object and failed loading cache", ioE); } } else throw new IOException("Could not download object and no cache exists", e); } } public static T loadObject(Path file, Class type) throws IOException { try (BufferedReader br = Files.newBufferedReader(file)) { return Inceptum.GSON.fromJson(br, type); } } public static T loadObject(Path file, Type type) throws IOException { try (BufferedReader br = Files.newBufferedReader(file)) { return Inceptum.GSON.fromJson(br, type); } } public static 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); } } 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)); } 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; } }); } 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; } } }