package io.gitlab.jfronny.glaunch.util; import io.gitlab.jfronny.glaunch.GLaunch; import java.io.*; import java.net.URL; 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 = new URL(url).openStream()) { 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, () -> downloadString(url), 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 = GLaunch.CACHE_DIR.resolve(Integer.toString(url.hashCode())); try { String download = sourceString.get(); Files.writeString(cache, download); return GLaunch.GSON.fromJson(download, type); } catch (IOException e) { if (Files.exists(cache)) { GLaunch.LOGGER.info("Using cache for " + url, e); try (BufferedReader br = Files.newBufferedReader(cache)) { return GLaunch.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 GLaunch.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)) { GLaunch.GSON.toJson(object, bw); } } private static String downloadString(String url) throws IOException { try (InputStream is = new URL(url).openStream(); Reader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr)) { StringBuilder text = new StringBuilder(); String line; while ((line = br.readLine()) != null) text.append('\n').append(line); return text.substring(1); } } 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; } }); } }