diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java index 0a77aa76..6d0c2784 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java @@ -197,7 +197,7 @@ public final class BrowserFileListComp extends SimpleComp { unix.getUid() != null ? unix.getUid() : m.getCache().getUidForUser(user)); var gid = String.valueOf( unix.getGid() != null ? unix.getGid() : m.getCache().getGidForGroup(group)); - if (uid.equals(gid)) { + if (uid.equals(gid) && user.equals(group)) { return user + " [" + uid + "]"; } return user + " [" + uid + "] / " + group + " [" + gid + "]"; diff --git a/app/src/main/java/io/xpipe/app/core/check/AppBundledToolsCheck.java b/app/src/main/java/io/xpipe/app/core/check/AppBundledToolsCheck.java new file mode 100644 index 00000000..57aefbca --- /dev/null +++ b/app/src/main/java/io/xpipe/app/core/check/AppBundledToolsCheck.java @@ -0,0 +1,34 @@ +package io.xpipe.app.core.check; + +import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.core.process.OsType; + +import java.util.concurrent.TimeUnit; + +public class AppBundledToolsCheck { + + private static boolean getResult() { + var fc = new ProcessBuilder("where", "ssh").redirectErrorStream(true).redirectOutput(ProcessBuilder.Redirect.DISCARD); + try { + var proc = fc.start(); + proc.waitFor(2, TimeUnit.SECONDS); + return proc.exitValue() == 0; + } catch (Exception e) { + return false; + } + } + + public static void check() { + if (AppPrefs.get().useBundledTools().get()) { + return; + } + + if (!OsType.getLocal().equals(OsType.WINDOWS)) { + return; + } + + if (!getResult()) { + AppPrefs.get().useBundledTools.set(true); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index 6f2f6658..79be0a3a 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -5,10 +5,7 @@ import io.xpipe.app.beacon.BlobManager; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.*; -import io.xpipe.app.core.check.AppAvCheck; -import io.xpipe.app.core.check.AppCertutilCheck; -import io.xpipe.app.core.check.AppRosettaCheck; -import io.xpipe.app.core.check.AppShellCheck; +import io.xpipe.app.core.check.*; import io.xpipe.app.ext.ActionProvider; import io.xpipe.app.ext.DataStoreProviders; import io.xpipe.app.issue.TrackEvent; @@ -45,6 +42,7 @@ public class BaseMode extends OperationMode { AppI18n.init(); LicenseProvider.get().init(); AppCertutilCheck.check(); + AppBundledToolsCheck.check(); AppAvCheck.check(); AppSid.init(); LocalShell.init(); diff --git a/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java b/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java index 116a6e20..81201260 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java @@ -81,7 +81,7 @@ public class LauncherCommand implements Callable { } } - private void checkStart() { + private void checkStart(int attemptCounter) { var port = AppBeaconServer.get().getPort(); var reachable = BeaconServer.isReachable(port); if (!reachable) { @@ -112,17 +112,22 @@ public class LauncherCommand implements Callable { } try { - client.get() - .performRequest(DaemonFocusExchange.Request.builder() - .mode(getEffectiveMode()) - .build()); + client.get().performRequest(DaemonFocusExchange.Request.builder() + .mode(getEffectiveMode()) + .build()); if (!inputs.isEmpty()) { - client.get() - .performRequest(DaemonOpenExchange.Request.builder() - .arguments(inputs) - .build()); + client.get().performRequest(DaemonOpenExchange.Request.builder() + .arguments(inputs) + .build()); } } catch (Exception ex) { + // Wait until shutdown has completed + if (ex.getMessage() != null && ex.getMessage().contains("Daemon is currently in shutdown") && attemptCounter < 10) { + ThreadHelper.sleep(1000); + checkStart(++attemptCounter); + return; + } + var cli = XPipeInstallation.getLocalDefaultCliExecutable(); ErrorEvent.fromThrowable( "Unable to connect to existing running daemon instance as it did not respond." @@ -172,7 +177,7 @@ public class LauncherCommand implements Callable { @Override @SneakyThrows public Integer call() { - checkStart(); + checkStart(0); // Initialize base mode first to have access to the preferences to determine effective mode OperationMode.switchToSyncOrThrow(OperationMode.BACKGROUND); diff --git a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java index 33125b4d..d631f22a 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -43,7 +43,7 @@ public class AppPrefs { final BooleanProperty dontAcceptNewHostKeys = mapVaultSpecific(new SimpleBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class); final BooleanProperty performanceMode = map(new SimpleBooleanProperty(false), "performanceMode", Boolean.class); - final BooleanProperty useBundledTools = map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class); + public final BooleanProperty useBundledTools = map(new SimpleBooleanProperty(false), "useBundledTools", Boolean.class); public final ObjectProperty theme = map(new SimpleObjectProperty<>(), "theme", AppTheme.Theme.class); final BooleanProperty useSystemFont = map(new SimpleBooleanProperty(true), "useSystemFont", Boolean.class); diff --git a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java index 8f29ec5d..10dbc81a 100644 --- a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java @@ -155,12 +155,14 @@ public interface KittyTerminalType extends ExternalTerminalType { @Override public void launch(LaunchConfiguration configuration) throws Exception { + // We use the absolute path to force the usage of macOS netcat + // Homebrew versions have different option formats try (var sc = LocalShell.getShell().start()) { - CommandSupport.isInPathOrThrow(sc, "nc", "Netcat", null); + CommandSupport.isInPathOrThrow(sc, "/usr/bin/nc", "Netcat", null); } var toClose = prepare(); - var socketWrite = CommandBuilder.of().add("nc", "-U"); + var socketWrite = CommandBuilder.of().add("/usr/bin/nc", "-U"); open(configuration, socketWrite); if (toClose) { closeInitial(socketWrite); diff --git a/core/src/main/java/io/xpipe/core/store/ServiceStore.java b/core/src/main/java/io/xpipe/core/store/ServiceStore.java deleted file mode 100644 index b74db0f3..00000000 --- a/core/src/main/java/io/xpipe/core/store/ServiceStore.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.xpipe.core.store; - -import java.util.OptionalInt; - -public interface ServiceStore extends SingletonSessionStore { - - NetworkTunnelStore getParent(); - - int getPort(); - - OptionalInt getTargetPort(); - - @Override - default SessionChain newSession() { - var s = getParent().tunnelSession(); - return null; - } - - @Override - default Class getSessionClass() { - return null; - } -} diff --git a/dist/changelogs/11.0.md b/dist/changelogs/11.0.md index 2519be6c..5bb05722 100644 --- a/dist/changelogs/11.0.md +++ b/dist/changelogs/11.0.md @@ -55,6 +55,7 @@ I received plenty of user feedback and had time to observe the inner workings of - Fix file browser list jumping around on first show - Fix missing libxtst6 dependency on some debian-based systems - Fix file browser root session not applying same color of original connection +- Fix macOS kitty terminal netcat incompatibility with homebrew versions ## Other @@ -67,3 +68,4 @@ I received plenty of user feedback and had time to observe the inner workings of - Don't show git vault compatibility warnings on minor version updates - Enable ZGC on Linux and macOS - Some small appearance improvements +- Many other miscellaneous fixes all over the place