diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionAddExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionAddExchangeImpl.java index 185693c08..e5704ecad 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionAddExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionAddExchangeImpl.java @@ -1,19 +1,39 @@ package io.xpipe.app.beacon.impl; import com.sun.net.httpserver.HttpExchange; +import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.api.ConnectionAddExchange; - -import java.util.UUID; +import io.xpipe.core.util.ValidationException; public class ConnectionAddExchangeImpl extends ConnectionAddExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException { - var cat = msg.getCategory() != null ? msg.getCategory() : DataStorage.DEFAULT_CATEGORY_UUID; - var entry = DataStorage.get().addStoreEntryIfNotPresent(DataStoreEntry.createNew(UUID.randomUUID(), cat, msg.getName(), msg.getData())); + public Object handle(HttpExchange exchange, Request msg) throws Throwable { + var found = DataStorage.get().getStoreEntryIfPresent(msg.getData(), false); + if (found.isPresent()) { + return Response.builder().connection(found.get().getUuid()).build(); + } + + var entry = DataStoreEntry.createNew(msg.getName(), msg.getData()); + try { + DataStorage.get().addStoreEntryInProgress(entry); + if (msg.getValidate()) { + entry.validateOrThrow(); + } + } catch (Throwable ex) { + if (ex instanceof ValidationException) { + ErrorEvent.expected(ex); + } else if (ex instanceof StackOverflowError) { + // Cycles in connection graphs can fail hard but are expected + ErrorEvent.expected(ex); + } + throw ex; + } finally { + DataStorage.get().removeStoreEntryInProgress(entry); + } + DataStorage.get().addStoreEntryIfNotPresent(entry); return Response.builder().connection(entry.getUuid()).build(); } } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java new file mode 100644 index 000000000..dfd656d96 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionRefreshExchangeImpl.java @@ -0,0 +1,23 @@ +package io.xpipe.app.beacon.impl; + +import com.sun.net.httpserver.HttpExchange; +import io.xpipe.app.storage.DataStorage; +import io.xpipe.app.util.FixedHierarchyStore; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.api.ConnectionRefreshExchange; + +public class ConnectionRefreshExchangeImpl extends ConnectionRefreshExchange { + + @Override + public Object handle(HttpExchange exchange, Request msg) throws Throwable { + var e = DataStorage.get() + .getStoreEntryIfPresent(msg.getConnection()) + .orElseThrow(() -> new BeaconClientException("Unknown connection: " + msg.getConnection())); + if (e.getStore() instanceof FixedHierarchyStore) { + DataStorage.get().refreshChildren(e, true); + } else { + e.validateOrThrow(); + } + return Response.builder().build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionToggleExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionToggleExchangeImpl.java index f208fcc51..dbecdba4d 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionToggleExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionToggleExchangeImpl.java @@ -16,7 +16,7 @@ public class ConnectionToggleExchangeImpl extends ConnectionToggleExchange { if (!(e.getStore() instanceof SingletonSessionStore> singletonSessionStore)) { throw new BeaconClientException("Not a toggleable connection"); } - if (msg.isState()) { + if (msg.getState()) { singletonSessionStore.startSessionIfNeeded(); } else { singletonSessionStore.stopSessionIfNeeded(); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java index 0354d52cf..ad69b0479 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java @@ -2,6 +2,7 @@ package io.xpipe.app.beacon.impl; import io.xpipe.app.core.AppProperties; import io.xpipe.app.core.AppVersion; +import io.xpipe.app.util.LicenseProvider; import io.xpipe.beacon.api.DaemonVersionExchange; import com.sun.net.httpserver.HttpExchange; @@ -19,6 +20,7 @@ public class DaemonVersionExchangeImpl extends DaemonVersionExchange { + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.version") + ")"; var version = AppProperties.get().getVersion(); + var pro = LicenseProvider.get().hasPaidLicense(); return Response.builder() .version(version) .canonicalVersion(AppVersion.parse(version) @@ -26,6 +28,7 @@ public class DaemonVersionExchangeImpl extends DaemonVersionExchange { .orElse("?")) .buildVersion(AppProperties.get().getBuild()) .jvmVersion(jvmVersion) + .pro(pro) .build(); } } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java index 07c375df8..e4bfb2a2d 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -43,6 +43,7 @@ public class BrowserTransferComp extends SimpleComp { var background = new LabelComp(AppI18n.observable("transferDescription")) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2d-download-outline"))) + .apply(struc -> struc.get().setWrapText(true)) .visible(Bindings.isEmpty(syncItems)); var backgroundStack = new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); @@ -77,6 +78,7 @@ public class BrowserTransferComp extends SimpleComp { aBoolean -> aBoolean ? AppI18n.observable("dragLocalFiles") : AppI18n.observable("dragFiles"))) .apply(struc -> struc.get().setGraphic(new FontIcon("mdi2h-hand-left"))) .apply(struc -> AppFont.medium(struc.get())) + .apply(struc -> struc.get().setWrapText(true)) .hide(Bindings.isEmpty(syncItems)); var downloadButton = new IconButtonComp("mdi2d-download", () -> { diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index 37e5410d6..2573e747c 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -16,6 +16,7 @@ import javafx.util.Pair; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import lombok.SneakyThrows; import java.nio.file.Files; import java.nio.file.Path; @@ -338,7 +339,12 @@ public abstract class DataStorage { listeners.forEach(storageListener -> storageListener.onStoreListUpdate()); } + @SneakyThrows public boolean refreshChildren(DataStoreEntry e) { + return refreshChildren(e,false); + } + + public boolean refreshChildren(DataStoreEntry e, boolean throwOnFail) throws Exception { if (!(e.getStore() instanceof FixedHierarchyStore)) { return false; } @@ -348,8 +354,12 @@ public abstract class DataStorage { try { newChildren = ((FixedHierarchyStore) (e.getStore())).listChildren(e).stream().filter(dataStoreEntryRef -> dataStoreEntryRef != null && dataStoreEntryRef.get() != null).toList(); } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).handle(); - return false; + if (throwOnFail) { + throw ex; + } else { + ErrorEvent.fromThrowable(ex).handle(); + return false; + } } finally { e.decrementBusyCounter(); } diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 37962472b..d04990eff 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -139,6 +139,7 @@ open module io.xpipe.app { ConnectionBrowseExchangeImpl, ConnectionTerminalExchangeImpl, ConnectionToggleExchangeImpl, + ConnectionRefreshExchangeImpl, DaemonOpenExchangeImpl, DaemonFocusExchangeImpl, DaemonStatusExchangeImpl, diff --git a/app/src/main/resources/io/xpipe/app/resources/misc/api.md b/app/src/main/resources/io/xpipe/app/resources/misc/api.md index 6201a65a2..d548fda10 100644 --- a/app/src/main/resources/io/xpipe/app/resources/misc/api.md +++ b/app/src/main/resources/io/xpipe/app/resources/misc/api.md @@ -1307,6 +1307,164 @@ curl -X POST http://localhost:21721/connection/toggle \ +## Refreshes state of a connection + + + +`POST /connection/refresh` + +Performs a refresh on the specified connection. + +This will update the connection state information and also any children if the connection type has any. + +> Body parameter + +```json +{ + "connection": "36ad9716-a209-4f7f-9814-078d3349280c" +} +``` + +