From 41dc3b7119aaa83d7fefa00418c30bedb3b1f88c Mon Sep 17 00:00:00 2001 From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com> Date: Wed, 18 Aug 2021 04:32:51 +0200 Subject: [PATCH] installation/removal/updating/running extensions from store --- .../network/executer/ExecutionInfo.java | 1 + .../executer/NormalExtensionRunner.java | 113 ++++++++------ .../extensionstore/repository/StoreFetch.java | 4 +- .../repository/models/StoreExtension.java | 30 ++-- .../tools/StoreExtensionTools.java | 146 ++++++++++++++++-- 5 files changed, 213 insertions(+), 81 deletions(-) diff --git a/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/ExecutionInfo.java b/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/ExecutionInfo.java index f8aa242..6732de1 100644 --- a/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/ExecutionInfo.java +++ b/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/ExecutionInfo.java @@ -21,6 +21,7 @@ public class ExecutionInfo { extensionTypeToExecutionCommand.put("*.py3", new String[]{"python3", "{path}"}); extensionTypeToExecutionCommand.put("*.sh", new String[]{"{path}"}); extensionTypeToExecutionCommand.put("*.exe", new String[]{"{path}"}); + extensionTypeToExecutionCommand.put("*.js", new String[]{"node", "{path}"}); String[] extraArgs = {"-p", "{port}", "-f", "{filename}", "-c", "{cookie}"}; for(String type : extensionTypeToExecutionCommand.keySet()) { diff --git a/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/NormalExtensionRunner.java b/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/NormalExtensionRunner.java index bf91101..3ac1c29 100644 --- a/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/NormalExtensionRunner.java +++ b/G-Earth/src/main/java/gearth/services/extension_handler/extensions/implementations/network/executer/NormalExtensionRunner.java @@ -2,6 +2,7 @@ package gearth.services.extension_handler.extensions.implementations.network.exe import gearth.Main; import gearth.services.extension_handler.extensions.implementations.network.authentication.Authenticator; +import gearth.services.internal_extensions.extensionstore.tools.StoreExtensionTools; import java.io.BufferedReader; import java.io.File; @@ -72,7 +73,7 @@ public class NormalExtensionRunner implements ExtensionRunner { newPath ); - addExecPermission(newPath.toString()); +// addExecPermission(newPath.toString()); tryRunExtension(newPath.toString(), port); } catch (IOException e) { @@ -84,7 +85,15 @@ public class NormalExtensionRunner implements ExtensionRunner { public void tryRunExtension(String path, int port) { try { + if (new File(path).isDirectory()) { + // this extension is installed from the extension store and requires + // different behavior + StoreExtensionTools.executeExtension(path, port); + return; + } + String filename = Paths.get(path).getFileName().toString(); + String[] execCommand = ExecutionInfo.getExecutionCommand(getFileExtension(path)); execCommand = Arrays.copyOf(execCommand, execCommand.length); String cookie = Authenticator.generateCookieForExtension(filename); @@ -99,66 +108,74 @@ public class NormalExtensionRunner implements ExtensionRunner { // Process proc = Runtime.getRuntime().exec(execCommand); Process proc = pb.start(); - if (Main.hasFlag(ExtensionRunner.SHOW_EXTENSIONS_LOG)) { - String sep = "" + System.lineSeparator(); - synchronized (System.out) { - System.out.println(path + sep + "Launching" + sep + "----------" + sep); - } - - BufferedReader stdInput = new BufferedReader(new - InputStreamReader(proc.getInputStream())); - - new Thread(() -> { - try { - String line; - while((line = stdInput.readLine()) != null) { - synchronized (System.out) { - System.out.println(path + sep + "Output" + sep + line + sep + "----------" + sep); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - }).start(); - - BufferedReader stdError = new BufferedReader(new - InputStreamReader(proc.getErrorStream())); - - new Thread(() -> { - try { - String line; - while((line = stdError.readLine()) != null) { - synchronized (System.out) { - System.out.println(path + sep + "Error" + sep + line + sep + "----------" + sep); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - }).start(); - - } + maybeLogExtension(path, proc); } catch (IOException e) { e.printStackTrace(); } } + public static void maybeLogExtension(String path, Process proc) { + if (Main.hasFlag(ExtensionRunner.SHOW_EXTENSIONS_LOG)) { + String sep = "" + System.lineSeparator(); + synchronized (System.out) { + System.out.println(path + sep + "Launching" + sep + "----------" + sep); + } + + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(proc.getInputStream())); + + new Thread(() -> { + try { + String line; + while((line = stdInput.readLine()) != null) { + synchronized (System.out) { + System.out.println(path + sep + "Output" + sep + line + sep + "----------" + sep); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + + BufferedReader stdError = new BufferedReader(new + InputStreamReader(proc.getErrorStream())); + + new Thread(() -> { + try { + String line; + while((line = stdError.readLine()) != null) { + synchronized (System.out) { + System.out.println(path + sep + "Error" + sep + line + sep + "----------" + sep); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + }).start(); + + } + } + @Override public void uninstallExtension(String filename) { try { - Files.delete(Paths.get( - JARPATH, - ExecutionInfo.EXTENSIONSDIRECTORY, - filename - )); + Path path = Paths.get(JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY, filename); + if (new File(path.toString()).isDirectory()) { + // is installed through extension store + StoreExtensionTools.removeExtension(path.toString()); + } + else { + Files.delete(path); + } + } catch (IOException e) { e.printStackTrace(); } } - private void addExecPermission(String path) { - //not needed at first sight - } +// private void addExecPermission(String path) { +// //not needed at first sight +// } private String getFileExtension(String path) { String name = Paths.get(path).getFileName().toString(); diff --git a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/StoreFetch.java b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/StoreFetch.java index f6b73fc..332de50 100644 --- a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/StoreFetch.java +++ b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/StoreFetch.java @@ -1,6 +1,5 @@ package gearth.services.internal_extensions.extensionstore.repository; -import gearth.services.internal_extensions.extensionstore.repository.models.StoreConfig; import gearth.services.internal_extensions.extensionstore.repository.models.StoreData; import org.apache.commons.io.IOUtils; import org.json.JSONArray; @@ -8,7 +7,6 @@ import org.json.JSONObject; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; public class StoreFetch { @@ -42,7 +40,7 @@ public class StoreFetch { public static void main(String[] args) { -// get("1.4.1"); +// fetch("1.4.1"); } } diff --git a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/models/StoreExtension.java b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/models/StoreExtension.java index 979e428..75033ce 100644 --- a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/models/StoreExtension.java +++ b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/repository/models/StoreExtension.java @@ -127,12 +127,12 @@ public class StoreExtension { } public static class Commands { - private final String defaultCommand; - private final String linux; - private final String windows; - private final String mac; + private final List defaultCommand; + private final List linux; + private final List windows; + private final List mac; - public Commands(String defaultCommand, String linux, String windows, String mac) { + public Commands(List defaultCommand, List linux, List windows, List mac) { this.defaultCommand = defaultCommand; this.linux = linux; this.windows = windows; @@ -140,25 +140,29 @@ public class StoreExtension { } public Commands(JSONObject object) { - this.defaultCommand = object.getString("default"); - this.linux = object.has("linux") ? object.getString("linux") : null; - this.windows = object.has("windows") ? object.getString("windows") : null; - this.mac = object.has("mac") ? object.getString("mac") : null; + this.defaultCommand = object.getJSONArray("default").toList().stream() + .map(s -> (String)s).collect(Collectors.toList()); + this.linux = object.has("linux") ?object.getJSONArray("linux").toList().stream() + .map(s -> (String)s).collect(Collectors.toList()) : null; + this.windows = object.has("windows") ? object.getJSONArray("windows").toList().stream() + .map(s -> (String)s).collect(Collectors.toList()) : null; + this.mac = object.has("mac") ? object.getJSONArray("mac").toList().stream() + .map(s -> (String)s).collect(Collectors.toList()) : null; } - public String getDefault() { + public List getDefault() { return defaultCommand; } - public String getLinux() { + public List getLinux() { return linux; } - public String getWindows() { + public List getWindows() { return windows; } - public String getMac() { + public List getMac() { return mac; } } diff --git a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/tools/StoreExtensionTools.java b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/tools/StoreExtensionTools.java index 1e67427..3c7cb7d 100644 --- a/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/tools/StoreExtensionTools.java +++ b/G-Earth/src/main/java/gearth/services/internal_extensions/extensionstore/tools/StoreExtensionTools.java @@ -1,21 +1,29 @@ package gearth.services.internal_extensions.extensionstore.tools; +import gearth.misc.OSValidator; +import gearth.services.extension_handler.extensions.implementations.network.authentication.Authenticator; import gearth.services.extension_handler.extensions.implementations.network.executer.ExecutionInfo; import gearth.services.extension_handler.extensions.implementations.network.executer.NormalExtensionRunner; +import gearth.services.internal_extensions.extensionstore.repository.StoreFetch; import gearth.services.internal_extensions.extensionstore.repository.StoreRepository; import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.json.JSONArray; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -29,32 +37,71 @@ public class StoreExtensionTools { } - public static void executeExtension(String folderName) { + public static void executeExtension(String extensionPath, int port) { + try { + String installedExtensionId = Paths.get(extensionPath).getFileName().toString(); + + String commandPath = Paths.get(extensionPath, "command.txt").toString(); + String cookie = Authenticator.generateCookieForExtension(installedExtensionId); + List command = new JSONArray(FileUtils.readFileToString(new File(commandPath), "UTF-8")) + .toList().stream().map(o -> (String)o).map(s -> s + .replace("{port}", port+"") + .replace("{filename}", installedExtensionId) + .replace("{cookie}", cookie)) + .collect(Collectors.toList()); + + ProcessBuilder pb = new ProcessBuilder(command); + pb.directory(new File(Paths.get(extensionPath, "extension").toString())); + Process p = pb.start(); + NormalExtensionRunner.maybeLogExtension(extensionPath, p); + + } catch (IOException e) { + e.printStackTrace(); + } } private static void unzipInto(InputStream inputStream, File directory) throws IOException { + byte[] buffer = new byte[1024]; inputStream = new BufferedInputStream(inputStream); ZipInputStream zipInputStream = new ZipInputStream(inputStream); - for (ZipEntry entry = null; (entry = zipInputStream.getNextEntry()) != null;) { + + ZipEntry entry = zipInputStream.getNextEntry(); + while (entry != null) { File file = new File(Paths.get(directory.getPath(), entry.getName()).toString()); if (entry.isDirectory()) { - file.mkdirs(); + if (!file.isDirectory() && !file.mkdirs()) { + throw new IOException("Failed to create directory " + file); + } } else { - FileUtils.copyInputStreamToFile(inputStream, file); -// StreamUtil.write(pathBuilder, inputStream, false); + File parent = file.getParentFile(); + if (!parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("Failed to create directory " + parent); + } + + // write file content + FileOutputStream fos = new FileOutputStream(file); + int len; + while ((len = zipInputStream.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + fos.close(); } + entry = zipInputStream.getNextEntry(); } + zipInputStream.closeEntry(); + zipInputStream.close(); + + + } public static void installExtension(String name, StoreRepository storeRepository, InstallExtListener listener) { - - new Thread(() -> { String downloadUrl = String.format("https://github.com/sirjonasxx/G-ExtensionStore/raw/repo/%s/store/extensions/%s/extension.zip", storeRepository.getRepoVersion(), name); @@ -73,9 +120,20 @@ public class StoreExtensionTools { try { URL url = new URL(downloadUrl); InputStream inputStream = url.openStream(); - unzipInto(inputStream, extensionPath); - // todo command file + try { + unzipInto(inputStream, extensionPath); + + File commandFile = new File(Paths.get(path, "command.txt").toString()); + List command = OSValidator.isMac() ? ext.getCommands().getMac() : (OSValidator.isUnix() ? ext.getCommands().getLinux() : + (OSValidator.isWindows() ? ext.getCommands().getWindows() : ext.getCommands().getDefault())); + command = command == null ? ext.getCommands().getDefault() : command; + FileUtils.writeStringToFile(commandFile, new JSONArray(command).toString(), "UTF-8"); + listener.success(path); + + } catch (IOException e) { + listener.fail("Error while unzipping"); + } } catch (MalformedURLException e) { listener.fail("Invalid extension URL"); @@ -84,7 +142,7 @@ public class StoreExtensionTools { } } else { - listener.fail("Something went wrong creating the extension directory"); + listener.fail("Something went wrong creating the extension directory, does the extension already exist?"); } } else { @@ -95,13 +153,67 @@ public class StoreExtensionTools { } - public static void removeExtension(String folderName) { - + public static void removeExtension(String extensionPath) throws IOException { + FileUtils.deleteDirectory(new File(extensionPath)); } - public static void updateExtension() { + public static void updateExtension(String name, StoreRepository storeRepository, InstallExtListener listener) { + // remove old occurences + String path = Paths.get(NormalExtensionRunner.JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY).toString(); + File extensionsDir = new File(path); + + try { + File[] existingExtensions = extensionsDir.listFiles(); + if (existingExtensions != null) { + for (File extension : existingExtensions) { + + if (extension.isDirectory()) { + // installed through extensions store + if (extension.getName().contains("_")) { + List parts = new ArrayList<>(Arrays.asList(extension.getName().split("_"))); + parts.remove(path.length() - 1); + String extensionName = String.join("_", parts); + if (name.equals(extensionName)) { + removeExtension(extension.getPath()); + } + } + + } + + } + } + } catch (Exception e) { + listener.fail("Something went wrong with uninstalling the extension"); + return; + } + + installExtension(name, storeRepository, listener); + } + + public static void main(String[] args) { + StoreFetch.fetch("1.4.1", new StoreFetch.StoreFetchListener() { + @Override + public void success(StoreRepository storeRepository) { + installExtension("G-BuildTools", storeRepository, new InstallExtListener() { + @Override + public void success(String installationFolder) { + System.out.println(String.format("Installed in: %s", installationFolder)); + } + + @Override + public void fail(String reason) { + System.out.println(reason); + } + }); + } + + @Override + public void fail(String reason) { + System.out.println("failed fetching repository"); + } + }); }