mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-22 07:30:24 +00:00
Rework
This commit is contained in:
parent
323ca02a43
commit
4b15af2f17
25 changed files with 133 additions and 37 deletions
|
@ -4,7 +4,7 @@ import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.util.TerminalLauncher;
|
import io.xpipe.app.util.TerminalLauncher;
|
||||||
import io.xpipe.beacon.BeaconClientException;
|
import io.xpipe.beacon.BeaconClientException;
|
||||||
import io.xpipe.beacon.api.ConnectionTerminalExchange;
|
import io.xpipe.beacon.api.ConnectionTerminalExchange;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.xpipe.app.beacon.BeaconShellSession;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.beacon.BeaconClientException;
|
import io.xpipe.beacon.BeaconClientException;
|
||||||
import io.xpipe.beacon.api.ShellStartExchange;
|
import io.xpipe.beacon.api.ShellStartExchange;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
import com.sun.net.httpserver.HttpExchange;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import io.xpipe.app.browser.session.BrowserAbstractSessionModel;
|
||||||
import io.xpipe.app.browser.session.BrowserSessionTab;
|
import io.xpipe.app.browser.session.BrowserSessionTab;
|
||||||
import io.xpipe.app.comp.base.ModalOverlayComp;
|
import io.xpipe.app.comp.base.ModalOverlayComp;
|
||||||
import io.xpipe.app.ext.ProcessControlProvider;
|
import io.xpipe.app.ext.ProcessControlProvider;
|
||||||
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.app.fxcomps.Comp;
|
import io.xpipe.app.fxcomps.Comp;
|
||||||
import io.xpipe.app.issue.ErrorEvent;
|
import io.xpipe.app.issue.ErrorEvent;
|
||||||
import io.xpipe.app.storage.DataStorage;
|
import io.xpipe.app.storage.DataStorage;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.app.util.FileReference;
|
import io.xpipe.app.util.FileReference;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
import io.xpipe.core.store.FileSystemStore;
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.app.util.ThreadHelper;
|
import io.xpipe.app.util.ThreadHelper;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
|
|
@ -4,12 +4,13 @@ import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.process.ShellStoreState;
|
import io.xpipe.core.process.ShellStoreState;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.NetworkTunnelStore;
|
import io.xpipe.core.store.NetworkTunnelStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
|
||||||
import io.xpipe.core.store.StatefulDataStore;
|
import io.xpipe.core.store.StatefulDataStore;
|
||||||
import io.xpipe.core.util.JacksonizedValue;
|
import io.xpipe.core.util.JacksonizedValue;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@JsonTypeName("local")
|
@JsonTypeName("local")
|
||||||
public class LocalStore extends JacksonizedValue
|
public class LocalStore extends JacksonizedValue
|
||||||
implements NetworkTunnelStore, ShellStore, StatefulDataStore<ShellStoreState> {
|
implements NetworkTunnelStore, ShellStore, StatefulDataStore<ShellStoreState> {
|
||||||
|
|
66
app/src/main/java/io/xpipe/app/ext/ShellSession.java
Normal file
66
app/src/main/java/io/xpipe/app/ext/ShellSession.java
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package io.xpipe.app.ext;
|
||||||
|
|
||||||
|
import io.xpipe.core.process.ShellControl;
|
||||||
|
import io.xpipe.core.store.Session;
|
||||||
|
import io.xpipe.core.store.SessionListener;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ShellSession extends Session {
|
||||||
|
|
||||||
|
private final Supplier<ShellControl> supplier;
|
||||||
|
private final ShellControl shellControl;
|
||||||
|
|
||||||
|
public ShellSession(SessionListener listener, Supplier<ShellControl> supplier) {
|
||||||
|
super(listener);
|
||||||
|
this.supplier = supplier;
|
||||||
|
this.shellControl = createControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws Exception {
|
||||||
|
if (shellControl.isRunning()) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
shellControl.start();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
stop();
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShellControl createControl() {
|
||||||
|
var pc = supplier.get();
|
||||||
|
pc.onStartupFail(shellControl -> {
|
||||||
|
listener.onStateChange(false);
|
||||||
|
});
|
||||||
|
pc.onInit(shellControl -> {
|
||||||
|
listener.onStateChange(true);
|
||||||
|
});
|
||||||
|
pc.onKill(() -> {
|
||||||
|
listener.onStateChange(false);
|
||||||
|
});
|
||||||
|
// Listen for parent exit as onExit is called before exit is completed
|
||||||
|
// In case it is stuck, we would not get the right status otherwise
|
||||||
|
pc.getParentControl().ifPresent(p -> {
|
||||||
|
p.onExit(shellControl -> {
|
||||||
|
listener.onStateChange(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return shellControl.isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() throws Exception {
|
||||||
|
shellControl.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,34 @@
|
||||||
package io.xpipe.core.store;
|
package io.xpipe.app.ext;
|
||||||
|
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
|
import io.xpipe.core.store.*;
|
||||||
|
|
||||||
public interface ShellStore extends DataStore, FileSystemStore, ValidatableStore<ShellValidationContext> {
|
public interface ShellStore extends DataStore, FileSystemStore, ValidatableStore<ShellValidationContext>, SingletonSessionStore<ShellSession> {
|
||||||
|
|
||||||
|
default ShellControl getOrStartSession() throws Exception {
|
||||||
|
var session = getSession();
|
||||||
|
if (session != null) {
|
||||||
|
try {
|
||||||
|
session.getShellControl().command("echo hi").execute();
|
||||||
|
return session.getShellControl();
|
||||||
|
} catch (Exception e) {
|
||||||
|
stopSessionIfNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startSessionIfNeeded();
|
||||||
|
return getSession().getShellControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default ShellSession newSession() {
|
||||||
|
return new ShellSession(this, () -> control());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Class<?> getSessionClass() {
|
||||||
|
return ShellSession.class;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default FileSystem createFileSystem() {
|
default FileSystem createFileSystem() {
|
|
@ -12,7 +12,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
|
import io.xpipe.app.util.DataStoreCategoryChoiceComp;
|
||||||
import io.xpipe.core.store.DataStore;
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
|
|
|
@ -14,9 +14,11 @@ public class HostHelper {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException {
|
public static int findRandomOpenPortOnAllLocalInterfaces() {
|
||||||
try (ServerSocket socket = new ServerSocket(0)) {
|
try (ServerSocket socket = new ServerSocket(0)) {
|
||||||
return socket.getLocalPort();
|
return socket.getLocalPort();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return randomPort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.process.ShellStoreState;
|
import io.xpipe.core.process.ShellStoreState;
|
||||||
import io.xpipe.core.process.ShellTtyState;
|
import io.xpipe.core.process.ShellTtyState;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.core.store.ShellValidationContext;
|
import io.xpipe.core.store.ShellValidationContext;
|
||||||
import io.xpipe.core.store.ValidationContext;
|
import io.xpipe.core.store.ValidationContext;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import io.xpipe.app.storage.DataStorage;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.core.store.ShellValidationContext;
|
import io.xpipe.core.store.ShellValidationContext;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.xpipe.core.process;
|
package io.xpipe.core.process;
|
||||||
|
|
||||||
|
import io.xpipe.core.store.DataStore;
|
||||||
import io.xpipe.core.store.FilePath;
|
import io.xpipe.core.store.FilePath;
|
||||||
import io.xpipe.core.store.ShellStore;
|
|
||||||
import io.xpipe.core.store.StatefulDataStore;
|
import io.xpipe.core.store.StatefulDataStore;
|
||||||
import io.xpipe.core.util.FailableConsumer;
|
import io.xpipe.core.util.FailableConsumer;
|
||||||
import io.xpipe.core.util.FailableFunction;
|
import io.xpipe.core.util.FailableFunction;
|
||||||
|
@ -18,6 +18,8 @@ import java.util.function.Function;
|
||||||
|
|
||||||
public interface ShellControl extends ProcessControl {
|
public interface ShellControl extends ProcessControl {
|
||||||
|
|
||||||
|
Optional<ShellControl> getParentControl();
|
||||||
|
|
||||||
ShellTtyState getTtyState();
|
ShellTtyState getTtyState();
|
||||||
|
|
||||||
void setNonInteractive();
|
void setNonInteractive();
|
||||||
|
@ -32,9 +34,9 @@ public interface ShellControl extends ProcessControl {
|
||||||
|
|
||||||
void setWorkingDirectory(WorkingDirectoryFunction workingDirectory);
|
void setWorkingDirectory(WorkingDirectoryFunction workingDirectory);
|
||||||
|
|
||||||
Optional<ShellStore> getSourceStore();
|
Optional<DataStore> getSourceStore();
|
||||||
|
|
||||||
ShellControl withSourceStore(ShellStore store);
|
ShellControl withSourceStore(DataStore store);
|
||||||
|
|
||||||
List<ShellInitCommand> getInitCommands();
|
List<ShellInitCommand> getInitCommands();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ public interface NetworkTunnelStore extends DataStore {
|
||||||
|
|
||||||
interface TunnelFunction {
|
interface TunnelFunction {
|
||||||
|
|
||||||
NetworkTunnelSession create(int localPort, int remotePort);
|
NetworkTunnelSession create(int localPort, int remotePort, String address);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataStore getNetworkParent();
|
DataStore getNetworkParent();
|
||||||
|
@ -57,7 +57,7 @@ public interface NetworkTunnelStore extends DataStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default NetworkTunnelSession sessionChain(int local, int remotePort) throws Exception {
|
default NetworkTunnelSession sessionChain(int local, int remotePort, String address) throws Exception {
|
||||||
if (!isLocallyTunneable()) {
|
if (!isLocallyTunneable()) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Unable to create tunnel chain as one intermediate system does not support tunneling");
|
"Unable to create tunnel chain as one intermediate system does not support tunneling");
|
||||||
|
@ -75,7 +75,7 @@ public interface NetworkTunnelStore extends DataStore {
|
||||||
var currentLocalPort = isLast(current) ? local : randomPort();
|
var currentLocalPort = isLast(current) ? local : randomPort();
|
||||||
var currentRemotePort =
|
var currentRemotePort =
|
||||||
sessions.isEmpty() ? remotePort : sessions.getLast().getLocalPort();
|
sessions.isEmpty() ? remotePort : sessions.getLast().getLocalPort();
|
||||||
var t = func.create(currentLocalPort, currentRemotePort);
|
var t = func.create(currentLocalPort, currentRemotePort, current == this ? address : "localhost");
|
||||||
t.start();
|
t.start();
|
||||||
sessions.add(t);
|
sessions.add(t);
|
||||||
counter.incrementAndGet();
|
counter.incrementAndGet();
|
||||||
|
|
|
@ -38,7 +38,6 @@ public interface SingletonSessionStore<T extends Session>
|
||||||
default void startSessionIfNeeded() throws Exception {
|
default void startSessionIfNeeded() throws Exception {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
var s = getSession();
|
var s = getSession();
|
||||||
setSessionEnabled(true);
|
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
if (s.isRunning()) {
|
if (s.isRunning()) {
|
||||||
return;
|
return;
|
||||||
|
@ -50,9 +49,14 @@ public interface SingletonSessionStore<T extends Session>
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s = newSession();
|
s = newSession();
|
||||||
s.start();
|
if (s != null) {
|
||||||
setCache("session", s);
|
setSessionEnabled(true);
|
||||||
onStateChange(true);
|
s.start();
|
||||||
|
setCache("session", s);
|
||||||
|
onStateChange(true);
|
||||||
|
} else {
|
||||||
|
setSessionEnabled(false);
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
onStateChange(false);
|
onStateChange(false);
|
||||||
throw ex;
|
throw ex;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package io.xpipe.core.util;
|
|
||||||
|
|
||||||
import io.xpipe.core.store.ShellStore;
|
|
||||||
|
|
||||||
public interface Proxyable {
|
|
||||||
|
|
||||||
ShellStore getProxy();
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ import io.xpipe.app.ext.ProcessControlProvider;
|
||||||
import io.xpipe.app.storage.DataStoreEntry;
|
import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.core.store.FileSystemStore;
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.app.util.TerminalLauncher;
|
import io.xpipe.app.util.TerminalLauncher;
|
||||||
import io.xpipe.core.process.ShellStoreState;
|
import io.xpipe.core.process.ShellStoreState;
|
||||||
import io.xpipe.core.process.ShellTtyState;
|
import io.xpipe.core.process.ShellTtyState;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.ext.base.script.ScriptHierarchy;
|
import io.xpipe.ext.base.script.ScriptHierarchy;
|
||||||
|
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import io.xpipe.core.process.CommandControl;
|
||||||
import io.xpipe.core.process.ElevationFunction;
|
import io.xpipe.core.process.ElevationFunction;
|
||||||
import io.xpipe.core.process.ShellControl;
|
import io.xpipe.core.process.ShellControl;
|
||||||
import io.xpipe.core.process.ShellDialects;
|
import io.xpipe.core.process.ShellDialects;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.storage.DataStoreEntryRef;
|
||||||
import io.xpipe.app.util.ScanAlert;
|
import io.xpipe.app.util.ScanAlert;
|
||||||
import io.xpipe.core.process.ShellStoreState;
|
import io.xpipe.core.process.ShellStoreState;
|
||||||
import io.xpipe.core.process.ShellTtyState;
|
import io.xpipe.core.process.ShellTtyState;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
|
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class ChgrpAction implements BranchAction {
|
||||||
.filter(e -> !e.getValue().equals("nohome")
|
.filter(e -> !e.getValue().equals("nohome")
|
||||||
&& !e.getValue().equals("nogroup")
|
&& !e.getValue().equals("nogroup")
|
||||||
&& !e.getValue().equals("nobody")
|
&& !e.getValue().equals("nobody")
|
||||||
&& (e.getKey().equals(0) || e.getKey() >= 1000))
|
&& (e.getKey().equals(0) || e.getKey() >= 900))
|
||||||
.map(e -> e.getValue())
|
.map(e -> e.getValue())
|
||||||
.map(s -> (LeafAction) new Chgrp(s))
|
.map(s -> (LeafAction) new Chgrp(s))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class ChownAction implements BranchAction {
|
||||||
return model.getCache().getUsers().entrySet().stream()
|
return model.getCache().getUsers().entrySet().stream()
|
||||||
.filter(e -> !e.getValue().equals("nohome")
|
.filter(e -> !e.getValue().equals("nohome")
|
||||||
&& !e.getValue().equals("nobody")
|
&& !e.getValue().equals("nobody")
|
||||||
&& (e.getKey().equals(0) || e.getKey() >= 1000))
|
&& (e.getKey().equals(0) || e.getKey() >= 900))
|
||||||
.map(e -> e.getValue())
|
.map(e -> e.getValue())
|
||||||
.map(s -> (LeafAction) new Chown(s))
|
.map(s -> (LeafAction) new Chown(s))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -35,7 +35,7 @@ public abstract class AbstractServiceStore extends JacksonizedValue
|
||||||
public NetworkTunnelSession newSession() throws Exception {
|
public NetworkTunnelSession newSession() throws Exception {
|
||||||
LicenseProvider.get().getFeature("services").throwIfUnsupported();
|
LicenseProvider.get().getFeature("services").throwIfUnsupported();
|
||||||
var l = localPort != null ? localPort : HostHelper.findRandomOpenPortOnAllLocalInterfaces();
|
var l = localPort != null ? localPort : HostHelper.findRandomOpenPortOnAllLocalInterfaces();
|
||||||
return getHost().getStore().sessionChain(l, remotePort);
|
return getHost().getStore().sessionChain(l, remotePort, "localhost");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,7 +16,7 @@ import io.xpipe.app.storage.DataStoreEntry;
|
||||||
import io.xpipe.app.util.DataStoreFormatter;
|
import io.xpipe.app.util.DataStoreFormatter;
|
||||||
import io.xpipe.app.util.TerminalLauncher;
|
import io.xpipe.app.util.TerminalLauncher;
|
||||||
import io.xpipe.core.process.ShellStoreState;
|
import io.xpipe.core.process.ShellStoreState;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.app.ext.ShellStore;
|
||||||
import io.xpipe.ext.base.script.ScriptStore;
|
import io.xpipe.ext.base.script.ScriptStore;
|
||||||
|
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
|
|
@ -389,3 +389,5 @@ vmIdentity=Guest identity
|
||||||
vmIdentityDescription=The SSH identity authentication method to use for connecting if needed
|
vmIdentityDescription=The SSH identity authentication method to use for connecting if needed
|
||||||
vmPort=Port
|
vmPort=Port
|
||||||
vmPortDescription=The port to connect to via SSH
|
vmPortDescription=The port to connect to via SSH
|
||||||
|
forwardAgent=Forward agent
|
||||||
|
forwardAgentDescription=Make SSH agent identities available on the remote system
|
||||||
|
|
Loading…
Reference in a new issue