From e0266fec6b657ff3ed04193d5f38797eaac1a87d Mon Sep 17 00:00:00 2001 From: Christopher Schnick Date: Tue, 16 Aug 2022 17:49:46 +0200 Subject: [PATCH] Add some more store commands, add dialog helpers, and small fixes --- .../exchange/cli/EditStoreExchange.java | 33 ++++++++ ...e.java => SourceProviderListExchange.java} | 4 +- .../cli/StoreProviderListExchange.java | 33 ++++++++ beacon/src/main/java/module-info.java | 4 +- .../io/xpipe/core/store/InMemoryStore.java | 5 -- .../java/io/xpipe/core/store/LocalStore.java | 22 ++--- .../io/xpipe/extension/DataStoreProvider.java | 6 +- .../xpipe/extension/DataStoreProviders.java | 10 ++- .../java/io/xpipe/extension/DialogHelper.java | 83 +++++++++++++++++++ .../java/io/xpipe/extension/XPipeDaemon.java | 17 ++++ .../extension/comp/DynamicOptionsBuilder.java | 14 ++-- extension/src/main/java/module-info.java | 1 + 12 files changed, 202 insertions(+), 30 deletions(-) create mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java rename beacon/src/main/java/io/xpipe/beacon/exchange/cli/{ProviderListExchange.java => SourceProviderListExchange.java} (87%) create mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java create mode 100644 extension/src/main/java/io/xpipe/extension/DialogHelper.java create mode 100644 extension/src/main/java/io/xpipe/extension/XPipeDaemon.java diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java new file mode 100644 index 000000000..db4883179 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java @@ -0,0 +1,33 @@ +package io.xpipe.beacon.exchange.cli; + +import io.xpipe.beacon.RequestMessage; +import io.xpipe.beacon.ResponseMessage; +import io.xpipe.beacon.exchange.MessageExchange; +import io.xpipe.core.dialog.DialogReference; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class EditStoreExchange implements MessageExchange { + + @Override + public String getId() { + return "editEntry"; + } + + @Jacksonized + @Builder + @Value + public static class Request implements RequestMessage { + @NonNull + String name; + } + + @Jacksonized + @Builder + @Value + public static class Response implements ResponseMessage { + @NonNull DialogReference dialog; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ProviderListExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/SourceProviderListExchange.java similarity index 87% rename from beacon/src/main/java/io/xpipe/beacon/exchange/cli/ProviderListExchange.java rename to beacon/src/main/java/io/xpipe/beacon/exchange/cli/SourceProviderListExchange.java index 5f60af397..e129e31c9 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ProviderListExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/SourceProviderListExchange.java @@ -13,11 +13,11 @@ import lombok.extern.jackson.Jacksonized; import java.util.List; import java.util.Map; -public class ProviderListExchange implements MessageExchange { +public class SourceProviderListExchange implements MessageExchange { @Override public String getId() { - return "providerList"; + return "sourceProviderList"; } @Jacksonized diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java new file mode 100644 index 000000000..fd1fa2001 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java @@ -0,0 +1,33 @@ +package io.xpipe.beacon.exchange.cli; + +import io.xpipe.beacon.RequestMessage; +import io.xpipe.beacon.ResponseMessage; +import io.xpipe.beacon.exchange.MessageExchange; +import io.xpipe.beacon.exchange.data.ProviderEntry; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.util.List; + +public class StoreProviderListExchange implements MessageExchange { + + @Override + public String getId() { + return "storeProviderList"; + } + + @Jacksonized + @Builder + @Value + public static class Request implements RequestMessage { + } + + @Jacksonized + @Builder + @Value + public static class Response implements ResponseMessage { + @NonNull List entries; + } +} diff --git a/beacon/src/main/java/module-info.java b/beacon/src/main/java/module-info.java index 5fdc84ef7..2f9caae27 100644 --- a/beacon/src/main/java/module-info.java +++ b/beacon/src/main/java/module-info.java @@ -22,6 +22,8 @@ module io.xpipe.beacon { uses MessageExchange; provides io.xpipe.beacon.exchange.MessageExchange with + EditStoreExchange, + StoreProviderListExchange, ListCollectionsExchange, ListEntriesExchange, ModeExchange, @@ -45,7 +47,7 @@ module io.xpipe.beacon { RemoveCollectionExchange, RenameCollectionExchange, RenameEntryExchange, - ProviderListExchange, + SourceProviderListExchange, ConvertExchange, QueryRawDataExchange, QueryTableDataExchange, diff --git a/core/src/main/java/io/xpipe/core/store/InMemoryStore.java b/core/src/main/java/io/xpipe/core/store/InMemoryStore.java index 3e9ce281e..85e4cb36f 100644 --- a/core/src/main/java/io/xpipe/core/store/InMemoryStore.java +++ b/core/src/main/java/io/xpipe/core/store/InMemoryStore.java @@ -6,7 +6,6 @@ import lombok.Value; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.nio.charset.StandardCharsets; /** * A store whose contents are stored in memory. @@ -22,10 +21,6 @@ public class InMemoryStore implements StreamDataStore { this.value = value; } - public InMemoryStore(String s) { - value = s.getBytes(StandardCharsets.UTF_8); - } - @Override public boolean isLocalToApplication() { return true; diff --git a/core/src/main/java/io/xpipe/core/store/LocalStore.java b/core/src/main/java/io/xpipe/core/store/LocalStore.java index 71efe2cd8..c11b59c80 100644 --- a/core/src/main/java/io/xpipe/core/store/LocalStore.java +++ b/core/src/main/java/io/xpipe/core/store/LocalStore.java @@ -9,7 +9,6 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -23,22 +22,19 @@ public class LocalStore extends StandardShellStore implements MachineFileStore { return true; } - static class LocalProcessControl extends ProcessControl { + class LocalProcessControl extends ProcessControl { private final List input; - private final ProcessBuilder builder; private final Integer timeout; + private final List command; + private Charset charset; private Process process; LocalProcessControl(List input, List cmd, Integer timeout) { this.input = input; this.timeout = timeout; - var l = new ArrayList(); - l.add("cmd"); - l.add("/c"); - l.addAll(cmd); - builder = new ProcessBuilder(l); + this.command = cmd; } private InputStream createInputStream() { @@ -47,8 +43,12 @@ public class LocalStore extends StandardShellStore implements MachineFileStore { } @Override - public void start() throws IOException { + public void start() throws Exception { + var type = LocalStore.this.determineType(); + var l = type.switchTo(command); + var builder = new ProcessBuilder(l); process = builder.start(); + charset = type.getCharset(); var t = new Thread(() -> { try (var inputStream = createInputStream()){ @@ -84,7 +84,7 @@ public class LocalStore extends StandardShellStore implements MachineFileStore { @Override public Charset getCharset() { - return StandardCharsets.US_ASCII; + return charset; } public Integer getTimeout() { @@ -126,6 +126,6 @@ public class LocalStore extends StandardShellStore implements MachineFileStore { @Override public ShellType determineType() throws Exception { - return ShellTypes.determine(this); + return ShellTypes.getDefault(); } } diff --git a/extension/src/main/java/io/xpipe/extension/DataStoreProvider.java b/extension/src/main/java/io/xpipe/extension/DataStoreProvider.java index 3f9d14310..83dead532 100644 --- a/extension/src/main/java/io/xpipe/extension/DataStoreProvider.java +++ b/extension/src/main/java/io/xpipe/extension/DataStoreProvider.java @@ -72,11 +72,13 @@ public interface DataStoreProvider { return getModuleName() + ":" + getId() + "_icon.png"; } - default Dialog dialogForString(String s) { + DataStore storeForString(String s); + + default Dialog dialogForStore(DataStore store) { return null; } - default Dialog defaultDialog() { + default DataStore defaultStore() { throw new ExtensionException("CLI Dialog not implemented by provider"); } diff --git a/extension/src/main/java/io/xpipe/extension/DataStoreProviders.java b/extension/src/main/java/io/xpipe/extension/DataStoreProviders.java index f54d62e6c..be7183d05 100644 --- a/extension/src/main/java/io/xpipe/extension/DataStoreProviders.java +++ b/extension/src/main/java/io/xpipe/extension/DataStoreProviders.java @@ -44,7 +44,15 @@ public class DataStoreProviders { throw new IllegalStateException("Not initialized"); } - return ALL.stream().map(d -> d.dialogForString(s)).filter(Objects::nonNull).findAny(); + return ALL.stream().map(d -> { + var store = d.storeForString(s); + if (store != null) { + return d.dialogForStore(store); + } else { + return null; + } + } + ).filter(Objects::nonNull).findAny(); } diff --git a/extension/src/main/java/io/xpipe/extension/DialogHelper.java b/extension/src/main/java/io/xpipe/extension/DialogHelper.java new file mode 100644 index 000000000..7c79c1aec --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/DialogHelper.java @@ -0,0 +1,83 @@ +package io.xpipe.extension; + +import io.xpipe.core.dialog.Dialog; +import io.xpipe.core.dialog.QueryConverter; +import io.xpipe.core.store.DataStore; +import io.xpipe.core.store.LocalStore; +import io.xpipe.core.store.MachineFileStore; +import io.xpipe.core.store.ShellStore; +import io.xpipe.core.util.Secret; +import lombok.Value; + +public class DialogHelper { + + @Value + public static class Address { + String hostname; + Integer port; + } + + public static Dialog addressQuery(Address address) { + var hostNameQuery = Dialog.query("Hostname", false, true, false, address.getHostname(), QueryConverter.STRING); + var portQuery = Dialog.query("Port", false, true, false, address.getPort(), QueryConverter.INTEGER); + return Dialog.chain(hostNameQuery, portQuery).evaluateTo(() -> new Address(hostNameQuery.getResult(), portQuery.getResult())); + } + + public static Dialog machineQuery(DataStore store) { + var storeName = XPipeDaemon.getInstance().getStoreName(store).orElse("local"); + return Dialog.query("Machine", false, true, false, storeName, QueryConverter.STRING).map((String name) -> { + if (name.equals("local")) { + return new LocalStore(); + } + + var stored = XPipeDaemon.getInstance().getNamedStore(name); + if (stored.isEmpty()) { + throw new IllegalArgumentException(String.format("Store not found: %s", name)); + } + + if (!(stored.get() instanceof MachineFileStore)) { + throw new IllegalArgumentException(String.format("Store not a machine store: %s", name)); + } + + return stored.get(); + }); + } + + public static Dialog shellQuery(DataStore store) { + var storeName = XPipeDaemon.getInstance().getStoreName(store).orElse("local"); + return Dialog.query("Shell", false, true, false, storeName, QueryConverter.STRING).map((String name) -> { + if (name.equals("local")) { + return new LocalStore(); + } + + var stored = XPipeDaemon.getInstance().getNamedStore(name); + if (stored.isEmpty()) { + throw new IllegalArgumentException(String.format("Store not found: %s", name)); + } + + if (!(stored.get() instanceof ShellStore)) { + throw new IllegalArgumentException(String.format("Store not a shell store: %s", name)); + } + + return stored.get(); + }); + } + + public static Dialog fileQuery(String name) { + return Dialog.query("File", true, true, false, name, QueryConverter.STRING); + } + + public static Dialog userQuery(String name) { + return Dialog.query("User", false, true, false, name, QueryConverter.STRING); + } + + + public static Dialog passwordQuery(Secret password) { + return Dialog.querySecret("Password", false, true, password); + } + + public static Dialog timeoutQuery(Integer timeout) { + return Dialog.query("Timeout", false, true, false, timeout, QueryConverter.INTEGER); + } + +} diff --git a/extension/src/main/java/io/xpipe/extension/XPipeDaemon.java b/extension/src/main/java/io/xpipe/extension/XPipeDaemon.java new file mode 100644 index 000000000..7cb37308b --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/XPipeDaemon.java @@ -0,0 +1,17 @@ +package io.xpipe.extension; + +import io.xpipe.core.store.DataStore; + +import java.util.Optional; +import java.util.ServiceLoader; + +public interface XPipeDaemon { + + static XPipeDaemon getInstance() { + return ServiceLoader.load(XPipeDaemon.class).findFirst().orElseThrow(); + } + + Optional getNamedStore(String name); + + Optional getStoreName(DataStore store); +} diff --git a/extension/src/main/java/io/xpipe/extension/comp/DynamicOptionsBuilder.java b/extension/src/main/java/io/xpipe/extension/comp/DynamicOptionsBuilder.java index dc2dbfe3a..f7a4bd176 100644 --- a/extension/src/main/java/io/xpipe/extension/comp/DynamicOptionsBuilder.java +++ b/extension/src/main/java/io/xpipe/extension/comp/DynamicOptionsBuilder.java @@ -201,14 +201,7 @@ public class DynamicOptionsBuilder { return this; } - public Comp buildComp() { - if (title != null) { - entries.add(0, new DynamicOptionsComp.Entry(null, Comp.of(() -> new Label(title.getValue())).styleClass("title"))); - } - return new DynamicOptionsComp(entries, wrap); - } - - public Comp buildBindingComp(Supplier> creator, Property toSet) { + public final DynamicOptionsBuilder bindChoice(Supplier> creator, Property toSet) { props.forEach(prop -> { prop.addListener((c,o,n) -> { toSet.unbind(); @@ -216,12 +209,17 @@ public class DynamicOptionsBuilder { }); }); toSet.bind(creator.get()); + return this; + } + + public Comp buildComp() { if (title != null) { entries.add(0, new DynamicOptionsComp.Entry(null, Comp.of(() -> new Label(title.getValue())).styleClass("title"))); } return new DynamicOptionsComp(entries, wrap); } + public Region build() { return buildComp().createRegion(); } diff --git a/extension/src/main/java/module-info.java b/extension/src/main/java/module-info.java index 88594f465..77f1c7138 100644 --- a/extension/src/main/java/module-info.java +++ b/extension/src/main/java/module-info.java @@ -36,4 +36,5 @@ module io.xpipe.extension { uses io.xpipe.extension.event.EventHandler; uses io.xpipe.extension.prefs.PrefsProvider; uses io.xpipe.extension.DataStoreProvider; + uses io.xpipe.extension.XPipeDaemon; } \ No newline at end of file