Skip to content

Commit

Permalink
Various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
crschnick committed Aug 14, 2024
1 parent 51121d2 commit ac221b3
Show file tree
Hide file tree
Showing 24 changed files with 144 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public Object handle(HttpExchange exchange, Request msg) throws Exception {
TerminalInitScriptConfig.ofName(DataStorage.get().getStoreEntryDisplayName(found.get())),null);
}
}
TerminalLauncherManager.submitAsync(UUID.randomUUID(), ((ShellStore) DataStorage.get().local().getStore()).control(),
TerminalInitScriptConfig.ofName("abc"),null);

var r = TerminalLauncherManager.waitForNextLaunch();
var c = ProcessControlProvider.get().getEffectiveLocalDialect().getOpenScriptCommand(r.toString()).buildBaseParts(null);
return Response.builder().command(c).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ private boolean showActionProvider(ActionProvider p) {
var branch = p.getBranchDataStoreCallSite();
if (branch != null
&& entry.getStore() != null
&& branch.getApplicableClass().isAssignableFrom(entry.getStore().getClass())) {
&& branch.getApplicableClass().isAssignableFrom(entry.getStore().getClass())
&& branch.isApplicable(entry.ref())) {
return branch.getChildren(entry.ref()).stream().anyMatch(child -> {
return showActionProvider(child);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import atlantafx.base.theme.Styles;
import io.xpipe.app.browser.session.BrowserChooserComp;
import io.xpipe.app.comp.base.ButtonComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.core.window.AppWindowHelper;
import io.xpipe.app.fxcomps.Comp;
Expand All @@ -19,7 +18,6 @@
import javafx.application.Platform;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Alert;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.kordamp.ikonli.javafx.FontIcon;
Expand Down Expand Up @@ -94,13 +92,7 @@ public CompStructure<HBox> createBase() {
var f = data.resolve(FileNames.getFileName(currentPath.trim()));
var source = Path.of(currentPath.trim());
if (Files.exists(source)) {
var shouldCopy = AppWindowHelper.showBlockingAlert(alert -> {
alert.setTitle(AppI18n.get("confirmGitShareTitle"));
alert.setHeaderText(AppI18n.get("confirmGitShareHeader"));
alert.setAlertType(Alert.AlertType.CONFIRMATION);
})
.map(buttonType -> buttonType.getButtonData().isDefaultButton())
.orElse(false);
var shouldCopy = AppWindowHelper.showConfirmationAlert("confirmGitShareTitle","confirmGitShareHeader", "confirmGitShareContent");
if (!shouldCopy) {
return;
}
Expand Down
95 changes: 44 additions & 51 deletions app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.beacon.BeaconClient;
import io.xpipe.beacon.BeaconClientInformation;
import io.xpipe.beacon.BeaconServer;
import io.xpipe.beacon.api.DaemonFocusExchange;
import io.xpipe.beacon.api.DaemonOpenExchange;
import io.xpipe.core.process.OsType;
Expand Down Expand Up @@ -82,65 +83,57 @@ public static void runLauncher(String[] args) {

private void checkStart() {
var port = AppBeaconServer.get().getPort();
var client = BeaconClient.tryEstablishConnection(
port, BeaconClientInformation.Daemon.builder().build());
if (client.isPresent()) {
try {
client.get()
.performRequest(DaemonFocusExchange.Request.builder()
.mode(getEffectiveMode())
.build());
if (!inputs.isEmpty()) {
client.get()
.performRequest(DaemonOpenExchange.Request.builder()
.arguments(inputs)
.build());
}
} catch (Exception ex) {
var cli = XPipeInstallation.getLocalDefaultCliExecutable();
ErrorEvent.fromThrowable(
"Unable to connect to existing running daemon instance as it did not respond."
+ " Either try to kill the process xpiped manually or use the command \"" + cli
+ "\" daemon stop --force.",
ex)
.term()
.expected()
.handle();
var reachable = BeaconServer.isReachable(port);
if (!reachable) {
// Even in case we are unable to reach another beacon server
// there might be another instance running, for example
// starting up or listening on another port
if (!AppDataLock.lock()) {
TrackEvent.info("Data directory " + AppProperties.get().getDataDir().toString()
+ " is already locked. Is another instance running?");
OperationMode.halt(1);
}

if (OsType.getLocal().equals(OsType.MACOS)) {
Desktop.getDesktop().setOpenURIHandler(e -> {
try {
client.get()
.performRequest(DaemonOpenExchange.Request.builder()
.arguments(List.of(e.getURI().toString()))
.build());
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).expected().omit().handle();
}
});
ThreadHelper.sleep(1000);
}
TrackEvent.info("Another instance is already running on this port. Quitting ...");
OperationMode.halt(1);
// We are good to start up!
return;
}

// Even in case we are unable to reach another beacon server
// there might be another instance running, for example
// starting up or listening on another port
if (!AppDataLock.lock()) {
TrackEvent.info("Data directory " + AppProperties.get().getDataDir().toString()
+ " is already locked. Is another instance running?");
var client = BeaconClient.tryEstablishConnection(
port, BeaconClientInformation.Daemon.builder().build());
if (client.isEmpty()) {
// If an instance is running as another user, we cannot connect to it as the xpipe_auth file is inaccessible
// Therefore the beacon client is not present.
// We still should check whether it is somehow occupied, otherwise beacon server startup will fail
TrackEvent.info("Another instance is already running on this port as another user or is not reachable. Quitting ...");
OperationMode.halt(1);
return;
}

// If an instance is running as another user, we cannot connect to it as the xpipe_auth file is inaccessible
// Therefore the beacon client is not present.
// We still should check whether it is somehow occupied, otherwise beacon server startup will fail
if (BeaconClient.isOccupied(port)) {
TrackEvent.info("Another instance is already running on this port as another user. Quitting ...");
OperationMode.halt(1);
try {
client.get().performRequest(DaemonFocusExchange.Request.builder().mode(getEffectiveMode()).build());
if (!inputs.isEmpty()) {
client.get().performRequest(DaemonOpenExchange.Request.builder().arguments(inputs).build());
}
} catch (Exception ex) {
var cli = XPipeInstallation.getLocalDefaultCliExecutable();
ErrorEvent.fromThrowable("Unable to connect to existing running daemon instance as it did not respond." +
" Either try to kill the process xpiped manually or use the command \"" +
cli +
"\" daemon stop --force.", ex).term().expected().handle();
}

if (OsType.getLocal().equals(OsType.MACOS)) {
Desktop.getDesktop().setOpenURIHandler(e -> {
try {
client.get().performRequest(DaemonOpenExchange.Request.builder().arguments(List.of(e.getURI().toString())).build());
} catch (Exception ex) {
ErrorEvent.fromThrowable(ex).expected().omit().handle();
}
});
ThreadHelper.sleep(1000);
}
TrackEvent.info("Another instance is already running on this port. Quitting ...");
OperationMode.halt(1);
}

private XPipeDaemonMode getEffectiveMode() {
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/io/xpipe/app/util/ScanAlert.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.process.ShellTtyState;
import io.xpipe.core.store.ShellStore;

import javafx.application.Platform;
Expand All @@ -34,7 +36,10 @@ public class ScanAlert {

public static void showAsync(DataStoreEntry entry) {
ThreadHelper.runAsync(() -> {
if (entry == null || entry.getStore() instanceof ShellStore) {
var showForCon = entry == null || (entry.getStore() instanceof ShellStore && (
!(entry.getStorePersistentState() instanceof ShellStoreState shellStoreState) ||
shellStoreState.getTtyState() == null || shellStoreState.getTtyState() == ShellTtyState.NONE));
if (showForCon) {
showForShellStore(entry);
}
});
Expand All @@ -46,6 +51,10 @@ public static void showForShellStore(DataStoreEntry initial) {
return null;
}

if (sc.getTtyState() != ShellTtyState.NONE) {
return null;
}

var providers = ScanProvider.getAll();
var applicable = new ArrayList<ScanProvider.ScanOperation>();
for (ScanProvider scanProvider : providers) {
Expand Down
87 changes: 47 additions & 40 deletions app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
import lombok.experimental.NonFinal;

import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.SequencedMap;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CountDownLatch;

public class TerminalLauncherManager {
Expand Down Expand Up @@ -53,69 +51,78 @@ public FilePath apply(ShellControl shellControl) {
}
}

public static void submitSync(
UUID request, ProcessControl processControl, TerminalInitScriptConfig config, String directory) {
var entry = new Entry(request, processControl, config, directory, null);
entries.put(request, entry);
prepare(processControl, config, directory, entry);
}

public static CountDownLatch submitAsync(
UUID request, ProcessControl processControl, TerminalInitScriptConfig config, String directory) {
var entry = new Entry(request, processControl, config, directory, null);
entries.put(request, entry);
var latch = new CountDownLatch(1);
ThreadHelper.runAsync(() -> {
prepare(processControl, config, directory, entry);
latch.countDown();
});
return latch;
synchronized (entries) {
var entry = new Entry(request, processControl, config, directory, null);
entries.put(request, entry);
var latch = new CountDownLatch(1);
ThreadHelper.runAsync(() -> {
prepare(processControl, config, directory, entry);
latch.countDown();
});
return latch;
}
}

public static Path waitForNextLaunch() throws BeaconClientException, BeaconServerException {
if (entries.isEmpty()) {
throw new BeaconClientException("Unknown launch request");
}
Map.Entry<UUID, Entry> first;
synchronized (entries) {
if (entries.isEmpty()) {
throw new BeaconClientException("Unknown launch request");
}

var first = entries.firstEntry();
entries.remove(first.getKey());
return waitForCompletion(first.getKey());
first = entries.firstEntry();
entries.remove(first.getKey());
}
return waitForCompletion(first.getValue());
}

public static Path waitForCompletion(UUID request) throws BeaconClientException, BeaconServerException {
var e = entries.get(request);
Entry e;
synchronized (entries) {
e = entries.get(request);
}
if (e == null) {
throw new BeaconClientException("Unknown launch request " + request);
}

return waitForCompletion(e);
}

public static Path waitForCompletion(Entry e) throws BeaconClientException, BeaconServerException {
while (true) {
if (e.result == null) {
ThreadHelper.sleep(10);
continue;
}

var r = e.getResult();
if (r instanceof ResultFailure failure) {
entries.remove(request);
var t = failure.getThrowable();
throw new BeaconServerException(t);
}
synchronized (entries) {
var r = e.getResult();
if (r instanceof ResultFailure failure) {
entries.remove(e.getRequest());
var t = failure.getThrowable();
throw new BeaconServerException(t);
}

return ((ResultSuccess) r).getTargetScript();
return ((ResultSuccess) r).getTargetScript();
}
}
}

public static Path performLaunch(UUID request) throws BeaconClientException {
var e = entries.remove(request);
if (e == null) {
throw new BeaconClientException("Unknown launch request " + request);
}
synchronized (entries) {
var e = entries.remove(request);
if (e == null) {
throw new BeaconClientException("Unknown launch request " + request);
}

if (!(e.result instanceof ResultSuccess)) {
throw new BeaconClientException("Invalid launch request state " + request);
}
if (!(e.result instanceof ResultSuccess)) {
throw new BeaconClientException("Invalid launch request state " + request);
}

return ((ResultSuccess) e.getResult()).getTargetScript();
return ((ResultSuccess) e.getResult()).getTargetScript();
}
}

public interface Result {}
Expand Down
9 changes: 0 additions & 9 deletions beacon/src/main/java/io/xpipe/beacon/BeaconClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ public BeaconClient(int port) {
this.port = port;
}

public static boolean isOccupied(int port) {
var file = XPipeInstallation.getLocalBeaconAuthFile();
var reachable = BeaconServer.isReachable(port);
if (!Files.exists(file) && !reachable) {
return false;
}
return reachable;
}

public static BeaconClient establishConnection(int port, BeaconClientInformation information) throws Exception {
var client = new BeaconClient(port);
var auth = Files.readString(XPipeInstallation.getLocalBeaconAuthFile());
Expand Down
6 changes: 3 additions & 3 deletions dist/changelogs/11.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ The main concern here is to verify that the existing normal shell implementation

There is now support to add your teleport connections that are available via tsh.

## Profiles
## Workspaces

You can now create multiple user profiles in the settings menu.
You can now create multiple user workspaces in the settings menu.

This will create desktop shortcuts that you can use to start XPipe with different profiles active.
This will create desktop shortcuts that you can use to start XPipe with different workspaces active.

## Serial connection support

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.store.ShellStore;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;

import lombok.Value;

public class BrowseStoreAction implements ActionProvider {
Expand All @@ -20,17 +17,6 @@ public class BrowseStoreAction implements ActionProvider {
public LeafDataStoreCallSite<?> getLeafDataStoreCallSite() {
return new LeafDataStoreCallSite<ShellStore>() {

@Override
public boolean isApplicable(DataStoreEntryRef<ShellStore> o) {
var state = o.get().getStorePersistentState();
if (state instanceof ShellStoreState shellStoreState) {
return shellStoreState.getShellDialect() == null
|| shellStoreState.getShellDialect().getDumbMode().supportsAnyPossibleInteraction();
} else {
return true;
}
}

@Override
public ActionProvider.Action createAction(DataStoreEntryRef<ShellStore> store) {
return new Action(store.get());
Expand Down
Loading

0 comments on commit ac221b3

Please sign in to comment.