mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-23 08:00:56 -04:00
Service rework
This commit is contained in:
@@ -25,7 +25,7 @@ public abstract class AbstractServiceStore implements SingletonSessionStore<Netw
|
||||
|
||||
private final Integer remotePort;
|
||||
private final Integer localPort;
|
||||
private final String path;
|
||||
private final ServiceProtocolType serviceProtocolType;
|
||||
|
||||
public boolean licenseRequired() {
|
||||
return true;
|
||||
@@ -36,6 +36,7 @@ public abstract class AbstractServiceStore implements SingletonSessionStore<Netw
|
||||
Validators.nonNull(getHost());
|
||||
Validators.isType(getHost(), NetworkTunnelStore.class);
|
||||
Validators.nonNull(remotePort);
|
||||
Validators.nonNull(serviceProtocolType);
|
||||
}
|
||||
|
||||
public boolean requiresTunnel() {
|
||||
|
||||
@@ -107,16 +107,18 @@ public abstract class AbstractServiceStoreProvider implements SingletonSessionSt
|
||||
return Bindings.createStringBinding(
|
||||
() -> {
|
||||
var desc = s.getLocalPort() != null
|
||||
? "localhost:" + s.getLocalPort() + " <- " + s.getRemotePort()
|
||||
? "localhost:" + s.getLocalPort() + " <- :" + s.getRemotePort()
|
||||
: s.isSessionRunning()
|
||||
? "localhost:" + s.getSession().getLocalPort() + " <- " + s.getRemotePort()
|
||||
? "localhost:" + s.getSession().getLocalPort() + " <- :" + s.getRemotePort()
|
||||
: AppI18n.get("remotePort", s.getRemotePort());
|
||||
var type = s.getServiceProtocolType() != null && !(s.getServiceProtocolType() instanceof ServiceProtocolType.None) ?
|
||||
AppI18n.get(s.getServiceProtocolType().getTranslationKey()) : null;
|
||||
var state = !s.requiresTunnel()
|
||||
? null
|
||||
: s.isSessionRunning()
|
||||
? AppI18n.get("active")
|
||||
: s.isSessionEnabled() ? AppI18n.get("starting") : AppI18n.get("inactive");
|
||||
return new ShellStoreFormat(null, desc, state).format();
|
||||
return new ShellStoreFormat(null, desc, type, state).format();
|
||||
},
|
||||
section.getWrapper().getCache(),
|
||||
AppPrefs.get().language());
|
||||
|
||||
@@ -11,7 +11,6 @@ import io.xpipe.core.store.NetworkTunnelStore;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -31,10 +30,9 @@ public class CustomServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
CustomServiceStore st = store.getValue().asNeeded();
|
||||
var host = new SimpleObjectProperty<>(st.getHost());
|
||||
var path = new SimpleStringProperty(st.getPath());
|
||||
var localPort = new SimpleObjectProperty<>(st.getLocalPort());
|
||||
var remotePort = new SimpleObjectProperty<>(st.getRemotePort());
|
||||
|
||||
var serviceProtocolType = new SimpleObjectProperty<>(st.getServiceProtocolType());
|
||||
var q = new OptionsBuilder()
|
||||
.nameAndDescription("serviceHost")
|
||||
.addComp(
|
||||
@@ -50,15 +48,15 @@ public class CustomServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
.nonNull()
|
||||
.nameAndDescription("serviceLocalPort")
|
||||
.addInteger(localPort)
|
||||
.nameAndDescription("servicePath")
|
||||
.addString(path)
|
||||
.sub(ServiceProtocolTypeHelper.choice(serviceProtocolType), serviceProtocolType)
|
||||
.nonNull()
|
||||
.bind(
|
||||
() -> {
|
||||
return CustomServiceStore.builder()
|
||||
.host(host.get())
|
||||
.localPort(localPort.get())
|
||||
.remotePort(remotePort.get())
|
||||
.path(path.get())
|
||||
.serviceProtocolType(serviceProtocolType.get())
|
||||
.build();
|
||||
},
|
||||
store);
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
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.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;
|
||||
|
||||
@@ -38,4 +46,39 @@ public class FixedServiceStoreProvider extends AbstractServiceStoreProvider {
|
||||
public List<Class<?>> getStoreClasses() {
|
||||
return List.of(FixedServiceStore.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiDialog guiDialog(DataStoreEntry entry, Property<DataStore> store) {
|
||||
FixedServiceStore 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()
|
||||
.nameAndDescription("serviceLocalPort")
|
||||
.addInteger(localPort)
|
||||
.sub(ServiceProtocolTypeHelper.choice(serviceProtocolType), serviceProtocolType)
|
||||
.nonNull()
|
||||
.bind(
|
||||
() -> {
|
||||
return FixedServiceStore.builder()
|
||||
.host(host.get())
|
||||
.displayParent(st.getDisplayParent())
|
||||
.localPort(localPort.get())
|
||||
.remotePort(st.getRemotePort())
|
||||
.serviceProtocolType(serviceProtocolType.get())
|
||||
.build();
|
||||
},
|
||||
store);
|
||||
return q.buildDialog();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,8 +55,10 @@ public class ServiceCopyUrlAction implements ActionProvider {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
serviceStore.startSessionIfNeeded();
|
||||
var l = serviceStore.getSession().getLocalPort();
|
||||
ClipboardHelper.copyUrl("localhost:" + l);
|
||||
var l = serviceStore.requiresTunnel() ? serviceStore.getSession().getLocalPort() : serviceStore.getRemotePort();
|
||||
var base = "localhost:" + l;
|
||||
var full = serviceStore.getServiceProtocolType().formatUrl(base);
|
||||
ClipboardHelper.copyUrl(full);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,129 +15,32 @@ import java.util.List;
|
||||
public class ServiceOpenAction implements ActionProvider {
|
||||
|
||||
@Override
|
||||
public BranchDataStoreCallSite<?> getBranchDataStoreCallSite() {
|
||||
return new BranchDataStoreCallSite<>() {
|
||||
public DefaultDataStoreCallSite<?> getDefaultDataStoreCallSite() {
|
||||
return new DefaultDataStoreCallSite<AbstractServiceStore>() {
|
||||
@Override
|
||||
public boolean isMajor(DataStoreEntryRef<DataStore> o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<DataStore> store) {
|
||||
return AppI18n.observable("openWebsite");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<DataStore> store) {
|
||||
return "mdi2s-search-web";
|
||||
public ActionProvider.Action createAction(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return new Action(store.getStore());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AbstractServiceStore> getApplicableClass() {
|
||||
return AbstractServiceStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ActionProvider> getChildren(DataStoreEntryRef<DataStore> store) {
|
||||
return List.of(new HttpAction(), new HttpsAction());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class HttpAction implements ActionProvider {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "serviceOpenHttp";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeafDataStoreCallSite<?> getLeafDataStoreCallSite() {
|
||||
return new LeafDataStoreCallSite<AbstractServiceStore>() {
|
||||
|
||||
@Override
|
||||
public boolean canLinkTo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider.Action createAction(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return new ServiceOpenAction.Action("http", store.getStore());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AbstractServiceStore> getApplicableClass() {
|
||||
return AbstractServiceStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return AppI18n.observable("openHttp");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return "mdi2s-shield-off-outline";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class HttpsAction implements ActionProvider {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "serviceOpenHttps";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeafDataStoreCallSite<?> getLeafDataStoreCallSite() {
|
||||
return new LeafDataStoreCallSite<AbstractServiceStore>() {
|
||||
|
||||
@Override
|
||||
public boolean canLinkTo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider.Action createAction(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return new ServiceOpenAction.Action("https", store.getStore());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AbstractServiceStore> getApplicableClass() {
|
||||
return AbstractServiceStore.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObservableValue<String> getName(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return AppI18n.observable("openHttps");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(DataStoreEntryRef<AbstractServiceStore> store) {
|
||||
return "mdi2s-shield-lock-outline";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
static class Action implements ActionProvider.Action {
|
||||
|
||||
String protocol;
|
||||
AbstractServiceStore serviceStore;
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
serviceStore.startSessionIfNeeded();
|
||||
var l = serviceStore.getSession().getLocalPort();
|
||||
var path =
|
||||
serviceStore.getPath() != null && !serviceStore.getPath().isEmpty() ? serviceStore.getPath() : "";
|
||||
if (!path.isEmpty() && !path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
Hyperlinks.open(protocol + "://localhost:" + l + path);
|
||||
var l = serviceStore.requiresTunnel() ? serviceStore.getSession().getLocalPort() : serviceStore.getRemotePort();
|
||||
var base = "localhost:" + l;
|
||||
var full = serviceStore.getServiceProtocolType().formatUrl(base);
|
||||
serviceStore.getServiceProtocolType().open(full);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package io.xpipe.ext.base.service;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.ext.base.identity.SshIdentityStrategy;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ServiceProtocolType.None.class),
|
||||
@JsonSubTypes.Type(value = ServiceProtocolType.Http.class),
|
||||
@JsonSubTypes.Type(value = ServiceProtocolType.Https.class)
|
||||
})
|
||||
public interface ServiceProtocolType {
|
||||
|
||||
public abstract String formatUrl(String base);
|
||||
|
||||
public abstract void open(String url);
|
||||
|
||||
public abstract String getTranslationKey();
|
||||
|
||||
|
||||
@JsonTypeName("none")
|
||||
@Value
|
||||
@Jacksonized
|
||||
@Builder
|
||||
public static class None implements ServiceProtocolType {
|
||||
|
||||
@Override
|
||||
public String formatUrl(String base) {
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(String url) {}
|
||||
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
return "none";
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("http")
|
||||
@Value
|
||||
@Jacksonized
|
||||
@Builder
|
||||
public static class Http implements ServiceProtocolType {
|
||||
|
||||
String path;
|
||||
|
||||
@Override
|
||||
public String formatUrl(String base) {
|
||||
var url = "http://" + base;
|
||||
if (path != null && !path.isEmpty()) {
|
||||
url += (!path.startsWith("/") ? "/" : "") + path;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(String url) {
|
||||
Hyperlinks.open(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
return "http";
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("https")
|
||||
@Value
|
||||
@Jacksonized
|
||||
@Builder
|
||||
public static class Https implements ServiceProtocolType {
|
||||
|
||||
String path;
|
||||
|
||||
@Override
|
||||
public String formatUrl(String base) {
|
||||
var url = "https://" + base;
|
||||
if (path != null && !path.isEmpty()) {
|
||||
url += (!path.startsWith("/") ? "/" : "") + path;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(String url) {
|
||||
Hyperlinks.open(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
return "https";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.xpipe.ext.base.service;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class ServiceProtocolTypeHelper {
|
||||
|
||||
private static OptionsBuilder http(Property<ServiceProtocolType.Http> p) {
|
||||
var path = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPath() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("servicePath")
|
||||
.addString(path)
|
||||
.bind(
|
||||
() -> {
|
||||
return new ServiceProtocolType.Http(path.get());
|
||||
},
|
||||
p);
|
||||
}
|
||||
|
||||
private static OptionsBuilder https(Property<ServiceProtocolType.Https> p) {
|
||||
var path = new SimpleStringProperty(p.getValue() != null ? p.getValue().getPath() : null);
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("servicePath")
|
||||
.addString(path)
|
||||
.bind(
|
||||
() -> {
|
||||
return new ServiceProtocolType.Https(path.get());
|
||||
},
|
||||
p);
|
||||
}
|
||||
|
||||
public static OptionsBuilder choice(Property<ServiceProtocolType> serviceProtocolType) {
|
||||
var ex = serviceProtocolType.getValue();
|
||||
var http = new SimpleObjectProperty<>(ex instanceof ServiceProtocolType.Http h ? h : null);
|
||||
var https = new SimpleObjectProperty<>(ex instanceof ServiceProtocolType.Https h ? h : null);
|
||||
var selected = new SimpleIntegerProperty(ex instanceof ServiceProtocolType.None ? 0 :
|
||||
ex instanceof ServiceProtocolType.Http ? 1 : ex instanceof ServiceProtocolType.Https ? 2 : -1);
|
||||
var available = new LinkedHashMap<ObservableValue<String>, OptionsBuilder>();
|
||||
available.put(AppI18n.observable("none"), new OptionsBuilder());
|
||||
available.put(AppI18n.observable("http"), http(http));
|
||||
available.put(AppI18n.observable("https"), https(https));
|
||||
return new OptionsBuilder()
|
||||
.nameAndDescription("serviceProtocolType")
|
||||
.choice(selected, available)
|
||||
.bindChoice(() -> {
|
||||
return switch (selected.get()) {
|
||||
case 0 -> new SimpleObjectProperty<>(new ServiceProtocolType.None());
|
||||
case 1 -> http;
|
||||
case 2 -> https;
|
||||
default -> new SimpleObjectProperty<>();
|
||||
};
|
||||
}, serviceProtocolType);
|
||||
}
|
||||
}
|
||||
@@ -1267,3 +1267,7 @@ updateNag=You haven't updated XPipe in a while. You might be missing out on new
|
||||
updateNagTitle=Update reminder
|
||||
updateNagButton=See releases
|
||||
refreshServices=Refresh services
|
||||
serviceProtocolType=Service protocol type
|
||||
serviceProtocolTypeDescription=The protocol to use to open the service
|
||||
http=HTTP
|
||||
https=HTTPS
|
||||
|
||||
Reference in New Issue
Block a user