mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-05-04 11:50:44 +00:00
Rework for host hierarchies
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
package io.xpipe.app.ext;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface HostAddressStore extends DataStore {
|
||||
|
||||
HostAddress getHostAddress();
|
||||
}
|
||||
@@ -673,14 +673,19 @@ public class DataStoreEntry extends StorageElement {
|
||||
return;
|
||||
}
|
||||
|
||||
var newComplete = newStore.isComplete();
|
||||
if (!newComplete) {
|
||||
var changed = !Objects.equals(store, newStore) || validity != Validity.INCOMPLETE;
|
||||
validity = Validity.INCOMPLETE;
|
||||
store = newStore;
|
||||
if (changed) {
|
||||
notifyUpdate(false, false);
|
||||
try {
|
||||
var newComplete = newStore.isComplete();
|
||||
if (!newComplete) {
|
||||
var changed = !Objects.equals(store, newStore) || validity != Validity.INCOMPLETE;
|
||||
validity = Validity.INCOMPLETE;
|
||||
store = newStore;
|
||||
if (changed) {
|
||||
notifyUpdate(false, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorEventFactory.fromThrowable(e).handle();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,6 @@ open module io.xpipe.app {
|
||||
provides ActionProvider with
|
||||
SetupToolActionProvider,
|
||||
XPipeUrlProvider,
|
||||
HostAddressSwitchBranchProvider,
|
||||
OpenHubMenuLeafProvider,
|
||||
EditHubLeafProvider,
|
||||
CloneHubLeafProvider,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.hub.action.HubLeafProvider;
|
||||
import io.xpipe.app.hub.action.StoreAction;
|
||||
import io.xpipe.app.hub.comp.StoreViewState;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
public class AbstractHostCreationActionProvider implements HubLeafProvider<AbstractHostTransformStore> {
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<AbstractHostTransformStore> store) {
|
||||
return AppI18n.observable("abstractHostConvert");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelGraphic getIcon(DataStoreEntryRef<AbstractHostTransformStore> store) {
|
||||
return new LabelGraphic.IconGraphic("mdi2c-cog-transfer-outline");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getApplicableClass() {
|
||||
return AbstractHostTransformStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(DataStoreEntryRef<AbstractHostTransformStore> o) {
|
||||
return o.getStore().canConvertToAbstractHost();
|
||||
}
|
||||
|
||||
@Jacksonized
|
||||
@SuperBuilder
|
||||
public static class Action extends StoreAction<AbstractHostTransformStore> {
|
||||
|
||||
@Override
|
||||
public void executeImpl() throws Exception {
|
||||
var d = ref.getStore();
|
||||
var ah = d.createAbstractHostStore();
|
||||
var entry = DataStorage.get().addStoreIfNotPresent(ref.get().getName(), ah);
|
||||
entry.setExpanded(true);
|
||||
var newStore = d.withNewParent(entry.ref());
|
||||
DataStorage.get().updateEntryStore(ref.get(), newStore);
|
||||
entry.setChildrenCache(null);
|
||||
StoreViewState.get().triggerStoreListUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -1,10 +1,9 @@
|
||||
package io.xpipe.ext.base.store;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.ext.*;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.Validators;
|
||||
import io.xpipe.ext.base.identity.IdentityValue;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
@@ -15,9 +14,10 @@ import lombok.extern.jackson.Jacksonized;
|
||||
@SuperBuilder
|
||||
@Jacksonized
|
||||
@JsonTypeName("abstractHost")
|
||||
public class AbstractHostStore implements DataStore, HostAddressStore {
|
||||
public class AbstractHostStore implements DataStore, HostAddressStore, HostAddressGatewayStore {
|
||||
|
||||
String host;
|
||||
DataStoreEntryRef<NetworkTunnelStore> gateway;
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
@@ -28,4 +28,9 @@ public class AbstractHostStore implements DataStore, HostAddressStore {
|
||||
public HostAddress getHostAddress() {
|
||||
return HostAddress.of(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreEntryRef<NetworkTunnelStore> getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
}
|
||||
+34
-3
@@ -1,14 +1,15 @@
|
||||
package io.xpipe.ext.base.store;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.*;
|
||||
import io.xpipe.app.hub.comp.*;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@@ -36,16 +37,46 @@ public class AbstractHostStoreProvider implements DataStoreProvider {
|
||||
return DataStoreUsageCategory.GROUP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> informationString(StoreSection section) {
|
||||
return Bindings.createStringBinding(
|
||||
() -> {
|
||||
var all = section.getAllChildren().getList();
|
||||
var shown = section.getShownChildren().getList();
|
||||
if (shown.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var string = all.size() == shown.size() ? all.size() : shown.size() + "/" + all.size();
|
||||
return all.size() > 0
|
||||
? (all.size() == 1 ? AppI18n.get("abstractHostHasConnection", string) : AppI18n.get("abstractHostHasConnections", string))
|
||||
: AppI18n.get("abstractHostNoConnections");
|
||||
},
|
||||
section.getShownChildren().getList(),
|
||||
section.getAllChildren().getList(),
|
||||
AppI18n.activeLanguage());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
AbstractHostStore st = store.getValue().asNeeded();
|
||||
|
||||
Property<String> host = new SimpleObjectProperty<>(st.getHost());
|
||||
var host = new SimpleObjectProperty<>(st.getHost());
|
||||
var gateway = new SimpleObjectProperty<>(st.getGateway());
|
||||
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("abstractHostAddress")
|
||||
.addString(host)
|
||||
.nonNull()
|
||||
.nameAndDescription("abstractHostGateway")
|
||||
.addComp(new StoreChoiceComp<>(StoreChoiceComp.Mode.PROXY,
|
||||
entry,
|
||||
gateway,
|
||||
NetworkTunnelStore.class,
|
||||
ref -> true,
|
||||
StoreViewState.get().getAllConnectionsCategory()
|
||||
), gateway)
|
||||
.bind(
|
||||
() -> {
|
||||
return AbstractHostStore.builder()
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
|
||||
public interface AbstractHostTransformStore extends DataStore {
|
||||
|
||||
boolean canConvertToAbstractHost();
|
||||
|
||||
AbstractHostStore createAbstractHostStore();
|
||||
|
||||
AbstractHostTransformStore withNewParent(DataStoreEntryRef<AbstractHostStore> newParent);
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.ext;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.HostAddress;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.xpipe.app.ext;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.CompStructure;
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
|
||||
public interface HostAddressGatewayStore extends HostAddressStore {
|
||||
|
||||
DataStoreEntryRef<NetworkTunnelStore> getGateway();
|
||||
}
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package io.xpipe.ext.base.store;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.HostAddressStore;
|
||||
import io.xpipe.ext.base.identity.IdentityValue;
|
||||
|
||||
public interface HostAddressIdentityStore extends HostAddressStore {
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.HostAddress;
|
||||
|
||||
public interface HostAddressStore extends DataStore {
|
||||
|
||||
HostAddress getHostAddress();
|
||||
}
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package io.xpipe.app.hub.action.impl;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.HostAddressSwitchStore;
|
||||
import io.xpipe.app.hub.action.HubBranchProvider;
|
||||
import io.xpipe.app.hub.action.HubLeafProvider;
|
||||
import io.xpipe.app.hub.action.HubMenuItemProvider;
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
package io.xpipe.app.ext;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.HostAddress;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
package io.xpipe.app.ext;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
|
||||
public interface HostAddressTunnelStore extends HostAddressStore, NetworkTunnelStore {
|
||||
|
||||
+2
-4
@@ -1,12 +1,10 @@
|
||||
package io.xpipe.ext.base.store;
|
||||
package io.xpipe.ext.base.host;
|
||||
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.HostAddress;
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
import io.xpipe.app.ext.ShellStore;
|
||||
import io.xpipe.ext.base.identity.IdentityValue;
|
||||
|
||||
public interface HostStore extends DataStore, ShellStore, NetworkTunnelStore {
|
||||
public interface HostStore extends DataStore {
|
||||
|
||||
HostAddress getHostAddress();
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.DataStoreProvider;
|
||||
import io.xpipe.app.ext.DataStoreUsageCategory;
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
import io.xpipe.app.hub.comp.*;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
|
||||
@@ -15,42 +15,15 @@ import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@SuperBuilder
|
||||
@SuperBuilder(toBuilder = true)
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public abstract class AbstractServiceStore implements SingletonSessionStore<NetworkTunnelSession>, DataStore {
|
||||
|
||||
private final Integer remotePort;
|
||||
private final Integer localPort;
|
||||
private final ServiceProtocolType serviceProtocolType;
|
||||
|
||||
public abstract DataStoreEntryRef<NetworkTunnelStore> getHost();
|
||||
|
||||
public boolean licenseRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
Validators.nonNull(getHost());
|
||||
NetworkTunnelStore.checkTunnelable(getHost());
|
||||
Validators.nonNull(remotePort);
|
||||
Validators.nonNull(serviceProtocolType);
|
||||
}
|
||||
|
||||
public String getOpenTargetUrl() {
|
||||
return ServiceAddressRotation.getRotatedAddress(this);
|
||||
}
|
||||
|
||||
public boolean requiresTunnel() {
|
||||
if (getHost() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getHost().getStore().isLocallyTunnelable()) {
|
||||
var parent = getHost().getStore().getNetworkParent();
|
||||
public static boolean requiresTunnel(NetworkTunnelStore t) {
|
||||
if (!t.isLocallyTunnelable()) {
|
||||
var parent = t.getNetworkParent();
|
||||
if (!(parent instanceof NetworkTunnelStore nts)) {
|
||||
return false;
|
||||
}
|
||||
@@ -58,11 +31,78 @@ public abstract class AbstractServiceStore implements SingletonSessionStore<Netw
|
||||
return nts.requiresTunnel();
|
||||
}
|
||||
|
||||
return getHost().getStore().requiresTunnel();
|
||||
return t.requiresTunnel();
|
||||
}
|
||||
|
||||
public static boolean requiresManualAddress(DataStore s) {
|
||||
if (!(s instanceof NetworkTunnelStore t)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!t.isLocallyTunnelable()) {
|
||||
var parent = t.getNetworkParent();
|
||||
if (!(parent instanceof NetworkTunnelStore nts)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nts.requiresTunnel();
|
||||
}
|
||||
|
||||
return t.requiresTunnel();
|
||||
}
|
||||
|
||||
private final Integer remotePort;
|
||||
private final Integer localPort;
|
||||
private final ServiceProtocolType serviceProtocolType;
|
||||
|
||||
public abstract String getAddress();
|
||||
|
||||
public abstract DataStoreEntryRef<NetworkTunnelStore> getGateway();
|
||||
|
||||
public abstract DataStoreEntryRef<?> getHost();
|
||||
|
||||
public boolean licenseRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkComplete() throws Throwable {
|
||||
Validators.nonNull(remotePort);
|
||||
Validators.nonNull(serviceProtocolType);
|
||||
if (getHost() != null) {
|
||||
getHost().checkComplete();
|
||||
} else {
|
||||
Validators.nonNull(getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
public String getOpenTargetUrl() {
|
||||
return ServiceAddressRotation.getRotatedAddress(this);
|
||||
}
|
||||
|
||||
public boolean requiresTunnel() {
|
||||
if (getHost() == null || !(getHost().getStore() instanceof NetworkTunnelStore t)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!t.isLocallyTunnelable()) {
|
||||
var parent = t.getNetworkParent();
|
||||
if (!(parent instanceof NetworkTunnelStore nts)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nts.requiresTunnel();
|
||||
}
|
||||
|
||||
return t.requiresTunnel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkTunnelSession newSession() {
|
||||
if (!(getHost().getStore() instanceof NetworkTunnelStore t)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var f = LicenseProvider.get().getFeature("services");
|
||||
if (licenseRequired() && !f.isSupported()) {
|
||||
var active = DataStorage.get().getStoreEntries().stream()
|
||||
@@ -78,13 +118,13 @@ public abstract class AbstractServiceStore implements SingletonSessionStore<Netw
|
||||
|
||||
var l = localPort != null ? localPort : HostHelper.findRandomOpenPortOnAllLocalInterfaces();
|
||||
|
||||
var parent = getHost().getStore().getNetworkParent();
|
||||
if (!getHost().getStore().isLocallyTunnelable() && parent instanceof NetworkTunnelStore nts) {
|
||||
var parent = t.getNetworkParent();
|
||||
if (!t.isLocallyTunnelable() && parent instanceof NetworkTunnelStore nts) {
|
||||
return nts.createTunnelSession(
|
||||
l, remotePort, nts.getTunnelHostName() != null ? nts.getTunnelHostName() : "localhost");
|
||||
}
|
||||
|
||||
return getHost().getStore().createTunnelSession(l, remotePort, "localhost");
|
||||
return t.createTunnelSession(l, remotePort, "localhost");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,9 +30,18 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt
|
||||
@Override
|
||||
public boolean supportsSession(SingletonSessionStore<?> s) {
|
||||
var abs = (AbstractServiceStore) s;
|
||||
return abs.getHost() == null
|
||||
|| !abs.getHost().getStore().requiresTunnel()
|
||||
|| !abs.getHost().getStore().isLocallyTunnelable();
|
||||
if (abs.getHost() != null && (!(abs.getHost().getStore() instanceof NetworkTunnelStore t)
|
||||
|| !t.requiresTunnel()
|
||||
|| !t.isLocallyTunnelable())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (abs.getHost() == null && (abs.getGateway() == null ||
|
||||
!abs.getGateway().getStore().isLocallyTunnelable() || !abs.getGateway().getStore().requiresTunnel())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,22 +1,44 @@
|
||||
package io.xpipe.ext.base.service;
|
||||
|
||||
import io.xpipe.app.ext.DataStore;
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.ext.base.host.AbstractHostStore;
|
||||
import io.xpipe.ext.base.host.AbstractHostTransformStore;
|
||||
import io.xpipe.ext.base.host.HostAddressStore;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@SuperBuilder
|
||||
@SuperBuilder(toBuilder = true)
|
||||
@Getter
|
||||
@Jacksonized
|
||||
@JsonTypeName("customService")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public final class CustomServiceStore extends AbstractServiceStore {
|
||||
public final class CustomServiceStore extends AbstractServiceStore implements AbstractHostTransformStore {
|
||||
|
||||
private final DataStoreEntryRef<NetworkTunnelStore> host;
|
||||
private final DataStoreEntryRef<HostAddressStore> host;
|
||||
private final String address;
|
||||
private final DataStoreEntryRef<NetworkTunnelStore> gateway;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canConvertToAbstractHost() {
|
||||
return host == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractHostStore createAbstractHostStore() {
|
||||
return AbstractHostStore.builder().host(address).gateway(gateway).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractHostTransformStore withNewParent(DataStoreEntryRef<AbstractHostStore> newParent) {
|
||||
return toBuilder().address(null).gateway(null).host(newParent.asNeeded()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,44 @@ import io.xpipe.app.ext.DataStoreCreationCategory;
|
||||
import io.xpipe.app.ext.GuiDialog;
|
||||
import io.xpipe.app.ext.NetworkTunnelStore;
|
||||
import io.xpipe.app.hub.comp.StoreChoiceComp;
|
||||
import io.xpipe.app.hub.comp.StoreComboChoiceComp;
|
||||
import io.xpipe.app.hub.comp.StoreViewState;
|
||||
import io.xpipe.app.platform.BindingsHelper;
|
||||
import io.xpipe.app.platform.OptionsBuilder;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
|
||||
import io.xpipe.ext.base.host.AbstractHostStore;
|
||||
import io.xpipe.ext.base.host.HostAddressStore;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
|
||||
@Override
|
||||
public DataStoreEntry getSyntheticParent(DataStoreEntry store) {
|
||||
var c = (CustomServiceStore) store.getStore();
|
||||
if (c.getHost() == null || c.getHost().getStore() instanceof AbstractHostStore) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.getSyntheticParent(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreEntry getDisplayParent(DataStoreEntry store) {
|
||||
var c = (CustomServiceStore) store.getStore();
|
||||
if (c.getHost() != null && c.getHost().getStore() instanceof AbstractHostStore) {
|
||||
return c.getHost().get();
|
||||
}
|
||||
|
||||
return super.getDisplayParent(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrderPriority() {
|
||||
return -1;
|
||||
@@ -30,20 +56,42 @@ public class CustomServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
@Override
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
CustomServiceStore st = store.getValue().asNeeded();
|
||||
var host = new SimpleObjectProperty<>(st.getHost());
|
||||
|
||||
var comboHost = new SimpleObjectProperty<>(StoreComboChoiceComp.ComboValue.of(
|
||||
st.getAddress(),
|
||||
st.getHost()
|
||||
));
|
||||
var gateway = new SimpleObjectProperty<>(st.getGateway());
|
||||
var hideGateway = BindingsHelper.map(comboHost, c -> c == null || c.getRef() != null);
|
||||
|
||||
var localPort = new SimpleObjectProperty<>(st.getLocalPort());
|
||||
var remotePort = new SimpleObjectProperty<>(st.getRemotePort());
|
||||
var serviceProtocolType = new SimpleObjectProperty<>(st.getServiceProtocolType());
|
||||
|
||||
var hostChoice = new StoreComboChoiceComp<>(
|
||||
hostStore -> hostStore.getHostAddress().get(),
|
||||
entry,
|
||||
comboHost,
|
||||
NetworkTunnelStore.class,
|
||||
n -> n.getStore() instanceof AbstractHostStore ||
|
||||
(n.getStore() instanceof NetworkTunnelStore t && t.isLocallyTunnelable()),
|
||||
StoreViewState.get().getAllConnectionsCategory()
|
||||
);
|
||||
var gatewayChoice = new StoreChoiceComp<>(
|
||||
StoreChoiceComp.Mode.PROXY,
|
||||
entry,
|
||||
gateway,
|
||||
NetworkTunnelStore.class,
|
||||
ref -> !ref.get().equals(DataStorage.get().local()),
|
||||
StoreViewState.get().getAllConnectionsCategory());
|
||||
|
||||
var q = new OptionsBuilder()
|
||||
.nameAndDescription("serviceHost")
|
||||
.addComp(
|
||||
StoreChoiceComp.other(
|
||||
host,
|
||||
NetworkTunnelStore.class,
|
||||
n -> n.getStore().isLocallyTunnelable(),
|
||||
StoreViewState.get().getAllConnectionsCategory()),
|
||||
host)
|
||||
.addComp(hostChoice, comboHost)
|
||||
.nonNull()
|
||||
.nameAndDescription("gateway")
|
||||
.addComp(gatewayChoice, gateway)
|
||||
.hide(hideGateway)
|
||||
.nameAndDescription("serviceRemotePort")
|
||||
.addInteger(remotePort)
|
||||
.nonNull()
|
||||
@@ -54,7 +102,9 @@ public class CustomServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
.bind(
|
||||
() -> {
|
||||
return CustomServiceStore.builder()
|
||||
.host(host.get())
|
||||
.address(comboHost.get() != null ? comboHost.get().getManualHost() : null)
|
||||
.host(comboHost.get() != null ? comboHost.get().getRef() : null)
|
||||
.gateway(gateway.get())
|
||||
.localPort(localPort.get())
|
||||
.remotePort(remotePort.get())
|
||||
.serviceProtocolType(serviceProtocolType.get())
|
||||
|
||||
@@ -26,6 +26,16 @@ public class FixedServiceStore extends AbstractServiceStore implements FixedChil
|
||||
private final DataStoreEntryRef<NetworkTunnelStore> host;
|
||||
private final DataStoreEntryRef<? extends DataStore> displayParent;
|
||||
|
||||
@Override
|
||||
public String getAddress() {
|
||||
return "localhost";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreEntryRef<NetworkTunnelStore> getGateway() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStoreEntryRef<NetworkTunnelStore> getHost() {
|
||||
return host;
|
||||
|
||||
@@ -27,10 +27,11 @@ public class ServiceAddressRotation {
|
||||
public static String getRotatedAddress(AbstractServiceStore serviceStore) {
|
||||
var s = serviceStore.getSession();
|
||||
if (s == null) {
|
||||
var host = serviceStore.getHost().getStore().getTunnelHostName() != null
|
||||
? serviceStore.getHost().getStore().getTunnelHostName()
|
||||
: "localhost";
|
||||
return getRotatedLocalhost(host + ":" + serviceStore.getRemotePort());
|
||||
var address = serviceStore.getAddress();
|
||||
if (address == null) {
|
||||
address = "localhost";
|
||||
}
|
||||
return getRotatedLocalhost(address + ":" + serviceStore.getRemotePort());
|
||||
}
|
||||
|
||||
return getRotatedLocalhost("localhost:" + s.getLocalPort());
|
||||
|
||||
@@ -2,6 +2,9 @@ import io.xpipe.app.action.ActionProvider;
|
||||
import io.xpipe.app.ext.DataStorageExtensionProvider;
|
||||
import io.xpipe.app.ext.DataStoreProvider;
|
||||
import io.xpipe.ext.base.desktop.DesktopApplicationStoreProvider;
|
||||
import io.xpipe.ext.base.host.AbstractHostCreationActionProvider;
|
||||
import io.xpipe.ext.base.host.AbstractHostStoreProvider;
|
||||
import io.xpipe.ext.base.host.HostAddressSwitchBranchProvider;
|
||||
import io.xpipe.ext.base.identity.*;
|
||||
import io.xpipe.ext.base.script.*;
|
||||
import io.xpipe.ext.base.service.*;
|
||||
@@ -14,6 +17,7 @@ open module io.xpipe.ext.base {
|
||||
exports io.xpipe.ext.base.service;
|
||||
exports io.xpipe.ext.base.identity;
|
||||
exports io.xpipe.ext.base.identity.ssh;
|
||||
exports io.xpipe.ext.base.host;
|
||||
|
||||
requires java.desktop;
|
||||
requires io.xpipe.core;
|
||||
@@ -28,8 +32,11 @@ open module io.xpipe.ext.base {
|
||||
requires atlantafx.base;
|
||||
requires com.sun.jna.platform;
|
||||
requires com.sun.jna;
|
||||
requires javafx.base;
|
||||
|
||||
provides ActionProvider with
|
||||
AbstractHostCreationActionProvider,
|
||||
HostAddressSwitchBranchProvider,
|
||||
LocalIdentityConvertHubLeafProvider,
|
||||
RunBackgroundScriptActionProvider,
|
||||
RunHubBatchScriptActionProvider,
|
||||
|
||||
Generated
+9
-2
@@ -726,7 +726,7 @@ serviceLocalPortDescription=The local port to forward to, otherwise a random one
|
||||
serviceRemotePort=Remote port
|
||||
serviceRemotePortDescription=The port on which the service is running on
|
||||
serviceHost=Service host
|
||||
serviceHostDescription=The host the service is running on
|
||||
serviceHostDescription=The host entry or manual address of the server on which the service is running on
|
||||
openWebsite=Open website
|
||||
customServiceGroup.displayName=Service group
|
||||
customServiceGroup.displayDescription=Group multiple services into one category
|
||||
@@ -741,7 +741,8 @@ fixedServiceGroup.displayDescription=List the available services on a system
|
||||
mappedService.displayName=Service
|
||||
mappedService.displayDescription=Interact with a service exposed by a container
|
||||
customService.displayName=Service
|
||||
customService.displayDescription=Automatically tunnel a remote service port to your local machine
|
||||
#force
|
||||
customService.displayDescription=Automatically open or tunnel a remote service port on your local machine
|
||||
fixedService.displayName=Service
|
||||
fixedService.displayDescription=Use a predefined service
|
||||
noServices=No available services
|
||||
@@ -1665,5 +1666,11 @@ abstractHost.displayName=Abstract host
|
||||
abstractHost.displayDescription=Create an entry for a host that does not support shell connections
|
||||
abstractHostAddress=Host address
|
||||
abstractHostAddressDescription=The address of the host
|
||||
abstractHostGateway=Gateway
|
||||
abstractHostGatewayDescription=The optional gateway system through which to reach this host
|
||||
abstractHostConvert=Convert to abstract host
|
||||
abstractHostNoConnections=No available connections
|
||||
abstractHostHasConnections=$COUNT$ available connections
|
||||
abstractHostHasConnection=$COUNT$ available connection
|
||||
largeFileWarningTitle=Large file edit
|
||||
largeFileWarningContent=The file you want to edit is quite large with $SIZE$. Do you really want to open this file in your text editor?
|
||||
|
||||
Reference in New Issue
Block a user