installation/removal/updating/running extensions from store

This commit is contained in:
sirjonasxx 2021-08-18 04:32:51 +02:00
parent 3ccd67b1c4
commit 41dc3b7119
5 changed files with 213 additions and 81 deletions

View File

@ -21,6 +21,7 @@ public class ExecutionInfo {
extensionTypeToExecutionCommand.put("*.py3", new String[]{"python3", "{path}"}); extensionTypeToExecutionCommand.put("*.py3", new String[]{"python3", "{path}"});
extensionTypeToExecutionCommand.put("*.sh", new String[]{"{path}"}); extensionTypeToExecutionCommand.put("*.sh", new String[]{"{path}"});
extensionTypeToExecutionCommand.put("*.exe", new String[]{"{path}"}); extensionTypeToExecutionCommand.put("*.exe", new String[]{"{path}"});
extensionTypeToExecutionCommand.put("*.js", new String[]{"node", "{path}"});
String[] extraArgs = {"-p", "{port}", "-f", "{filename}", "-c", "{cookie}"}; String[] extraArgs = {"-p", "{port}", "-f", "{filename}", "-c", "{cookie}"};
for(String type : extensionTypeToExecutionCommand.keySet()) { for(String type : extensionTypeToExecutionCommand.keySet()) {

View File

@ -2,6 +2,7 @@ package gearth.services.extension_handler.extensions.implementations.network.exe
import gearth.Main; import gearth.Main;
import gearth.services.extension_handler.extensions.implementations.network.authentication.Authenticator; 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.BufferedReader;
import java.io.File; import java.io.File;
@ -72,7 +73,7 @@ public class NormalExtensionRunner implements ExtensionRunner {
newPath newPath
); );
addExecPermission(newPath.toString()); // addExecPermission(newPath.toString());
tryRunExtension(newPath.toString(), port); tryRunExtension(newPath.toString(), port);
} catch (IOException e) { } catch (IOException e) {
@ -84,7 +85,15 @@ public class NormalExtensionRunner implements ExtensionRunner {
public void tryRunExtension(String path, int port) { public void tryRunExtension(String path, int port) {
try { 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 filename = Paths.get(path).getFileName().toString();
String[] execCommand = ExecutionInfo.getExecutionCommand(getFileExtension(path)); String[] execCommand = ExecutionInfo.getExecutionCommand(getFileExtension(path));
execCommand = Arrays.copyOf(execCommand, execCommand.length); execCommand = Arrays.copyOf(execCommand, execCommand.length);
String cookie = Authenticator.generateCookieForExtension(filename); String cookie = Authenticator.generateCookieForExtension(filename);
@ -99,6 +108,13 @@ public class NormalExtensionRunner implements ExtensionRunner {
// Process proc = Runtime.getRuntime().exec(execCommand); // Process proc = Runtime.getRuntime().exec(execCommand);
Process proc = pb.start(); Process proc = pb.start();
maybeLogExtension(path, proc);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void maybeLogExtension(String path, Process proc) {
if (Main.hasFlag(ExtensionRunner.SHOW_EXTENSIONS_LOG)) { if (Main.hasFlag(ExtensionRunner.SHOW_EXTENSIONS_LOG)) {
String sep = "" + System.lineSeparator(); String sep = "" + System.lineSeparator();
synchronized (System.out) { synchronized (System.out) {
@ -138,27 +154,28 @@ public class NormalExtensionRunner implements ExtensionRunner {
}).start(); }).start();
} }
} catch (IOException e) {
e.printStackTrace();
}
} }
@Override @Override
public void uninstallExtension(String filename) { public void uninstallExtension(String filename) {
try { try {
Files.delete(Paths.get( Path path = Paths.get(JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY, filename);
JARPATH, if (new File(path.toString()).isDirectory()) {
ExecutionInfo.EXTENSIONSDIRECTORY, // is installed through extension store
filename StoreExtensionTools.removeExtension(path.toString());
)); }
else {
Files.delete(path);
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void addExecPermission(String path) { // private void addExecPermission(String path) {
//not needed at first sight // //not needed at first sight
} // }
private String getFileExtension(String path) { private String getFileExtension(String path) {
String name = Paths.get(path).getFileName().toString(); String name = Paths.get(path).getFileName().toString();

View File

@ -1,6 +1,5 @@
package gearth.services.internal_extensions.extensionstore.repository; 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 gearth.services.internal_extensions.extensionstore.repository.models.StoreData;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.json.JSONArray; import org.json.JSONArray;
@ -8,7 +7,6 @@ import org.json.JSONObject;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
public class StoreFetch { public class StoreFetch {
@ -42,7 +40,7 @@ public class StoreFetch {
public static void main(String[] args) { public static void main(String[] args) {
// get("1.4.1"); // fetch("1.4.1");
} }
} }

View File

@ -127,12 +127,12 @@ public class StoreExtension {
} }
public static class Commands { public static class Commands {
private final String defaultCommand; private final List<String> defaultCommand;
private final String linux; private final List<String> linux;
private final String windows; private final List<String> windows;
private final String mac; private final List<String> mac;
public Commands(String defaultCommand, String linux, String windows, String mac) { public Commands(List<String> defaultCommand, List<String> linux, List<String> windows, List<String> mac) {
this.defaultCommand = defaultCommand; this.defaultCommand = defaultCommand;
this.linux = linux; this.linux = linux;
this.windows = windows; this.windows = windows;
@ -140,25 +140,29 @@ public class StoreExtension {
} }
public Commands(JSONObject object) { public Commands(JSONObject object) {
this.defaultCommand = object.getString("default"); this.defaultCommand = object.getJSONArray("default").toList().stream()
this.linux = object.has("linux") ? object.getString("linux") : null; .map(s -> (String)s).collect(Collectors.toList());
this.windows = object.has("windows") ? object.getString("windows") : null; this.linux = object.has("linux") ?object.getJSONArray("linux").toList().stream()
this.mac = object.has("mac") ? object.getString("mac") : null; .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<String> getDefault() {
return defaultCommand; return defaultCommand;
} }
public String getLinux() { public List<String> getLinux() {
return linux; return linux;
} }
public String getWindows() { public List<String> getWindows() {
return windows; return windows;
} }
public String getMac() { public List<String> getMac() {
return mac; return mac;
} }
} }

View File

@ -1,21 +1,29 @@
package gearth.services.internal_extensions.extensionstore.tools; 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.ExecutionInfo;
import gearth.services.extension_handler.extensions.implementations.network.executer.NormalExtensionRunner; 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.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension; import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import java.io.BufferedInputStream; import java.io.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; 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<String> 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 { private static void unzipInto(InputStream inputStream, File directory) throws IOException {
byte[] buffer = new byte[1024];
inputStream = new BufferedInputStream(inputStream); inputStream = new BufferedInputStream(inputStream);
ZipInputStream zipInputStream = new ZipInputStream(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()); File file = new File(Paths.get(directory.getPath(), entry.getName()).toString());
if (entry.isDirectory()) { if (entry.isDirectory()) {
file.mkdirs(); if (!file.isDirectory() && !file.mkdirs()) {
throw new IOException("Failed to create directory " + file);
}
} }
else { else {
FileUtils.copyInputStreamToFile(inputStream, file); File parent = file.getParentFile();
// StreamUtil.write(pathBuilder, inputStream, false); 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) { public static void installExtension(String name, StoreRepository storeRepository, InstallExtListener listener) {
new Thread(() -> { new Thread(() -> {
String downloadUrl = String.format("https://github.com/sirjonasxx/G-ExtensionStore/raw/repo/%s/store/extensions/%s/extension.zip", storeRepository.getRepoVersion(), name); 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 { try {
URL url = new URL(downloadUrl); URL url = new URL(downloadUrl);
InputStream inputStream = url.openStream(); 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<String> 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) { } catch (MalformedURLException e) {
listener.fail("Invalid extension URL"); listener.fail("Invalid extension URL");
@ -84,7 +142,7 @@ public class StoreExtensionTools {
} }
} }
else { 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 { 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<String> 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");
}
});
} }