From 33577ca7c1a2a859af1266b207de8060f25f864f Mon Sep 17 00:00:00 2001 From: crschnick Date: Mon, 17 Jun 2024 12:28:37 +0000 Subject: [PATCH] More beacon fixes --- .../io/xpipe/app/beacon/AppBeaconServer.java | 8 ++-- .../app/beacon/BeaconRequestHandler.java | 12 ++++++ .../app/beacon/impl/AskpassExchangeImpl.java | 12 +++--- .../beacon/impl/DaemonFocusExchangeImpl.java | 10 +---- .../beacon/impl/DaemonOpenExchangeImpl.java | 7 +--- .../beacon/impl/DaemonStatusExchangeImpl.java | 12 +++--- .../beacon/impl/DaemonStopExchangeImpl.java | 12 +++--- .../impl/DaemonVersionExchangeImpl.java | 12 +++--- .../beacon/impl/HandshakeExchangeImpl.java | 10 +++-- .../xpipe/app/comp/base/SideMenuBarComp.java | 5 +-- .../io/xpipe/app/core/mode/OperationMode.java | 2 +- .../java/io/xpipe/app/prefs/AppPrefs.java | 9 ----- .../io/xpipe/app/prefs/HttpApiCategory.java | 4 -- .../java/io/xpipe/beacon/BeaconInterface.java | 8 ++-- .../io/xpipe/core/util/CoreJacksonModule.java | 38 ++++++++++++++----- lang/app/strings/translations_en.properties | 4 -- 16 files changed, 86 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java index a1837c1d..ecf7aedc 100644 --- a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java +++ b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java @@ -1,16 +1,14 @@ package io.xpipe.app.beacon; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; import io.xpipe.app.core.AppResources; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; -import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.MarkdownHelper; import io.xpipe.beacon.BeaconConfig; import io.xpipe.beacon.BeaconInterface; import io.xpipe.core.util.XPipeInstallation; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpServer; import lombok.Getter; import java.io.IOException; @@ -52,7 +50,7 @@ public class AppBeaconServer { port = BeaconConfig.getUsedPort(); propertyPort = true; } else { - port = AppPrefs.get().httpServerPort().getValue(); + port = XPipeInstallation.getDefaultBeaconPort(); propertyPort = false; } INSTANCE = new AppBeaconServer(port, propertyPort); diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java index 0ac65aa3..ae244a46 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java @@ -1,8 +1,10 @@ package io.xpipe.app.beacon; +import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; +import io.xpipe.app.util.ThreadHelper; import io.xpipe.beacon.*; import io.xpipe.core.util.JacksonMapper; @@ -25,6 +27,16 @@ public class BeaconRequestHandler implements HttpHandler { @Override public void handle(HttpExchange exchange) { + if (OperationMode.isInShutdown()) { + return; + } + + if (beaconInterface.requiresCompletedStartup()) { + while (OperationMode.isInStartup()) { + ThreadHelper.sleep(100); + } + } + if (!AppPrefs.get().disableApiAuthentication().get() && beaconInterface.requiresAuthentication()) { var auth = exchange.getRequestHeaders().getFirst("Authorization"); if (auth == null) { diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java index 4abf377f..c5f0fc4c 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java @@ -1,17 +1,17 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.util.AskpassAlert; import io.xpipe.app.util.SecretManager; -import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.AskpassExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; - public class AskpassExchangeImpl extends AskpassExchange { + @Override + public boolean requiresCompletedStartup() { + return false; + } + @Override public Object handle(HttpExchange exchange, Request msg) { if (msg.getRequest() == null) { diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java index 1d3e4aff..1e1d5152 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java @@ -1,19 +1,13 @@ package io.xpipe.app.beacon.impl; -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; -import io.xpipe.beacon.api.DaemonFocusExchange; - import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; +import io.xpipe.app.core.mode.OperationMode; +import io.xpipe.beacon.api.DaemonFocusExchange; public class DaemonFocusExchangeImpl extends DaemonFocusExchange { @Override public Object handle(HttpExchange exchange, Request msg) { - OperationMode.switchUp(OperationMode.map(msg.getMode())); return Response.builder().build(); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java index 2c2c8222..06eee787 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java @@ -1,17 +1,14 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.launcher.LauncherInput; import io.xpipe.app.util.PlatformState; -import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonOpenExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; - public class DaemonOpenExchangeImpl extends DaemonOpenExchange { + @Override public Object handle(HttpExchange exchange, Request msg) throws BeaconServerException { diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java index 402ea1c9..a0fb7e07 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java @@ -1,16 +1,16 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonStatusExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; - public class DaemonStatusExchangeImpl extends DaemonStatusExchange { + @Override + public boolean requiresCompletedStartup() { + return false; + } + @Override public Object handle(HttpExchange exchange, Request body) { String mode; diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java index c4fec7cd..720e007d 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java @@ -1,17 +1,17 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.util.ThreadHelper; -import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonStopExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; - public class DaemonStopExchangeImpl extends DaemonStopExchange { + @Override + public boolean requiresCompletedStartup() { + return false; + } + @Override public Object handle(HttpExchange exchange, Request msg) { ThreadHelper.runAsync(() -> { 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 5ba3b8a2..4c2a6339 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 @@ -1,16 +1,16 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.AppProperties; -import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonVersionExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; - public class DaemonVersionExchangeImpl extends DaemonVersionExchange { + @Override + public boolean requiresCompletedStartup() { + return false; + } + @Override public Object handle(HttpExchange exchange, Request msg) { var jvmVersion = System.getProperty("java.vm.vendor") + " " diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java index 96d1a6a6..0e46ce94 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java @@ -1,20 +1,22 @@ package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.BeaconSession; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.beacon.BeaconAuthMethod; import io.xpipe.beacon.BeaconClientException; -import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.HandshakeExchange; -import com.sun.net.httpserver.HttpExchange; - -import java.io.IOException; import java.util.UUID; public class HandshakeExchangeImpl extends HandshakeExchange { + @Override + public boolean requiresCompletedStartup() { + return false; + } + @Override public Object handle(HttpExchange exchange, Request body) throws BeaconClientException { diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java index 641f2273..a6f7003b 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java @@ -1,5 +1,6 @@ package io.xpipe.app.comp.base; +import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.Comp; @@ -9,11 +10,9 @@ import io.xpipe.app.fxcomps.augment.Augment; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.util.PlatformThread; -import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.update.UpdateAvailableAlert; import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.util.Hyperlinks; - import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.Property; @@ -162,7 +161,7 @@ public class SideMenuBarComp extends Comp> { var b = new IconButtonComp( "mdi2c-code-json", () -> Hyperlinks.open("http://localhost:" - + AppPrefs.get().httpServerPort().getValue())) + + AppBeaconServer.get().getPort())) .tooltipKey("api") .apply(simpleBorders) .accessibleTextKey("api"); diff --git a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java index 8b20c4ff..0eb66c64 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java @@ -126,8 +126,8 @@ public abstract class OperationMode { var usedArgs = parseProperties(args); setup(args); LauncherCommand.runLauncher(usedArgs); - inStartup = false; AppDesktopIntegration.setupDesktopIntegrations(); + inStartup = false; } public static void switchToAsync(OperationMode newMode) { 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 41d1d932..ade25593 100644 --- a/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java +++ b/app/src/main/java/io/xpipe/app/prefs/AppPrefs.java @@ -14,15 +14,12 @@ import io.xpipe.app.terminal.ExternalTerminalType; import io.xpipe.app.util.PasswordLockSecretValue; import io.xpipe.core.util.InPlaceSecretValue; import io.xpipe.core.util.ModuleHelper; -import io.xpipe.core.util.XPipeInstallation; - import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableDoubleValue; import javafx.beans.value.ObservableStringValue; import javafx.beans.value.ObservableValue; - import lombok.Getter; import lombok.Value; @@ -122,17 +119,11 @@ public class AppPrefs { private final StringProperty lockCrypt = mapVaultSpecific(new SimpleStringProperty(), "workspaceLock", String.class); - final Property httpServerPort = map( - new SimpleObjectProperty<>(XPipeInstallation.getDefaultBeaconPort()), "httpServerPort", Integer.class); final StringProperty apiKey = mapVaultSpecific(new SimpleStringProperty(UUID.randomUUID().toString()), "apiKey", String.class); final BooleanProperty disableApiAuthentication = map(new SimpleBooleanProperty(false), "disableApiAuthentication", Boolean.class); - public ObservableValue httpServerPort() { - return httpServerPort; - } - public ObservableStringValue apiKey() { return apiKey; } diff --git a/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java b/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java index 73d1f220..4f763df0 100644 --- a/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/HttpApiCategory.java @@ -1,6 +1,5 @@ package io.xpipe.app.prefs; -import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.util.OptionsBuilder; @@ -17,9 +16,6 @@ public class HttpApiCategory extends AppPrefsCategory { return new OptionsBuilder() .addTitle("httpServerConfiguration") .sub(new OptionsBuilder() - .nameAndDescription("httpServerPort") - .addInteger(prefs.httpServerPort) - .disable(AppBeaconServer.get().isPropertyPort()) .nameAndDescription("apiKey") .addString(prefs.apiKey) .nameAndDescription("disableApiAuthentication") diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java index e474b993..feb513e8 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java @@ -1,11 +1,9 @@ package io.xpipe.beacon; -import io.xpipe.core.util.ModuleLayerLoader; - import com.sun.net.httpserver.HttpExchange; +import io.xpipe.core.util.ModuleLayerLoader; import lombok.SneakyThrows; -import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.ServiceLoader; @@ -63,6 +61,10 @@ public abstract class BeaconInterface { return (Class) Class.forName(name); } + public boolean requiresCompletedStartup() { + return true; + } + public boolean requiresAuthentication() { return true; } diff --git a/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java b/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java index b350b6aa..bebcba05 100644 --- a/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java +++ b/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java @@ -1,14 +1,5 @@ package io.xpipe.core.util; -import io.xpipe.core.dialog.BaseQueryElement; -import io.xpipe.core.dialog.BusyElement; -import io.xpipe.core.dialog.ChoiceElement; -import io.xpipe.core.dialog.HeaderElement; -import io.xpipe.core.process.OsType; -import io.xpipe.core.process.ShellDialect; -import io.xpipe.core.process.ShellDialects; -import io.xpipe.core.store.LocalStore; - import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import com.fasterxml.jackson.core.JsonGenerator; @@ -18,11 +9,21 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.type.ArrayType; +import io.xpipe.core.dialog.BaseQueryElement; +import io.xpipe.core.dialog.BusyElement; +import io.xpipe.core.dialog.ChoiceElement; +import io.xpipe.core.dialog.HeaderElement; +import io.xpipe.core.process.OsType; +import io.xpipe.core.process.ShellDialect; +import io.xpipe.core.process.ShellDialects; +import io.xpipe.core.store.LocalStore; +import io.xpipe.core.store.StorePath; import java.io.IOException; import java.lang.reflect.WildcardType; import java.nio.charset.Charset; import java.nio.file.Path; +import java.util.List; import java.util.stream.Stream; public class CoreJacksonModule extends SimpleModule { @@ -68,6 +69,25 @@ public class CoreJacksonModule extends SimpleModule { context.addDeserializers(_deserializers); } + public static class StorePathSerializer extends JsonSerializer { + + @Override + public void serialize(StorePath value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + var ar = value.getNames().toArray(String[]::new); + jgen.writeArray(ar, 0, ar.length); + } + } + + public static class StorePathDeserializer extends JsonDeserializer { + + @Override + public StorePath deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + JavaType javaType = JacksonMapper.getDefault().getTypeFactory().constructCollectionLikeType(List.class, String.class); + List list = JacksonMapper.getDefault().readValue(p, javaType); + return new StorePath(list); + } + } + public static class CharsetSerializer extends JsonSerializer { @Override diff --git a/lang/app/strings/translations_en.properties b/lang/app/strings/translations_en.properties index 8101e24d..54ce6693 100644 --- a/lang/app/strings/translations_en.properties +++ b/lang/app/strings/translations_en.properties @@ -461,10 +461,6 @@ stickToTop=Keep on top orderAheadOf=Order ahead of ... httpServer=HTTP server httpServerConfiguration=HTTP server configuration -#context: networking -httpServerPort=Port -#context: networking -httpServerPortDescription=The port on which the HTTP server will listen on.\n\nNote that if you change this, any other applications that interact with the server need to be configured to use the new port as well.\n\nRequires a restart to apply. apiKey=API key apiKeyDescription=The API key to authenticate XPipe daemon API requests. For more information on how to authenticate, see the general API documentation.\n\nRequires a restart to apply. disableApiAuthentication=Disable API authentication