install extensions through store

This commit is contained in:
sirjonasxx 2021-08-19 20:07:16 +02:00
parent 01554eb428
commit 9032fbd9df
14 changed files with 450 additions and 34 deletions

View File

@ -16,6 +16,9 @@ import java.net.Socket;
*/
public class NetworkExtensionsProducer implements ExtensionProducer {
public static int extensionPort = -1;
private ServerSocket serverSocket;
@Override
@ -84,6 +87,7 @@ public class NetworkExtensionsProducer implements ExtensionProducer {
private boolean createServer(int port) {
try {
serverSocket = new ServerSocket(port);
extensionPort = port;
return true;
} catch (IOException e) {
return false;

View File

@ -44,7 +44,7 @@ public class GExtensionStore extends ExtensionForm {
gExtensionStoreController.maybeInitialized();
}
public GExtensionStoreController getExtensionStoreController() {
public GExtensionStoreController getController() {
return extensionStoreController;
}

View File

@ -205,7 +205,7 @@ public class GExtensionStoreController implements Initializable {
private void onFullInitialize() {
initialized = true;
pushOverview(new ByDateOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository()));
setRootOverview(new ByDateOverview(null, 0, GExtensionStore.PAGESIZE, getStoreRepository()));
}
public void gExtensionStore(GExtensionStore gExtensionStore) {
@ -228,4 +228,7 @@ public class GExtensionStoreController implements Initializable {
return currentOverviews.getLast();
}
public String getContentItemsContainer() {
return contentItemsContainer;
}
}

View File

@ -2,6 +2,9 @@ package gearth.services.internal_extensions.extensionstore.application;
import org.w3c.dom.Element;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -35,19 +38,23 @@ public class WebUtils {
return s;
}
public static String elapsedTime(int time) {
public static String elapsedSince(LocalDateTime time) {
return elapsedTime(System.currentTimeMillis()/1000 - time.atZone(ZoneId.systemDefault()).toEpochSecond());
}
public static String elapsedTime(long time) {
if (time < 60) return time + (time == 1 ? " second" : " seconds");
time = time/60;
if (time < 60) return time + (time == 1 ? " minute" : " minutes");
time = time/60;
if (time < 24) return time + (time == 1 ? " hour" : " hours");
int days = time/24;
long days = time/24;
if (days < 7) return days + (days == 1 ? " day" : " days");
int weeks = days/7;
long weeks = days/7;
if (weeks < 6) return weeks + (weeks == 1 ? " week" : " weeks");
int months = days/31;
long months = days/31;
if (months < 12) return months + (months == 1 ? " month" : " months");
int years = days/365;
long years = days/365;
return years + (years == 1 ? " year" : " years");
}

View File

@ -1,19 +1,79 @@
package gearth.services.internal_extensions.extensionstore.application.entities;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.internal_extensions.extensionstore.GExtensionStore;
import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController;
import gearth.services.internal_extensions.extensionstore.application.WebUtils;
import gearth.services.internal_extensions.extensionstore.application.entities.extensiondetails.StoreExtensionDetailsOverview;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.CategorizedOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import netscape.javascript.JSObject;
public class StoreExtensionItem implements ContentItem {
protected final StoreExtension storeExtension;
private GExtensionStore gExtensionStore = null;
public StoreExtensionItem(StoreExtension storeExtension) {
this.storeExtension = storeExtension;
}
public void onClick() {
gExtensionStore.getController().pushOverview(
new StoreExtensionDetailsOverview(
gExtensionStore.getController().getCurrentOverview(),
0,
GExtensionStore.PAGESIZE,
storeExtension,
gExtensionStore.getRepository()
)
);
}
protected String displayVersion() {
return storeExtension.getVersion();
}
protected String displayColor(int i) {
return i % 2 == 0 ? "item_lightblue" : "item_darkblue";
}
@Override
public void addHtml(int i, GExtensionStore gExtensionStore) {
this.gExtensionStore = gExtensionStore;
StoreRepository repository = gExtensionStore.getRepository();
String id = "ext" + i + "_" + System.currentTimeMillis();
StringBuilder htmlBuilder = new StringBuilder()
.append("<div class=\"overview_item ").append(displayColor(i)).append(" content_item\">")
.append("<div class=\"overview_item_logo\">")
.append("<img src=\"").append(repository.getResourceUrl(String.format("store/extensions/%s/icon.png", storeExtension.getTitle()))).append("\" alt=\"\">")
.append("</div>")
.append("<div class=\"overview_item_info\">")
.append("<div onclick=\"").append(id).append(".onClick()\" class=\"oii_name clickable\">").append(WebUtils.escapeMessage(storeExtension.getTitle())).append("</div>")
.append("<div class=\"oii_desc\">By ").append(storeExtension.getAuthors().get(0).getName()).append(", last updated ").append(WebUtils.elapsedSince(storeExtension.getUpdateDate())).append(" ago</div>")
.append("</div>")
.append("<div onclick=\"").append(id).append(".onClick()\" class=\"overview_item_msgs clickable\">")
.append("<div class=\"oim_top\">").append("Version: ").append(displayVersion()).append("</div>")
.append("<div class=\"oim_bottom\">").append("Rating: ").append(storeExtension.getRating()).append("</div>")
// .append("<div class=\"oim_bottom\">").append(storeExtension.getFramework().getFramework().getName().replace("Native", "")).append(" </div>")
.append("</div>")
.append("</div>");
String extension = htmlBuilder.toString();
GExtensionStoreController controller = gExtensionStore.getController();
controller.getWebView().getEngine().executeScript("document.getElementById('" + controller.getContentItemsContainer() + "').innerHTML += '" + extension + "';");
JSObject window = (JSObject) controller.getWebView().getEngine().executeScript("window");
window.setMember(id, this);
}
}

View File

@ -1,19 +1,75 @@
package gearth.services.internal_extensions.extensionstore.application.entities.categories;
import gearth.services.internal_extensions.extensionstore.GExtensionStore;
import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController;
import gearth.services.internal_extensions.extensionstore.application.WebUtils;
import gearth.services.internal_extensions.extensionstore.application.entities.ContentItem;
import gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews.CategorizedOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.ExtCategory;
import gearth.services.internal_extensions.extensionstore.repository.querying.ExtensionOrdering;
import netscape.javascript.JSObject;
import java.util.Arrays;
import java.util.Collections;
public class CategoryItem implements ContentItem {
private final ExtCategory category;
private GExtensionStore gExtensionStore = null;
public CategoryItem(ExtCategory category) {
this.category = category;
}
public void onClick() {
gExtensionStore.getController().pushOverview(
new CategorizedOverview(
gExtensionStore.getController().getCurrentOverview(),
0,
GExtensionStore.PAGESIZE,
gExtensionStore.getRepository(),
category
)
);
}
@Override
public void addHtml(int i, GExtensionStore gExtensionStore) {
this.gExtensionStore = gExtensionStore;
StoreRepository repository = gExtensionStore.getRepository();
String id = "category" + i + "_" + System.currentTimeMillis();
int releasesCount = gExtensionStore.getRepository().getExtensions(0, -1, "", ExtensionOrdering.NEW_RELEASES,
null, null, null, Collections.singletonList(category.getName()), false, false).size();
StringBuilder htmlBuilder = new StringBuilder()
.append("<div class=\"overview_item ").append(i % 2 == 0 ? "item_lightblue" : "item_darkblue").append(" content_item\">")
.append("<div class=\"overview_item_logo\">")
.append("<img src=\"").append(repository.getResourceUrl(String.format("assets/icons/%s", category.getIcon()))).append("\" alt=\"\">")
.append("</div>")
.append("<div class=\"overview_item_info\">")
.append("<div onclick=\"").append(id).append(".onClick()\" class=\"oii_name clickable\">").append(WebUtils.escapeMessage(category.getName())).append("</div>")
.append("<div class=\"oii_desc\">").append(WebUtils.escapeMessage(category.getDescription())).append(" </div>")
.append("</div>")
.append("<div onclick=\"").append(id).append(".onClick()\" class=\"overview_item_msgs clickable\">")
.append("<div class=\"oim_top\">").append(releasesCount).append(" releases").append("</div>")
// .append("<div class=\"oim_bottom\">").append(storeExtension.getFramework().getFramework().getName().replace("Native", "")).append(" </div>")
.append("</div>")
.append("</div>");
String category = htmlBuilder.toString();
GExtensionStoreController controller = gExtensionStore.getController();
controller.getWebView().getEngine().executeScript("document.getElementById('" + controller.getContentItemsContainer() + "').innerHTML += '" + category + "';");
JSObject window = (JSObject) controller.getWebView().getEngine().executeScript("window");
window.setMember(id, this);
}
}

View File

@ -0,0 +1,186 @@
package gearth.services.internal_extensions.extensionstore.application.entities.extensiondetails;
import gearth.services.extension_handler.extensions.implementations.network.NetworkExtensionsProducer;
import gearth.services.extension_handler.extensions.implementations.network.executer.NormalExtensionRunner;
import gearth.services.internal_extensions.extensionstore.GExtensionStore;
import gearth.services.internal_extensions.extensionstore.application.GExtensionStoreController;
import gearth.services.internal_extensions.extensionstore.application.WebUtils;
import gearth.services.internal_extensions.extensionstore.application.entities.ContentItem;
import gearth.services.internal_extensions.extensionstore.application.entities.HOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import gearth.services.internal_extensions.extensionstore.tools.InstalledExtension;
import gearth.services.internal_extensions.extensionstore.tools.StoreExtensionTools;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.w3c.dom.Element;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class StoreExtensionDetailsOverview extends HOverview {
private final StoreRepository storeRepository;
private final StoreExtension extension;
private final Optional<InstalledExtension> installedExtension;
public StoreExtensionDetailsOverview(HOverview parent, int startIndex, int limit, StoreExtension extension, StoreRepository storeRepository) {
super(parent, startIndex, limit);
this.extension = extension;
this.storeRepository = storeRepository;
List<InstalledExtension> installed = StoreExtensionTools.getInstalledExtension();
// assure highest version comes first
installed.sort((o1, o2) -> new ComparableVersion(o2.getVersion()).compareTo(new ComparableVersion(o1.getVersion())));
installedExtension = installed.stream().filter(i -> i.getName().equals(extension.getTitle())).findFirst();
}
// 0 = not installed
// 1 = installed
// 2 = needs update
private int mode() {
if(installedExtension.isPresent()) {
InstalledExtension i = installedExtension.get();
if (new ComparableVersion(i.getVersion()).compareTo(new ComparableVersion(extension.getVersion())) < 0) {
return 2;
}
return 1;
}
return 0;
}
@Override
public String buttonText() {
int mode = mode();
return mode == 2 ? "Update" : "Install";
// return mode == 0 ? "Install" : (mode == 1 ? "Remove" : "Update");
}
@Override
public boolean buttonEnabled() {
return mode() != 1;
}
@Override
public List<? extends ContentItem> getContentItems() {
return Collections.singletonList(new StoreExtensionDetailsItem(extension));
}
@Override
public int getMaxAmount() {
return 1;
}
private void setButtonEnable(GExtensionStore gExtensionStore, boolean enabled) {
GExtensionStoreController c = gExtensionStore.getController();
Element generic_btn = c.getWebView().getEngine().getDocument().getElementById("generic_btn");
WebUtils.removeClass((Element) generic_btn.getParentNode(), "gdisabled");
if (!enabled) WebUtils.addClass((Element) generic_btn.getParentNode(), "gdisabled");
}
private void awaitPopup(String mode) {
popup(Alert.AlertType.WARNING,
String.format("%s extension", mode),
String.format("%s extension [%s]", mode, extension.getTitle()),
String.format("Press \"OK\" and wait while the extension is being %sed", mode.toLowerCase()));
}
private void successPopup(String mode) {
popup(Alert.AlertType.INFORMATION,
String.format("%s extension", mode),
String.format("%s extension [%s]", mode, extension.getTitle()),
String.format("Extension %s completed successfully", mode.toLowerCase()));
}
private void errorPopup(String mode, String error) {
popup(Alert.AlertType.ERROR,
String.format("%s failed", mode),
String.format("%s failed [%s]", mode, extension.getTitle()),
String.format("%s failed with the following message: %s", mode, error));
}
private void popup(Alert.AlertType alertType, String title, String header, String context) {
Alert alert = new Alert(alertType);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(context);
alert.showAndWait();
}
@Override
public void buttonClick(GExtensionStore gExtensionStore) {
int mode = mode();
if (mode == 2) return;
String modeString = mode() == 0 ? "Install" : "Update";
HOverview selff = this;
StoreExtensionTools.InstallExtListener listener = new StoreExtensionTools.InstallExtListener() {
@Override
public void success(String installationFolder) {
Platform.runLater(() -> successPopup(modeString));
StoreExtensionTools.executeExtension(installationFolder, NetworkExtensionsProducer.extensionPort);
}
@Override
public void fail(String reason) {
Platform.runLater(() -> {
errorPopup(modeString, reason);
if (gExtensionStore.getController().getCurrentOverview() == selff) {
setButtonEnable(gExtensionStore, true);
}
});
}
};
setButtonEnable(gExtensionStore, false);
awaitPopup(modeString);
if (mode() == 0) {
StoreExtensionTools.installExtension(extension.getTitle(), storeRepository, listener);
}
else if (mode() == 1) {
StoreExtensionTools.updateExtension(extension.getTitle(), storeRepository, listener);
}
}
@Override
public Header header() {
return new Header() {
@Override
public String iconUrl() {
return storeRepository.getResourceUrl(String.format("store/extensions/%s/icon.png", extension.getTitle()));
}
@Override
public String title() {
return extension.getTitle();
}
@Override
public String description() {
return extension.getDescription();
}
@Override
public String contentTitle() {
return extension.getTitle();
}
};
}
@Override
public HOverview getNewPage(int startIndex, int size) {
return null; // impossible
}
}

View File

@ -7,7 +7,12 @@ import gearth.services.internal_extensions.extensionstore.repository.StoreReposi
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import gearth.services.internal_extensions.extensionstore.tools.InstalledExtension;
import gearth.services.internal_extensions.extensionstore.tools.StoreExtensionTools;
import org.apache.maven.artifact.versioning.ComparableVersion;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -36,6 +41,8 @@ public class InstalledOverview extends HOverview {
@Override
public List<? extends ContentItem> getContentItems() {
List<InstalledExtension> installed = StoreExtensionTools.getInstalledExtension();
installed.sort(Comparator.comparing(o -> new ComparableVersion(o.getVersion())));
installed = installed.subList(startIndex, Math.min(startIndex + limit, installed.size()));
Map<String, StoreExtension> nameToExt = new HashMap<>();
storeRepository.getExtensions().forEach(e -> nameToExt.put(e.getTitle(), e));
@ -50,7 +57,11 @@ public class InstalledOverview extends HOverview {
@Override
public void buttonClick(GExtensionStore gExtensionStore) {
// todo open installation folder
try {
Desktop.getDesktop().open(new File(StoreExtensionTools.EXTENSIONS_PATH));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
@ -63,7 +74,7 @@ public class InstalledOverview extends HOverview {
@Override
public String title() {
return "Installed extensions";
return "Installed Extensions";
}
@Override

View File

@ -18,13 +18,24 @@ public class StoreExtensionInstalledItem extends StoreExtensionItem {
this.installedExtension = installedExtension;
}
@Override
protected String displayColor(int i) {
return super.displayColor(i);
// todo color depending on if it needs an update
}
@Override
protected String displayVersion() {
return installedExtension.getVersion();
}
@Override
public void addHtml(int i, GExtensionStore gExtensionStore) {
if (this.storeExtension != null) {
super.addHtml(i, gExtensionStore /* add custom color here */);
}
//todo
//todo html when extension isn't in store
}
}

View File

@ -0,0 +1,59 @@
package gearth.services.internal_extensions.extensionstore.application.entities.queriedoverviews;
import gearth.misc.OSValidator;
import gearth.services.internal_extensions.extensionstore.application.WebUtils;
import gearth.services.internal_extensions.extensionstore.application.entities.HOverview;
import gearth.services.internal_extensions.extensionstore.repository.StoreRepository;
import gearth.services.internal_extensions.extensionstore.repository.models.ExtCategory;
import gearth.services.internal_extensions.extensionstore.repository.models.StoreExtension;
import gearth.services.internal_extensions.extensionstore.repository.querying.ExtensionOrdering;
import java.util.Collections;
import java.util.List;
public class CategorizedOverview extends QueriedExtensionOverview {
private final ExtCategory category;
public CategorizedOverview(HOverview parent, int startIndex, int size, StoreRepository storeRepository, ExtCategory category) {
super(parent, startIndex, size, storeRepository);
this.category = category;
}
@Override
protected List<StoreExtension> query(int startIndex, int size) {
return storeRepository.getExtensions(startIndex, size, "", ExtensionOrdering.RATING,
Collections.singletonList(OSValidator.getOSFull()), null, null,
Collections.singletonList(category.getName()), false, false);
}
@Override
public Header header() {
return new Header() {
@Override
public String iconUrl() {
return storeRepository.getResourceUrl(String.format("assets/icons/%s", category.getIcon()));
}
@Override
public String title() {
return category.getName();
}
@Override
public String description() {
return category.getDescription();
}
@Override
public String contentTitle() {
return "Category: " + category.getName();
}
};
}
@Override
public HOverview getNewPage(int startIndex, int size) {
return new CategorizedOverview(parent, startIndex, size, storeRepository, category);
}
}

View File

@ -31,7 +31,7 @@ public class StoreExtension {
public StoreExtension(JSONObject object, StoreConfig storeConfig) {
this.title = object.getString("title");
this.description = object.getString("title");
this.description = object.getString("description");
this.authors = object.getJSONArray("authors").toList().stream().map(o -> new Author(new JSONObject((Map)o))).collect(Collectors.toList());
this.version = object.getString("version");
this.categories = storeConfig.getCategories().stream().filter(c -> object.getJSONArray("categories")

View File

@ -32,6 +32,8 @@ public class StoreExtensionTools {
}
public final static String EXTENSIONS_PATH = Paths.get(NormalExtensionRunner.JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY).toString();
public static void executeExtension(String extensionPath, int port) {
try {
@ -107,7 +109,7 @@ public class StoreExtensionTools {
String version = ext.getVersion();
String folderName = name + "_" + version;
String path = Paths.get(NormalExtensionRunner.JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY, folderName).toString();
String path = Paths.get(EXTENSIONS_PATH, folderName).toString();
File dir = new File(path);
File extensionPath = new File(Paths.get(path, "extension").toString());
@ -156,9 +158,7 @@ public class StoreExtensionTools {
public static List<InstalledExtension> getInstalledExtension() {
List<InstalledExtension> installedExtensions = new ArrayList<>();
String path = Paths.get(NormalExtensionRunner.JARPATH, ExecutionInfo.EXTENSIONSDIRECTORY).toString();
File extensionsDir = new File(path);
File extensionsDir = new File(EXTENSIONS_PATH);
File[] existingExtensions = extensionsDir.listFiles();
if (existingExtensions != null) {
@ -168,9 +168,9 @@ public class StoreExtensionTools {
// installed through extensions store
if (extension.getName().contains("_")) {
List<String> parts = new ArrayList<>(Arrays.asList(extension.getName().split("_")));
parts.remove(parts.size() - 1);
String version = parts.remove(parts.size() - 1);
String extensionName = String.join("_", parts);
installedExtensions.add(new InstalledExtension(extensionName, parts.get(parts.size() - 1)));
installedExtensions.add(new InstalledExtension(extensionName, version));
}
}
@ -194,9 +194,8 @@ public class StoreExtensionTools {
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);
File extensionsDir = new File(EXTENSIONS_PATH);
try {
File[] existingExtensions = extensionsDir.listFiles();
@ -219,7 +218,8 @@ public class StoreExtensionTools {
}
}
} catch (Exception e) {
listener.fail("Something went wrong with uninstalling the extension");
listener.fail("Something went wrong with uninstalling the extension, make sure to disconnect" +
" the extension if it was still running.");
return;
}

View File

@ -19,13 +19,16 @@
min-width: 41px;
}
.overview_item_logo > img {
max-width: 40px;
max-height: 40px;
}
.overview_item_info {
flex: 1 1 auto;
min-width: 0;
margin-left: 3px;
margin-top: 0;
margin-left: 5px;
}
.overview_item_msgs {
@ -33,31 +36,34 @@
width: 103px;
min-width: 103px;
margin-left: 4px;
padding-left: 4px;
border: 0 solid #bab8b4;
border-left-width: 1px;
margin-top: 2px;
}
.oii_name {
font-size: 13px;
width: 100%;
overflow: hidden;
max-height: 14px;
min-height: 14px;
padding-top: 3px;
padding-top: 4px;
}
.oii_desc {
font-size: 11px;
margin-top: 2px;
margin-top: 3px;
overflow: hidden;
}
.oim_msgs {
.oim_top {
font-size: 11px;
margin-top: 3px;
margin-top: 6px;
}
.oim_unread {
.oim_bottom {
font-size: 11px;
margin-top: 3px;
margin-top: 4px;
}

View File

@ -48,8 +48,8 @@
}
#logo > img {
max-height: 50px;
max-width: 50px;
height: 50px;
width: 50px;
}
@ -95,6 +95,19 @@
margin-left: auto;
}
.quick_links_item > a {
text-decoration: none;
/*border-bottom: 1px solid #1b79ab;*/
/*box-sizing: border-box;*/
/*padding-bottom: -1px;*/
box-shadow: 0 -1px 0 #218ac2 inset;
color: #218ac2
;
}