Add some more store commands, add dialog helpers, and small fixes

This commit is contained in:
Christopher Schnick 2022-08-16 17:49:46 +02:00
parent 775a046e66
commit e0266fec6b
12 changed files with 202 additions and 30 deletions

View file

@ -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;
}
}

View file

@ -13,11 +13,11 @@ import lombok.extern.jackson.Jacksonized;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class ProviderListExchange implements MessageExchange { public class SourceProviderListExchange implements MessageExchange {
@Override @Override
public String getId() { public String getId() {
return "providerList"; return "sourceProviderList";
} }
@Jacksonized @Jacksonized

View file

@ -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<ProviderEntry> entries;
}
}

View file

@ -22,6 +22,8 @@ module io.xpipe.beacon {
uses MessageExchange; uses MessageExchange;
provides io.xpipe.beacon.exchange.MessageExchange with provides io.xpipe.beacon.exchange.MessageExchange with
EditStoreExchange,
StoreProviderListExchange,
ListCollectionsExchange, ListCollectionsExchange,
ListEntriesExchange, ListEntriesExchange,
ModeExchange, ModeExchange,
@ -45,7 +47,7 @@ module io.xpipe.beacon {
RemoveCollectionExchange, RemoveCollectionExchange,
RenameCollectionExchange, RenameCollectionExchange,
RenameEntryExchange, RenameEntryExchange,
ProviderListExchange, SourceProviderListExchange,
ConvertExchange, ConvertExchange,
QueryRawDataExchange, QueryRawDataExchange,
QueryTableDataExchange, QueryTableDataExchange,

View file

@ -6,7 +6,6 @@ import lombok.Value;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/** /**
* A store whose contents are stored in memory. * A store whose contents are stored in memory.
@ -22,10 +21,6 @@ public class InMemoryStore implements StreamDataStore {
this.value = value; this.value = value;
} }
public InMemoryStore(String s) {
value = s.getBytes(StandardCharsets.UTF_8);
}
@Override @Override
public boolean isLocalToApplication() { public boolean isLocalToApplication() {
return true; return true;

View file

@ -9,7 +9,6 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -23,22 +22,19 @@ public class LocalStore extends StandardShellStore implements MachineFileStore {
return true; return true;
} }
static class LocalProcessControl extends ProcessControl { class LocalProcessControl extends ProcessControl {
private final List<Secret> input; private final List<Secret> input;
private final ProcessBuilder builder;
private final Integer timeout; private final Integer timeout;
private final List<String> command;
private Charset charset;
private Process process; private Process process;
LocalProcessControl(List<Secret> input, List<String> cmd, Integer timeout) { LocalProcessControl(List<Secret> input, List<String> cmd, Integer timeout) {
this.input = input; this.input = input;
this.timeout = timeout; this.timeout = timeout;
var l = new ArrayList<String>(); this.command = cmd;
l.add("cmd");
l.add("/c");
l.addAll(cmd);
builder = new ProcessBuilder(l);
} }
private InputStream createInputStream() { private InputStream createInputStream() {
@ -47,8 +43,12 @@ public class LocalStore extends StandardShellStore implements MachineFileStore {
} }
@Override @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(); process = builder.start();
charset = type.getCharset();
var t = new Thread(() -> { var t = new Thread(() -> {
try (var inputStream = createInputStream()){ try (var inputStream = createInputStream()){
@ -84,7 +84,7 @@ public class LocalStore extends StandardShellStore implements MachineFileStore {
@Override @Override
public Charset getCharset() { public Charset getCharset() {
return StandardCharsets.US_ASCII; return charset;
} }
public Integer getTimeout() { public Integer getTimeout() {
@ -126,6 +126,6 @@ public class LocalStore extends StandardShellStore implements MachineFileStore {
@Override @Override
public ShellType determineType() throws Exception { public ShellType determineType() throws Exception {
return ShellTypes.determine(this); return ShellTypes.getDefault();
} }
} }

View file

@ -72,11 +72,13 @@ public interface DataStoreProvider {
return getModuleName() + ":" + getId() + "_icon.png"; return getModuleName() + ":" + getId() + "_icon.png";
} }
default Dialog dialogForString(String s) { DataStore storeForString(String s);
default Dialog dialogForStore(DataStore store) {
return null; return null;
} }
default Dialog defaultDialog() { default DataStore defaultStore() {
throw new ExtensionException("CLI Dialog not implemented by provider"); throw new ExtensionException("CLI Dialog not implemented by provider");
} }

View file

@ -44,7 +44,15 @@ public class DataStoreProviders {
throw new IllegalStateException("Not initialized"); 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();
} }

View file

@ -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);
}
}

View file

@ -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<DataStore> getNamedStore(String name);
Optional<String> getStoreName(DataStore store);
}

View file

@ -201,14 +201,7 @@ public class DynamicOptionsBuilder<T> {
return this; return this;
} }
public <V extends T> Comp<?> buildComp() { public final <V extends T> DynamicOptionsBuilder<T> bindChoice(Supplier<Property<? extends V>> creator, Property<T> toSet) {
if (title != null) {
entries.add(0, new DynamicOptionsComp.Entry(null, Comp.of(() -> new Label(title.getValue())).styleClass("title")));
}
return new DynamicOptionsComp(entries, wrap);
}
public <V extends T> Comp<?> buildBindingComp(Supplier<Property<? extends V>> creator, Property<T> toSet) {
props.forEach(prop -> { props.forEach(prop -> {
prop.addListener((c,o,n) -> { prop.addListener((c,o,n) -> {
toSet.unbind(); toSet.unbind();
@ -216,12 +209,17 @@ public class DynamicOptionsBuilder<T> {
}); });
}); });
toSet.bind(creator.get()); toSet.bind(creator.get());
return this;
}
public Comp<?> buildComp() {
if (title != null) { if (title != null) {
entries.add(0, new DynamicOptionsComp.Entry(null, Comp.of(() -> new Label(title.getValue())).styleClass("title"))); entries.add(0, new DynamicOptionsComp.Entry(null, Comp.of(() -> new Label(title.getValue())).styleClass("title")));
} }
return new DynamicOptionsComp(entries, wrap); return new DynamicOptionsComp(entries, wrap);
} }
public <V extends T> Region build() { public <V extends T> Region build() {
return buildComp().createRegion(); return buildComp().createRegion();
} }

View file

@ -36,4 +36,5 @@ module io.xpipe.extension {
uses io.xpipe.extension.event.EventHandler; uses io.xpipe.extension.event.EventHandler;
uses io.xpipe.extension.prefs.PrefsProvider; uses io.xpipe.extension.prefs.PrefsProvider;
uses io.xpipe.extension.DataStoreProvider; uses io.xpipe.extension.DataStoreProvider;
uses io.xpipe.extension.XPipeDaemon;
} }