From 315e8350ebca433b2943204849aa2d5deeb8ec99 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sat, 4 Jan 2025 10:06:52 +0000 Subject: [PATCH] Service fixes --- .../xpipe/app/comp/store/StoreEntryComp.java | 6 +- .../app/comp/store/StoreEntryWrapper.java | 21 +++++++ .../service/AbstractServiceStoreProvider.java | 26 ++++----- .../service/FixedServiceStoreProvider.java | 7 +-- .../service/MappedServiceStoreProvider.java | 57 +++++++++++++++++-- lang/strings/fixed_en.properties | 1 + 6 files changed, 87 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index 2fa4e2af1..840afe045 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -138,11 +138,7 @@ public abstract class StoreEntryComp extends SimpleComp { var loading = LoadingOverlayComp.noProgress( Comp.of(() -> button), - getWrapper().getEntry().getValidity().isUsable() - ? getWrapper() - .getBusy() - .or(getWrapper().getEntry().getProvider().busy(getWrapper())) - : getWrapper().getBusy()); + getWrapper().getEffectiveBusy()); AppFont.normal(button); return loading.createRegion(); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java index 983741383..13d49ceee 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java @@ -14,7 +14,9 @@ import io.xpipe.core.store.DataStore; import io.xpipe.core.store.SingletonSessionStore; import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; import javafx.beans.property.*; +import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableStringValue; import javafx.collections.FXCollections; @@ -54,6 +56,9 @@ public class StoreEntryWrapper { private final Property information = new SimpleStringProperty(); private final BooleanProperty perUser = new SimpleBooleanProperty(); + private boolean effectiveBusyProviderBound = false; + private final BooleanProperty effectiveBusy = new SimpleBooleanProperty(); + public StoreEntryWrapper(DataStoreEntry entry) { this.entry = entry; this.name = new SimpleStringProperty(entry.getName()); @@ -146,6 +151,12 @@ public class StoreEntryWrapper { name.setValue(entry.getName()); } + if (effectiveBusyProviderBound && !getValidity().getValue().isUsable()) { + this.effectiveBusyProviderBound = false; + this.effectiveBusy.unbind(); + this.effectiveBusy.bind(busy); + } + var storeChanged = store.getValue() != entry.getStore(); store.setValue(entry.getStore()); if (storeChanged || !information.isBound()) { @@ -229,6 +240,16 @@ public class StoreEntryWrapper { ErrorEvent.fromThrowable(ex).handle(); } } + + if (!effectiveBusyProviderBound && getValidity().getValue().isUsable()) { + this.effectiveBusyProviderBound = true; + this.effectiveBusy.unbind(); + this.effectiveBusy.bind(busy.or(getEntry().getProvider().busy(this))); + } + + if (!this.effectiveBusy.isBound() && !getValidity().getValue().isUsable()) { + this.effectiveBusy.bind(busy); + } } public boolean showActionProvider(ActionProvider p) { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStoreProvider.java index 06467eb60..03237a526 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/AbstractServiceStoreProvider.java @@ -31,17 +31,6 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt return DataStoreUsageCategory.TUNNEL; } - @Override - public ActionProvider.Action launchAction(DataStoreEntry store) { - return new ActionProvider.Action() { - @Override - public void execute() throws Exception { - AbstractServiceStore s = store.getStore().asNeeded(); - s.startSessionIfNeeded(); - } - }; - } - @Override public DataStoreEntry getSyntheticParent(DataStoreEntry store) { AbstractServiceStore s = store.getStore().asNeeded(); @@ -106,11 +95,7 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt AbstractServiceStore s = section.getWrapper().getEntry().getStore().asNeeded(); return Bindings.createStringBinding( () -> { - var desc = s.getLocalPort() != null - ? "localhost:" + s.getLocalPort() + " <- :" + s.getRemotePort() - : s.isSessionRunning() - ? "localhost:" + s.getSession().getLocalPort() + " <- :" + s.getRemotePort() - : AppI18n.get("remotePort", s.getRemotePort()); + var desc = formatService(s); var type = s.getServiceProtocolType() != null && !(s.getServiceProtocolType() instanceof ServiceProtocolType.None) ? AppI18n.get(s.getServiceProtocolType().getTranslationKey()) @@ -126,6 +111,15 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt AppPrefs.get().language()); } + protected String formatService(AbstractServiceStore s) { + var desc = s.getLocalPort() != null + ? "localhost:" + s.getLocalPort() + " <- :" + s.getRemotePort() + : s.isSessionRunning() + ? "localhost:" + s.getSession().getLocalPort() + " <- :" + s.getRemotePort() + : AppI18n.get("servicePort", s.getRemotePort()); + return desc; + } + @Override public String getDisplayIconFileName(DataStore store) { return "base:service_icon.svg"; diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceStoreProvider.java index 71854e718..c19814983 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/FixedServiceStoreProvider.java @@ -3,6 +3,7 @@ package io.xpipe.ext.base.service; import io.xpipe.app.comp.store.StoreChoiceComp; import io.xpipe.app.comp.store.StoreSection; import io.xpipe.app.comp.store.StoreViewState; +import io.xpipe.app.core.AppI18n; import io.xpipe.app.ext.GuiDialog; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; @@ -36,12 +37,6 @@ public class FixedServiceStoreProvider extends AbstractServiceStoreProvider { return List.of("fixedService"); } - @Override - public ObservableValue informationString(StoreSection section) { - FixedServiceStore s = section.getWrapper().getEntry().getStore().asNeeded(); - return new SimpleStringProperty("Port " + s.getRemotePort()); - } - @Override public List> getStoreClasses() { return List.of(FixedServiceStore.class); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/service/MappedServiceStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/service/MappedServiceStoreProvider.java index 25017f241..69c1d7cc0 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/service/MappedServiceStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/service/MappedServiceStoreProvider.java @@ -1,9 +1,18 @@ package io.xpipe.ext.base.service; +import io.xpipe.app.comp.store.StoreChoiceComp; import io.xpipe.app.comp.store.StoreSection; +import io.xpipe.app.comp.store.StoreViewState; +import io.xpipe.app.core.AppI18n; +import io.xpipe.app.ext.GuiDialog; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; +import io.xpipe.app.util.OptionsBuilder; +import io.xpipe.core.store.DataStore; +import io.xpipe.core.store.NetworkTunnelStore; +import javafx.beans.property.Property; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; @@ -21,14 +30,54 @@ public class MappedServiceStoreProvider extends FixedServiceStoreProvider { return List.of("mappedService"); } - @Override - public ObservableValue informationString(StoreSection section) { - MappedServiceStore s = section.getWrapper().getEntry().getStore().asNeeded(); - return new SimpleStringProperty("Port " + s.getRemotePort() + " -> " + s.getContainerPort()); + protected String formatService(AbstractServiceStore s) { + var m = (MappedServiceStore) s; + var desc = s.getLocalPort() != null + ? "localhost:" + s.getLocalPort() + " <- :" + m.getRemotePort() + " <- :" + m.getContainerPort() + : s.isSessionRunning() + ? "localhost:" + s.getSession().getLocalPort() + " <- :" + m.getRemotePort() + " <- :" + m.getContainerPort() + : ":" + m.getRemotePort() + " <- :" + m.getContainerPort(); + return desc; } @Override public List> getStoreClasses() { return List.of(MappedServiceStore.class); } + + + @Override + public GuiDialog guiDialog(DataStoreEntry entry, Property store) { + MappedServiceStore st = store.getValue().asNeeded(); + var host = new SimpleObjectProperty<>(st.getHost()); + var localPort = new SimpleObjectProperty<>(st.getLocalPort()); + var serviceProtocolType = new SimpleObjectProperty<>(st.getServiceProtocolType()); + var q = new OptionsBuilder() + .nameAndDescription("serviceHost") + .addComp( + StoreChoiceComp.other( + host, + NetworkTunnelStore.class, + n -> n.getStore().isLocallyTunnelable(), + StoreViewState.get().getAllConnectionsCategory()), + host) + .nonNull() + .sub(ServiceProtocolTypeHelper.choice(serviceProtocolType), serviceProtocolType) + .nonNull() + .nameAndDescription("serviceLocalPort") + .addInteger(localPort) + .bind( + () -> { + return MappedServiceStore.builder() + .host(host.get()) + .displayParent(st.getDisplayParent()) + .localPort(localPort.get()) + .remotePort(st.getRemotePort()) + .serviceProtocolType(serviceProtocolType.get()) + .containerPort(st.getContainerPort()) + .build(); + }, + store); + return q.buildDialog(); + } } diff --git a/lang/strings/fixed_en.properties b/lang/strings/fixed_en.properties index 96a0181e3..8eea14e33 100644 --- a/lang/strings/fixed_en.properties +++ b/lang/strings/fixed_en.properties @@ -98,3 +98,4 @@ preview=Preview ghostty=Ghostty http=HTTP https=HTTPS +servicePort=Port $PORT$