From b68ada9e787ccdcb47cdf4679cf3968f7a5e142e Mon Sep 17 00:00:00 2001 From: crschnick Date: Tue, 14 May 2024 15:40:45 +0000 Subject: [PATCH] [stage] --- app/build.gradle | 3 - .../io/xpipe/app/beacon/AppBeaconServer.java | 90 +++++ .../app/beacon/BeaconRequestHandler.java | 122 ++++++ .../io/xpipe/app/beacon/BeaconSession.java | 11 + .../impl}/AskpassExchangeImpl.java | 15 +- .../app/beacon/impl/FocusExchangeImpl.java | 20 + .../beacon/impl/HandshakeExchangeImpl.java | 22 ++ .../app/beacon/impl/ModeExchangeImpl.java | 36 ++ .../app/beacon/impl/OpenExchangeImpl.java | 25 ++ .../app/beacon/impl/StatusExchangeImpl.java | 25 ++ .../app/beacon/impl/StopExchangeImpl.java | 22 ++ .../impl/TerminalLaunchExchangeImpl.java | 17 + .../beacon/impl/TerminalWaitExchangeImpl.java | 17 + .../impl}/VersionExchangeImpl.java | 15 +- .../io/xpipe/app/core/AppSocketServer.java | 358 ------------------ .../java/io/xpipe/app/core/mode/BaseMode.java | 12 +- .../io/xpipe/app/core/mode/OperationMode.java | 1 + .../app/exchange/DialogExchangeImpl.java | 76 ---- .../xpipe/app/exchange/FocusExchangeImpl.java | 15 - .../app/exchange/LaunchExchangeImpl.java | 34 -- .../app/exchange/MessageExchangeImpl.java | 47 --- .../app/exchange/MessageExchangeImpls.java | 61 --- .../xpipe/app/exchange/OpenExchangeImpl.java | 24 -- .../app/exchange/QueryStoreExchangeImpl.java | 23 -- .../exchange/TerminalLaunchExchangeImpl.java | 16 - .../exchange/TerminalWaitExchangeImpl.java | 17 - .../app/exchange/cli/DrainExchangeImpl.java | 30 -- .../exchange/cli/EditStoreExchangeImpl.java | 21 - .../exchange/cli/ListStoresExchangeImpl.java | 32 -- .../app/exchange/cli/ModeExchangeImpl.java | 36 -- .../exchange/cli/ReadDrainExchangeImpl.java | 14 - .../exchange/cli/RemoveStoreExchangeImpl.java | 23 -- .../exchange/cli/RenameStoreExchangeImpl.java | 18 - .../app/exchange/cli/SinkExchangeImpl.java | 29 -- .../app/exchange/cli/StatusExchangeImpl.java | 22 -- .../app/exchange/cli/StopExchangeImpl.java | 22 -- .../exchange/cli/StoreAddExchangeImpl.java | 141 ------- .../cli/StoreProviderListExchangeImpl.java | 37 -- .../xpipe/app/launcher/LauncherCommand.java | 19 +- .../app/launcher/LauncherConnection.java | 9 +- .../app/util/TerminalLauncherManager.java | 17 +- app/src/main/java/module-info.java | 35 +- .../java/io/xpipe/beacon/BeaconClient.java | 321 ++++------------ ...ge.java => BeaconClientErrorResponse.java} | 10 +- .../xpipe/beacon/BeaconClientException.java | 23 ++ .../xpipe/beacon/BeaconClientInformation.java | 77 ++++ .../java/io/xpipe/beacon/BeaconConfig.java | 12 - .../io/xpipe/beacon/BeaconConnection.java | 174 +-------- .../beacon/BeaconConnectorException.java | 25 ++ .../java/io/xpipe/beacon/BeaconException.java | 25 -- .../java/io/xpipe/beacon/BeaconFormat.java | 112 ------ .../java/io/xpipe/beacon/BeaconHandler.java | 34 -- .../java/io/xpipe/beacon/BeaconInterface.java | 74 ++++ .../io/xpipe/beacon/BeaconJacksonModule.java | 6 +- .../java/io/xpipe/beacon/BeaconServer.java | 5 +- .../beacon/BeaconServerErrorResponse.java | 20 + .../xpipe/beacon/BeaconServerException.java | 23 ++ .../java/io/xpipe/beacon/ClientException.java | 25 -- .../io/xpipe/beacon/ConnectorException.java | 25 -- .../java/io/xpipe/beacon/RequestMessage.java | 3 - .../java/io/xpipe/beacon/ResponseMessage.java | 3 - .../java/io/xpipe/beacon/ServerException.java | 25 -- .../{exchange => api}/AskpassExchange.java | 16 +- .../io/xpipe/beacon/api/FocusExchange.java | 29 ++ .../xpipe/beacon/api/HandshakeExchange.java | 34 ++ .../io/xpipe/beacon/api/ModeExchange.java | 32 ++ .../io/xpipe/beacon/api/OpenExchange.java | 30 ++ .../io/xpipe/beacon/api/StatusExchange.java | 27 ++ .../io/xpipe/beacon/api/StopExchange.java | 30 ++ .../TerminalLaunchExchange.java | 16 +- .../beacon/api/TerminalWaitExchange.java | 30 ++ .../io/xpipe/beacon/api/VersionExchange.java | 30 ++ .../xpipe/beacon/exchange/DrainExchange.java | 34 -- .../xpipe/beacon/exchange/FocusExchange.java | 31 -- .../xpipe/beacon/exchange/LaunchExchange.java | 36 -- .../beacon/exchange/MessageExchange.java | 34 -- .../beacon/exchange/MessageExchanges.java | 48 --- .../xpipe/beacon/exchange/OpenExchange.java | 32 -- .../beacon/exchange/QueryStoreExchange.java | 51 --- .../xpipe/beacon/exchange/SinkExchange.java | 34 -- .../xpipe/beacon/exchange/StopExchange.java | 31 -- .../beacon/exchange/TerminalWaitExchange.java | 32 -- .../beacon/exchange/cli/DialogExchange.java | 50 --- .../exchange/cli/EditStoreExchange.java | 35 -- .../exchange/cli/ListCollectionsExchange.java | 32 -- .../exchange/cli/ListEntriesExchange.java | 34 -- .../exchange/cli/ListStoresExchange.java | 32 -- .../beacon/exchange/cli/ModeExchange.java | 35 -- .../exchange/cli/ReadDrainExchange.java | 31 -- .../cli/RemoveCollectionExchange.java | 31 -- .../exchange/cli/RemoveStoreExchange.java | 31 -- .../cli/RenameCollectionExchange.java | 34 -- .../exchange/cli/RenameStoreExchange.java | 34 -- .../beacon/exchange/cli/StatusExchange.java | 29 -- .../beacon/exchange/cli/StoreAddExchange.java | 36 -- .../cli/StoreProviderListExchange.java | 35 -- .../beacon/exchange/cli/VersionExchange.java | 32 -- .../exchange/data/CollectionListEntry.java | 17 - .../beacon/exchange/data/EntryListEntry.java | 17 - .../beacon/exchange/data/ProviderEntry.java | 14 - .../exchange/data/ServerErrorMessage.java | 25 -- .../beacon/exchange/data/StoreListEntry.java | 17 - .../beacon/test/BeaconDaemonController.java | 5 +- .../test/BeaconDaemonExtensionTest.java | 5 +- .../xpipe/beacon/util/QuietDialogHandler.java | 74 ---- beacon/src/main/java/module-info.java | 41 +- .../io.xpipe.core.util.ModuleLayerLoader | 1 + core/build.gradle | 2 - .../io/xpipe/core/process/ShellDialects.java | 7 +- .../io/xpipe/core/util/JacksonMapper.java | 14 +- .../io/xpipe/core/util/ModuleLayerLoader.java | 3 +- core/src/main/java/module-info.java | 5 +- .../io.xpipe.core.util.ModuleLayerLoader | 2 + dist/changelogs/10.0.md | 3 + dist/licenses/prettytime.license | 177 --------- dist/licenses/prettytime.properties | 4 - ext/base/src/main/java/module-info.java | 1 + gradle/gradle_scripts/dev_default.properties | 3 + gradle/gradle_scripts/modules.gradle | 6 - version | 2 +- 120 files changed, 1084 insertions(+), 3160 deletions(-) create mode 100644 app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/BeaconSession.java rename app/src/main/java/io/xpipe/app/{exchange => beacon/impl}/AskpassExchangeImpl.java (55%) create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/FocusExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/ModeExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/OpenExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/StatusExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/StopExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java create mode 100644 app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java rename app/src/main/java/io/xpipe/app/{exchange => beacon/impl}/VersionExchangeImpl.java (54%) delete mode 100644 app/src/main/java/io/xpipe/app/core/AppSocketServer.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/DialogExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/FocusExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/OpenExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/QueryStoreExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/TerminalLaunchExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/TerminalWaitExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/DrainExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/EditStoreExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/ListStoresExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/ModeExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/ReadDrainExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/RemoveStoreExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/RenameStoreExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/SinkExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/StatusExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/StopExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/StoreAddExchangeImpl.java delete mode 100644 app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java rename beacon/src/main/java/io/xpipe/beacon/{exchange/data/ClientErrorMessage.java => BeaconClientErrorResponse.java} (53%) create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconClientException.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconClientInformation.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconConnectorException.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconException.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconFormat.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconHandler.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconServerErrorResponse.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/BeaconServerException.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/ClientException.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/ConnectorException.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/RequestMessage.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/ResponseMessage.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/ServerException.java rename beacon/src/main/java/io/xpipe/beacon/{exchange => api}/AskpassExchange.java (53%) create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/FocusExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/HandshakeExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/ModeExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/OpenExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/StatusExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/StopExchange.java rename beacon/src/main/java/io/xpipe/beacon/{exchange => api}/TerminalLaunchExchange.java (50%) create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/TerminalWaitExchange.java create mode 100644 beacon/src/main/java/io/xpipe/beacon/api/VersionExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/DrainExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/FocusExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/LaunchExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchanges.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/OpenExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/QueryStoreExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/SinkExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/StopExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/TerminalWaitExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/DialogExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListCollectionsExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListEntriesExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListStoresExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/ModeExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/ReadDrainExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveCollectionExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveStoreExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameCollectionExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameStoreExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/StatusExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreAddExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/cli/VersionExchange.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/data/CollectionListEntry.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/data/EntryListEntry.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/data/ProviderEntry.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/data/ServerErrorMessage.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/exchange/data/StoreListEntry.java delete mode 100644 beacon/src/main/java/io/xpipe/beacon/util/QuietDialogHandler.java create mode 100644 beacon/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader create mode 100644 core/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader create mode 100644 dist/changelogs/10.0.md delete mode 100644 dist/licenses/prettytime.license delete mode 100644 dist/licenses/prettytime.properties diff --git a/app/build.gradle b/app/build.gradle index e3f5e7fde..436152013 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,9 +45,7 @@ dependencies { api 'io.sentry:sentry:7.8.0' api 'commons-io:commons-io:2.16.1' api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.1" - api group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: "2.17.1" api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.17.1" - api group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: "2.17.1" api group: 'org.kordamp.ikonli', name: 'ikonli-material2-pack', version: "12.2.0" api group: 'org.kordamp.ikonli', name: 'ikonli-materialdesign2-pack', version: "12.2.0" api group: 'org.kordamp.ikonli', name: 'ikonli-javafx', version: "12.2.0" @@ -86,7 +84,6 @@ run { systemProperty 'io.xpipe.app.fullVersion', rootProject.fullVersion systemProperty 'io.xpipe.app.staging', isStage // systemProperty "io.xpipe.beacon.port", "21724" - // systemProperty "io.xpipe.beacon.printMessages", "true" // systemProperty 'io.xpipe.app.debugPlatform', "true" // Apply passed xpipe properties diff --git a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java new file mode 100644 index 000000000..109023f71 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java @@ -0,0 +1,90 @@ +package io.xpipe.app.beacon; + +import com.sun.net.httpserver.HttpServer; +import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.app.issue.TrackEvent; +import io.xpipe.beacon.BeaconConfig; +import io.xpipe.beacon.BeaconInterface; +import lombok.Getter; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Executors; + +public class AppBeaconServer { + + private static AppBeaconServer INSTANCE; + private final int port; + private boolean running; + private HttpServer server; + @Getter + private Set sessions = new HashSet<>(); + + private AppBeaconServer(int port) { + this.port = port; + } + + public static void init() { + int port = -1; + try { + port = BeaconConfig.getUsedPort(); + INSTANCE = new AppBeaconServer(port); + INSTANCE.start(); + + TrackEvent.withInfo("Initialized http server") + .tag("port", port) + .build() + .handle(); + } catch (Exception ex) { + // Not terminal! + // We can still continue without the running server + ErrorEvent.fromThrowable(ex) + .description("Unable to start local http server on port " + port) + .build() + .handle(); + } + } + + public static void reset() { + if (INSTANCE != null) { + INSTANCE.stop(); + INSTANCE = null; + } + } + + public void addSession(BeaconSession session) { + this.sessions.add(session); + } + + public static AppBeaconServer get() { + return INSTANCE; + } + + private void stop() { + if (!running) { + return; + } + + running = false; + server.stop(1); + } + + private void start() throws IOException { + server = HttpServer.create(new InetSocketAddress("localhost", port), 10); + BeaconInterface.getAll().forEach(beaconInterface -> { + server.createContext(beaconInterface.getPath(), new BeaconRequestHandler<>(beaconInterface)); + }); + server.setExecutor(Executors.newSingleThreadExecutor(r -> { + Thread t = Executors.defaultThreadFactory().newThread(r); + t.setName("http handler"); + t.setUncaughtExceptionHandler((t1, e) -> { + ErrorEvent.fromThrowable(e).handle(); + }); + return t; + })); + server.start(); + running = true; + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java new file mode 100644 index 000000000..839a66722 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java @@ -0,0 +1,122 @@ +package io.xpipe.app.beacon; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import io.xpipe.app.issue.ErrorEvent; +import io.xpipe.app.issue.TrackEvent; +import io.xpipe.beacon.*; +import io.xpipe.core.util.JacksonMapper; +import lombok.SneakyThrows; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +public class BeaconRequestHandler implements HttpHandler { + + private final BeaconInterface beaconInterface; + + public BeaconRequestHandler(BeaconInterface beaconInterface) {this.beaconInterface = beaconInterface;} + + @Override + public void handle(HttpExchange exchange) throws IOException { + if (beaconInterface.requiresAuthentication()) { + var auth = exchange.getRequestHeaders().getFirst("Authorization"); + if (auth == null) { + writeError(exchange, new BeaconClientErrorResponse("Missing Authorization header"), 401); + return; + } + + var token = auth.replace("Bearer ", ""); + var session = AppBeaconServer.get().getSessions().stream().filter(s -> s.getToken().equals(token)).findFirst().orElse(null); + if (session == null) { + writeError(exchange, new BeaconClientErrorResponse("Unknown token"), 403); + return; + } + } + + handleAuthenticatedRequest(exchange); + } + + private void handleAuthenticatedRequest(HttpExchange exchange) { + T object; + Object response; + try { + try (InputStream is = exchange.getRequestBody()) { + var tree = JacksonMapper.getDefault().readTree(is); + TrackEvent.trace("Parsed raw request:\n" + tree.toPrettyString()); + var emptyRequestClass = tree.isEmpty() && beaconInterface.getRequestClass().getDeclaredFields().length == 0; + object = emptyRequestClass ? createDefaultRequest(beaconInterface) : JacksonMapper.getDefault().treeToValue(tree, beaconInterface.getRequestClass()); + TrackEvent.trace("Parsed request object:\n" + object); + } + response = beaconInterface.handle(exchange, object); + } catch (BeaconClientException clientException) { + ErrorEvent.fromThrowable(clientException).omit().expected().handle(); + writeError(exchange, new BeaconClientErrorResponse(clientException.getMessage()), 400); + return; + } catch (BeaconServerException serverException) { + var cause = serverException.getCause() != null ? serverException.getCause() : serverException; + ErrorEvent.fromThrowable(cause).handle(); + writeError(exchange, new BeaconServerErrorResponse(cause), 500); + return; + } catch (IOException ex) { + // Handle serialization errors as normal exceptions and other IO exceptions as assuming that the connection is broken + if (!ex.getClass().getName().contains("jackson")) { + ErrorEvent.fromThrowable(ex).omit().expected().handle(); + } else { + ErrorEvent.fromThrowable(ex).omit().expected().handle(); + writeError(exchange, new BeaconClientErrorResponse(ex.getMessage()), 400); + } + return; + } catch (Throwable other) { + ErrorEvent.fromThrowable(other).handle(); + writeError(exchange, new BeaconServerErrorResponse(other), 500); + return; + } + + try { + if (response != null) { + TrackEvent.trace("Sending response:\n" + object); + var tree = JacksonMapper.getDefault().valueToTree(response); + TrackEvent.trace("Sending raw response:\n" + tree.toPrettyString()); + var bytes = tree.toPrettyString().getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + } else { + exchange.sendResponseHeaders(200, -1); + } + } catch (IOException ioException) { + ErrorEvent.fromThrowable(ioException).omit().expected().handle(); + } catch (Throwable other) { + ErrorEvent.fromThrowable(other).handle(); + writeError(exchange, new BeaconServerErrorResponse(other), 500); + return; + } + } + + private void writeError(HttpExchange exchange, Object errorMessage, int code) { + try { + var bytes = JacksonMapper.getDefault().writeValueAsString(errorMessage).getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(code, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + } catch (IOException ex) { + ErrorEvent.fromThrowable(ex).omit().expected().handle(); + } + } + + @SneakyThrows + @SuppressWarnings("unchecked") + private REQ createDefaultRequest(BeaconInterface beaconInterface) { + var c = beaconInterface.getRequestClass().getDeclaredMethod("builder"); + c.setAccessible(true); + var b = c.invoke(null); + var m = b.getClass().getDeclaredMethod("build"); + m.setAccessible(true); + return (REQ) beaconInterface.getRequestClass().cast(m.invoke(b)); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java b/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java new file mode 100644 index 000000000..38cec0f23 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java @@ -0,0 +1,11 @@ +package io.xpipe.app.beacon; + +import io.xpipe.beacon.BeaconClientInformation; +import lombok.Value; + +@Value +public class BeaconSession { + + BeaconClientInformation clientInformation; + String token; +} diff --git a/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java similarity index 55% rename from app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java rename to app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java index 810d2c71b..bfb70c3c6 100644 --- a/app/src/main/java/io/xpipe/app/exchange/AskpassExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java @@ -1,14 +1,17 @@ -package io.xpipe.app.exchange; +package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.util.SecretManager; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.AskpassExchange; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; +import io.xpipe.beacon.api.AskpassExchange; -public class AskpassExchangeImpl extends AskpassExchange - implements MessageExchangeImpl { +import java.io.IOException; + +public class AskpassExchangeImpl extends AskpassExchange { @Override - public Response handleRequest(BeaconHandler handler, Request msg) { + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { var found = msg.getSecretId() != null ? SecretManager.getProgress(msg.getRequest(), msg.getSecretId()) : SecretManager.getProgress(msg.getRequest()); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/FocusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/FocusExchangeImpl.java new file mode 100644 index 000000000..0497915f2 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/FocusExchangeImpl.java @@ -0,0 +1,20 @@ +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.FocusExchange; + +import java.io.IOException; + +public class FocusExchangeImpl extends FocusExchange { + + +@Override +public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + + OperationMode.switchUp(OperationMode.map(msg.getMode())); + return Response.builder().build(); +} +} 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 new file mode 100644 index 000000000..9c5077cb5 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java @@ -0,0 +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.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; +import io.xpipe.beacon.api.HandshakeExchange; + +import java.io.IOException; +import java.util.UUID; + +public class HandshakeExchangeImpl extends HandshakeExchange { + + @Override + public Object handle(HttpExchange exchange, Request body) throws IOException, BeaconClientException, BeaconServerException { + var session = new BeaconSession(body.getClient(), UUID.randomUUID().toString()); + AppBeaconServer.get().addSession(session); + return Response.builder().token(session.getToken()).build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ModeExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ModeExchangeImpl.java new file mode 100644 index 000000000..0cb196637 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ModeExchangeImpl.java @@ -0,0 +1,36 @@ +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.ModeExchange; + +import java.io.IOException; + +public class ModeExchangeImpl extends ModeExchange { + @Override + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + // Wait for startup + while (OperationMode.get() == null) { + ThreadHelper.sleep(100); + } + + var mode = OperationMode.map(msg.getMode()); + if (!mode.isSupported()) { + throw new BeaconClientException("Unsupported mode: " + msg.getMode().getDisplayName() + ". Supported: " + + String.join( + ", ", + OperationMode.getAll().stream() + .filter(OperationMode::isSupported) + .map(OperationMode::getId) + .toList())); + } + + OperationMode.switchToSyncIfPossible(mode); + return ModeExchange.Response.builder() + .usedMode(OperationMode.map(OperationMode.get())) + .build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/OpenExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/OpenExchangeImpl.java new file mode 100644 index 000000000..3109b1767 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/OpenExchangeImpl.java @@ -0,0 +1,25 @@ +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.OpenExchange; + +import java.io.IOException; + +public class OpenExchangeImpl extends OpenExchange { + @Override + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + if (msg.getArguments().isEmpty()) { + if (!OperationMode.switchToSyncIfPossible(OperationMode.GUI)) { + throw new BeaconServerException(PlatformState.getLastError()); + } + } + + LauncherInput.handle(msg.getArguments()); + return Response.builder().build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/StatusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/StatusExchangeImpl.java new file mode 100644 index 000000000..883bf207c --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/StatusExchangeImpl.java @@ -0,0 +1,25 @@ +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.StatusExchange; + +import java.io.IOException; + +public class StatusExchangeImpl extends StatusExchange { + + @Override + public Object handle(HttpExchange exchange, Request body) throws IOException, BeaconClientException, BeaconServerException { + String mode; + if (OperationMode.get() == null) { + mode = "none"; + } else { + mode = OperationMode.get().getId(); + } + + return Response.builder().mode(mode).build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/StopExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/StopExchangeImpl.java new file mode 100644 index 000000000..ee272d356 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/StopExchangeImpl.java @@ -0,0 +1,22 @@ +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.StopExchange; + +import java.io.IOException; + +public class StopExchangeImpl extends StopExchange { + + @Override + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + ThreadHelper.runAsync(() -> { + ThreadHelper.sleep(1000); + OperationMode.close(); + }); + return Response.builder().success(true).build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java new file mode 100644 index 000000000..097486bcc --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java @@ -0,0 +1,17 @@ +package io.xpipe.app.beacon.impl; + +import com.sun.net.httpserver.HttpExchange; +import io.xpipe.app.util.TerminalLauncherManager; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; +import io.xpipe.beacon.api.TerminalLaunchExchange; + +import java.io.IOException; + +public class TerminalLaunchExchangeImpl extends TerminalLaunchExchange { + @Override + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + var r = TerminalLauncherManager.performLaunch(msg.getRequest()); + return Response.builder().targetFile(r).build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java new file mode 100644 index 000000000..2114dacbd --- /dev/null +++ b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java @@ -0,0 +1,17 @@ +package io.xpipe.app.beacon.impl; + +import com.sun.net.httpserver.HttpExchange; +import io.xpipe.app.util.TerminalLauncherManager; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; +import io.xpipe.beacon.api.TerminalWaitExchange; + +import java.io.IOException; + +public class TerminalWaitExchangeImpl extends TerminalWaitExchange { + @Override + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + TerminalLauncherManager.waitForCompletion(msg.getRequest()); + return Response.builder().build(); + } +} diff --git a/app/src/main/java/io/xpipe/app/exchange/VersionExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/VersionExchangeImpl.java similarity index 54% rename from app/src/main/java/io/xpipe/app/exchange/VersionExchangeImpl.java rename to app/src/main/java/io/xpipe/app/beacon/impl/VersionExchangeImpl.java index 9115b06f8..d6fe83b97 100644 --- a/app/src/main/java/io/xpipe/app/exchange/VersionExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/VersionExchangeImpl.java @@ -1,14 +1,17 @@ -package io.xpipe.app.exchange; +package io.xpipe.app.beacon.impl; +import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.AppProperties; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.VersionExchange; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; +import io.xpipe.beacon.api.VersionExchange; -public class VersionExchangeImpl extends VersionExchange - implements MessageExchangeImpl { +import java.io.IOException; + +public class VersionExchangeImpl extends VersionExchange { @Override - public Response handleRequest(BeaconHandler handler, Request msg) { + public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { var jvmVersion = System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.version") + ")"; diff --git a/app/src/main/java/io/xpipe/app/core/AppSocketServer.java b/app/src/main/java/io/xpipe/app/core/AppSocketServer.java deleted file mode 100644 index eb2ac1695..000000000 --- a/app/src/main/java/io/xpipe/app/core/AppSocketServer.java +++ /dev/null @@ -1,358 +0,0 @@ -package io.xpipe.app.core; - -import io.xpipe.app.exchange.MessageExchangeImpls; -import io.xpipe.app.issue.ErrorEvent; -import io.xpipe.app.issue.TrackEvent; -import io.xpipe.beacon.*; -import io.xpipe.beacon.exchange.MessageExchanges; -import io.xpipe.beacon.exchange.data.ClientErrorMessage; -import io.xpipe.beacon.exchange.data.ServerErrorMessage; -import io.xpipe.core.util.Deobfuscator; -import io.xpipe.core.util.FailableRunnable; -import io.xpipe.core.util.JacksonMapper; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringWriter; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HexFormat; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; - -public class AppSocketServer { - - private static AppSocketServer INSTANCE; - private final int port; - private ServerSocket socket; - private boolean running; - private int connectionCounter; - private Thread listenerThread; - - private AppSocketServer(int port) { - this.port = port; - } - - public static void init() { - int port = -1; - try { - port = BeaconConfig.getUsedPort(); - INSTANCE = new AppSocketServer(port); - INSTANCE.createSocketListener(); - - TrackEvent.withInfo("Initialized socket server") - .tag("port", port) - .build() - .handle(); - } catch (Exception ex) { - // Not terminal! - ErrorEvent.fromThrowable(ex) - .description("Unable to start local socket server on port " + port) - .build() - .handle(); - } - } - - public static void reset() { - if (INSTANCE != null) { - INSTANCE.stop(); - INSTANCE = null; - } - } - - private void stop() { - if (!running) { - return; - } - - running = false; - try { - socket.close(); - } catch (IOException e) { - ErrorEvent.fromThrowable(e).handle(); - } - try { - listenerThread.join(); - } catch (InterruptedException ignored) { - } - } - - private void createSocketListener() throws IOException { - socket = new ServerSocket(port, 10000, InetAddress.getLoopbackAddress()); - running = true; - listenerThread = new Thread( - () -> { - while (running) { - Socket clientSocket; - try { - clientSocket = socket.accept(); - } catch (Exception ex) { - continue; - } - - try { - performExchangesAsync(clientSocket); - } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).build().handle(); - } - connectionCounter++; - } - }, - "socket server"); - listenerThread.start(); - } - - private boolean performExchange(Socket clientSocket, int id) throws Exception { - if (clientSocket.isClosed()) { - TrackEvent.trace("Socket closed"); - return false; - } - - JsonNode node; - try (InputStream blockIn = BeaconFormat.readBlocks(clientSocket.getInputStream())) { - node = JacksonMapper.getDefault().readTree(blockIn); - } - if (node.isMissingNode()) { - TrackEvent.trace("Received EOF"); - return false; - } - - TrackEvent.trace("Received raw request: \n" + node.toPrettyString()); - - var req = parseRequest(node); - TrackEvent.trace("Parsed request: \n" + req.toString()); - - var prov = MessageExchangeImpls.byRequest(req); - if (prov.isEmpty()) { - throw new IllegalArgumentException("Unknown request id: " + req.getClass()); - } - AtomicReference> post = new AtomicReference<>(); - var res = prov.get() - .handleRequest( - new BeaconHandler() { - @Override - public void postResponse(FailableRunnable r) { - post.set(r); - } - - @Override - public OutputStream sendBody() throws IOException { - TrackEvent.trace("Starting writing body for #" + id); - return AppSocketServer.this.sendBody(clientSocket); - } - - @Override - public InputStream receiveBody() throws IOException { - TrackEvent.trace("Starting to read body for #" + id); - return AppSocketServer.this.receiveBody(clientSocket); - } - }, - req); - - TrackEvent.trace("Sending response to #" + id + ": \n" + res.toString()); - AppSocketServer.this.sendResponse(clientSocket, res); - - try { - // If this fails, we sadly can't send an error response. Therefore just report it on the server side - if (post.get() != null) { - post.get().run(); - } - } catch (Exception ex) { - ErrorEvent.fromThrowable(ex).handle(); - } - - TrackEvent.builder() - .type("trace") - .message("Socket connection #" + id + " performed exchange " - + req.getClass().getSimpleName()) - .build() - .handle(); - - return true; - } - - private void performExchanges(Socket clientSocket, int id) { - try { - JsonNode informationNode; - try (InputStream blockIn = BeaconFormat.readBlocks(clientSocket.getInputStream())) { - informationNode = JacksonMapper.getDefault().readTree(blockIn); - } - if (informationNode.isMissingNode()) { - TrackEvent.trace("Received EOF"); - return; - } - var information = - JacksonMapper.getDefault().treeToValue(informationNode, BeaconClient.ClientInformation.class); - try (var blockOut = BeaconFormat.writeBlocks(clientSocket.getOutputStream())) { - blockOut.write("\"ACK\"".getBytes(StandardCharsets.UTF_8)); - } - - TrackEvent.builder() - .type("trace") - .message("Created new socket connection #" + id) - .tag("client", information != null ? information.toDisplayString() : "Unknown") - .build() - .handle(); - - try { - while (true) { - if (!performExchange(clientSocket, id)) { - break; - } - } - TrackEvent.builder() - .type("trace") - .message("Socket connection #" + id + " finished successfully") - .build() - .handle(); - - } catch (ClientException ce) { - TrackEvent.trace("Sending client error to #" + id + ": " + ce.getMessage()); - sendClientErrorResponse(clientSocket, ce.getMessage()); - } catch (ServerException se) { - TrackEvent.trace("Sending server error to #" + id + ": " + se.getMessage()); - Deobfuscator.deobfuscate(se); - sendServerErrorResponse(clientSocket, se); - var toReport = se.getCause() != null ? se.getCause() : se; - ErrorEvent.fromThrowable(toReport).build().handle(); - } catch (SocketException ex) { - // Do not send error and omit it, as this might happen often - // This is expected if you kill a running xpipe CLI process - // We do not send the error to the client as the socket connection might be broken - ErrorEvent.fromThrowable(ex).omitted(true).expected().build().handle(); - } catch (Throwable ex) { - TrackEvent.trace("Sending internal server error to #" + id + ": " + ex.getMessage()); - Deobfuscator.deobfuscate(ex); - sendServerErrorResponse(clientSocket, ex); - ErrorEvent.fromThrowable(ex).build().handle(); - } - } catch (SocketException ex) { - // Omit it, as this might happen often - // This is expected if you kill a running xpipe CLI process - ErrorEvent.fromThrowable(ex).expected().omit().build().handle(); - } catch (Throwable ex) { - ErrorEvent.fromThrowable(ex).build().handle(); - } finally { - try { - clientSocket.close(); - TrackEvent.trace("Closed socket #" + id); - } catch (IOException e) { - ErrorEvent.fromThrowable(e).build().handle(); - } - } - - TrackEvent.builder().type("trace").message("Socket connection #" + id + " finished unsuccessfully"); - } - - private void performExchangesAsync(Socket clientSocket) { - var id = connectionCounter; - var t = new Thread( - () -> { - performExchanges(clientSocket, id); - }, - "socket connection #" + id); - t.start(); - } - - public OutputStream sendBody(Socket outSocket) throws IOException { - outSocket.getOutputStream().write(BeaconConfig.BODY_SEPARATOR); - return BeaconFormat.writeBlocks(outSocket.getOutputStream()); - } - - public InputStream receiveBody(Socket outSocket) throws IOException { - var read = outSocket.getInputStream().readNBytes(BeaconConfig.BODY_SEPARATOR.length); - if (!Arrays.equals(read, BeaconConfig.BODY_SEPARATOR)) { - throw new IOException("Expected body start (" + HexFormat.of().formatHex(BeaconConfig.BODY_SEPARATOR) - + ") but got " + HexFormat.of().formatHex(read)); - } - return BeaconFormat.readBlocks(outSocket.getInputStream()); - } - - public void sendResponse(Socket outSocket, T obj) throws Exception { - ObjectNode json = JacksonMapper.getDefault().valueToTree(obj); - var prov = MessageExchanges.byResponse(obj).get(); - json.set("messageType", new TextNode(prov.getId())); - json.set("messagePhase", new TextNode("response")); - var msg = JsonNodeFactory.instance.objectNode(); - msg.set("xPipeMessage", json); - - var writer = new StringWriter(); - var mapper = JacksonMapper.getDefault(); - try (JsonGenerator g = mapper.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) { - g.writeTree(msg); - } catch (IOException ex) { - throw new ConnectorException("Couldn't serialize request", ex); - } - - var content = writer.toString(); - TrackEvent.trace("Sending raw response:\n" + content); - try (OutputStream blockOut = BeaconFormat.writeBlocks(outSocket.getOutputStream())) { - blockOut.write(content.getBytes(StandardCharsets.UTF_8)); - } - } - - public void sendClientErrorResponse(Socket outSocket, String message) throws Exception { - var err = new ClientErrorMessage(message); - ObjectNode json = JacksonMapper.getDefault().valueToTree(err); - var msg = JsonNodeFactory.instance.objectNode(); - msg.set("xPipeClientError", json); - - // Don't log this as it clutters the output - // TrackEvent.trace("beacon", "Sending raw client error:\n" + json.toPrettyString()); - - var mapper = JacksonMapper.getDefault(); - try (OutputStream blockOut = BeaconFormat.writeBlocks(outSocket.getOutputStream())) { - var gen = mapper.createGenerator(blockOut); - gen.writeTree(msg); - } - } - - public void sendServerErrorResponse(Socket outSocket, Throwable ex) throws Exception { - var err = new ServerErrorMessage(UUID.randomUUID(), ex); - ObjectNode json = JacksonMapper.getDefault().valueToTree(err); - var msg = JsonNodeFactory.instance.objectNode(); - msg.set("xPipeServerError", json); - - // Don't log this as it clutters the output - // TrackEvent.trace("beacon", "Sending raw server error:\n" + json.toPrettyString()); - - var mapper = JacksonMapper.getDefault(); - try (OutputStream blockOut = BeaconFormat.writeBlocks(outSocket.getOutputStream())) { - var gen = mapper.createGenerator(blockOut); - gen.writeTree(msg); - } - } - - private T parseRequest(JsonNode header) throws Exception { - ObjectNode content = (ObjectNode) header.required("xPipeMessage"); - TrackEvent.trace("Parsed raw request:\n" + content.toPrettyString()); - - var type = content.required("messageType").textValue(); - var phase = content.required("messagePhase").textValue(); - if (!phase.equals("request")) { - throw new IllegalArgumentException("Not a request"); - } - content.remove("messageType"); - content.remove("messagePhase"); - - var prov = MessageExchangeImpls.byId(type); - if (prov.isEmpty()) { - throw new IllegalArgumentException("Unknown request id: " + type); - } - - var reader = JacksonMapper.getDefault().readerFor(prov.get().getRequestClass()); - return reader.readValue(content); - } -} 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 d3b8582d7..0b51a28ca 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 @@ -1,5 +1,6 @@ package io.xpipe.app.core.mode; +import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.store.StoreViewState; import io.xpipe.app.core.*; @@ -17,7 +18,6 @@ import io.xpipe.app.util.FileBridge; import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.LocalShell; import io.xpipe.app.util.UnlockAlert; -import io.xpipe.core.util.JacksonMapper; public class BaseMode extends OperationMode { @@ -43,8 +43,6 @@ public class BaseMode extends OperationMode { // if (true) throw new IllegalStateException(); TrackEvent.info("Initializing base mode components ..."); - AppExtensionManager.init(true); - JacksonMapper.initModularized(AppExtensionManager.getInstance().getExtendedLayer()); AppI18n.init(); LicenseProvider.get().init(); AppPrefs.initLocal(); @@ -56,8 +54,8 @@ public class BaseMode extends OperationMode { AppShellCheck.check(); XPipeDistributionType.init(); AppPrefs.setDefaults(); - // Initialize socket server as we should be prepared for git askpass commands - AppSocketServer.init(); + // Initialize beacon server as we should be prepared for git askpass commands + AppBeaconServer.init(); GitStorageHandler.getInstance().init(); GitStorageHandler.getInstance().setupRepositoryAndPull(); AppPrefs.initSharedRemote(); @@ -85,8 +83,8 @@ public class BaseMode extends OperationMode { AppResources.reset(); AppExtensionManager.reset(); AppDataLock.unlock(); - // Shut down socket server last to keep a non-daemon thread running - AppSocketServer.reset(); + // Shut down server last to keep a non-daemon thread running + AppBeaconServer.reset(); TrackEvent.info("Background mode shutdown finished"); } } 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 7614c0f4b..d3dadb818 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 @@ -109,6 +109,7 @@ public abstract class OperationMode { AppProperties.logArguments(args); AppProperties.logSystemProperties(); AppProperties.logPassedProperties(); + AppExtensionManager.init(true); TrackEvent.info("Finished initial setup"); } catch (Throwable ex) { ErrorEvent.fromThrowable(ex).term().handle(); diff --git a/app/src/main/java/io/xpipe/app/exchange/DialogExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/DialogExchangeImpl.java deleted file mode 100644 index b6d46c203..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/DialogExchangeImpl.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.issue.TrackEvent; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.DialogExchange; -import io.xpipe.core.dialog.Dialog; -import io.xpipe.core.dialog.DialogReference; -import io.xpipe.core.util.FailableConsumer; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class DialogExchangeImpl extends DialogExchange - implements MessageExchangeImpl { - - private static final Map openDialogs = new HashMap<>(); - private static final Map> openDialogConsumers = new HashMap<>(); - - public static DialogReference add(Dialog d, FailableConsumer onCompletion) throws Exception { - return add(d, UUID.randomUUID(), onCompletion); - } - - public static DialogReference add(Dialog d, UUID uuid, FailableConsumer onCompletion) - throws Exception { - openDialogs.put(uuid, d); - openDialogConsumers.put(uuid, onCompletion); - return new DialogReference(uuid, d.start()); - } - - @Override - public DialogExchange.Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - if (msg.isCancel()) { - TrackEvent.withTrace("Received cancel dialog request") - .tag("key", msg.getDialogKey()) - .handle(); - openDialogs.remove(msg.getDialogKey()); - openDialogConsumers.remove(msg.getDialogKey()); - return DialogExchange.Response.builder().element(null).build(); - } - - var dialog = openDialogs.get(msg.getDialogKey()); - var e = dialog.receive(msg.getValue()); - - TrackEvent.withTrace("Received normal dialog request") - .tag("key", msg.getDialogKey()) - .tag("value", msg.getValue()) - .tag("newElement", e) - .handle(); - - if (e == null) { - openDialogs.remove(msg.getDialogKey()); - var con = openDialogConsumers.remove(msg.getDialogKey()); - con.accept(dialog.getResult()); - } - - return DialogExchange.Response.builder().element(e).build(); - // - // - // var provider = getProvider(msg.getInstance().getProvider()); - // var completeConfig = toCompleteConfig(provider); - // - // var option = completeConfig.keySet().stream() - // .filter(o -> o.getKey().equals(msg.getKey())).findAny() - // .orElseThrow(() -> new ClientException("Invalid config key: " + msg.getKey())); - // - // String errorMsg = null; - // try { - // option.getConverter().convertFromString(msg.getValue()); - // } catch (Exception ex) { - // errorMsg = ex.getMessage(); - // } - // - // return DialogExchange.Response.builder().errorMsg(errorMsg).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/FocusExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/FocusExchangeImpl.java deleted file mode 100644 index 2b5181d5d..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/FocusExchangeImpl.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.FocusExchange; - -public class FocusExchangeImpl extends FocusExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - OperationMode.switchUp(OperationMode.map(msg.getMode())); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java deleted file mode 100644 index a7dfb5a7c..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/LaunchExchangeImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.LaunchExchange; -import io.xpipe.core.store.LaunchableStore; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class LaunchExchangeImpl extends LaunchExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var store = getStoreEntryById(msg.getId(), false); - if (store.getStore() instanceof LaunchableStore s) { - // var command = s.prepareLaunchCommand() - // .prepareTerminalOpen(TerminalInitScriptConfig.ofName(store.getName()), sc -> null); - // return Response.builder().command(split(command)).build(); - } - - throw new IllegalArgumentException(store.getName() + " is not launchable"); - } - - private List split(String command) { - var split = Arrays.stream(command.split(" ", 3)).collect(Collectors.toList()); - var s = split.get(2); - if ((s.startsWith("\"") && s.endsWith("\"")) || (s.startsWith("'") && s.endsWith("'"))) { - split.set(2, s.substring(1, s.length() - 1)); - } - return split; - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpl.java deleted file mode 100644 index f73b7583a..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.storage.DataStorage; -import io.xpipe.app.storage.DataStoreEntry; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.core.store.DataStoreId; - -import lombok.NonNull; - -public interface MessageExchangeImpl extends MessageExchange { - - default DataStoreEntry getStoreEntryByName(@NonNull String name, boolean acceptDisabled) throws ClientException { - var store = DataStorage.get().getStoreEntryIfPresent(name); - if (store.isEmpty()) { - throw new ClientException("No store with name " + name + " was found"); - } - if (store.get().isDisabled() && !acceptDisabled) { - throw new ClientException( - String.format("Store %s is disabled", store.get().getName())); - } - return store.get(); - } - - default DataStoreEntry getStoreEntryById(@NonNull DataStoreId id, boolean acceptUnusable) throws ClientException { - var store = DataStorage.get().getStoreEntryIfPresent(id); - if (store.isEmpty()) { - throw new ClientException("No store with id " + id + " was found"); - } - if (store.get().isDisabled() && !acceptUnusable) { - throw new ClientException( - String.format("Store %s is disabled", store.get().getName())); - } - if (!store.get().getValidity().isUsable() && !acceptUnusable) { - throw new ClientException(String.format( - "Store %s is not completely configured", store.get().getName())); - } - return store.get(); - } - - String getId(); - - RS handleRequest(BeaconHandler handler, RQ msg) throws Exception; -} diff --git a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java b/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java deleted file mode 100644 index 94a18b15b..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/MessageExchangeImpls.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchanges; -import io.xpipe.core.util.ModuleLayerLoader; - -import java.util.List; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.stream.Collectors; - -public class MessageExchangeImpls { - - private static List> ALL; - - @SuppressWarnings("unchecked") - public static Optional> byId( - String name) { - var r = ALL.stream().filter(d -> d.getId().equals(name)).findAny(); - return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); - } - - @SuppressWarnings("unchecked") - public static - Optional> byRequest(RQ req) { - var r = ALL.stream() - .filter(d -> d.getRequestClass().equals(req.getClass())) - .findAny(); - return Optional.ofNullable((MessageExchangeImpl) r.orElse(null)); - } - - public static List> getAll() { - return ALL; - } - - public static class Loader implements ModuleLayerLoader { - - @Override - public void init(ModuleLayer layer) { - ALL = ServiceLoader.load(layer, MessageExchangeImpl.class).stream() - .map(s -> { - // TrackEvent.trace("init", "Loaded exchange implementation " + ex.getId()); - return (MessageExchangeImpl) s.get(); - }) - .collect(Collectors.toList()); - - ALL.forEach(messageExchange -> { - if (MessageExchanges.byId(messageExchange.getId()).isEmpty()) { - throw new AssertionError("Missing base exchange: " + messageExchange.getId()); - } - }); - - MessageExchanges.getAll().forEach(messageExchange -> { - if (MessageExchangeImpls.byId(messageExchange.getId()).isEmpty()) { - throw new AssertionError("Missing exchange implementation: " + messageExchange.getId()); - } - }); - } - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/OpenExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/OpenExchangeImpl.java deleted file mode 100644 index 3a9730a04..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/OpenExchangeImpl.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.launcher.LauncherInput; -import io.xpipe.app.util.PlatformState; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ServerException; -import io.xpipe.beacon.exchange.OpenExchange; - -public class OpenExchangeImpl extends OpenExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws ServerException { - if (msg.getArguments().isEmpty()) { - if (!OperationMode.switchToSyncIfPossible(OperationMode.GUI)) { - throw new ServerException(PlatformState.getLastError()); - } - } - - LauncherInput.handle(msg.getArguments()); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/QueryStoreExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/QueryStoreExchangeImpl.java deleted file mode 100644 index 39f546597..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/QueryStoreExchangeImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.QueryStoreExchange; -import io.xpipe.core.dialog.DialogMapper; - -public class QueryStoreExchangeImpl extends QueryStoreExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var store = getStoreEntryByName(msg.getName(), true); - var summary = ""; - var dialog = store.getProvider().dialogForStore(store.getStore().asNeeded()); - var config = new DialogMapper(dialog).handle(); - return Response.builder() - .summary(summary) - .internalStore(store.getStore()) - .provider(store.getProvider().getId()) - .config(config) - .build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/TerminalLaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/TerminalLaunchExchangeImpl.java deleted file mode 100644 index 5540de7f3..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/TerminalLaunchExchangeImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.util.TerminalLauncherManager; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.TerminalLaunchExchange; - -public class TerminalLaunchExchangeImpl extends TerminalLaunchExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws ClientException { - var r = TerminalLauncherManager.performLaunch(msg.getRequest()); - return Response.builder().targetFile(r).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/TerminalWaitExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/TerminalWaitExchangeImpl.java deleted file mode 100644 index bac98a9e2..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/TerminalWaitExchangeImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.xpipe.app.exchange; - -import io.xpipe.app.util.TerminalLauncherManager; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.ServerException; -import io.xpipe.beacon.exchange.TerminalWaitExchange; - -public class TerminalWaitExchangeImpl extends TerminalWaitExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws ServerException, ClientException { - TerminalLauncherManager.waitForCompletion(msg.getRequest()); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/DrainExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/DrainExchangeImpl.java deleted file mode 100644 index 5cdd9b159..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/DrainExchangeImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.DrainExchange; -import io.xpipe.core.store.ShellStore; - -public class DrainExchangeImpl extends DrainExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var ds = getStoreEntryById(msg.getSource(), false); - - if (!(ds.getStore() instanceof ShellStore)) { - throw new ClientException("Can't open file system for connection"); - } - - handler.postResponse(() -> { - ShellStore store = ds.getStore().asNeeded(); - try (var fs = store.createFileSystem(); - var output = handler.sendBody(); - var inputStream = fs.openInput(msg.getPath())) { - inputStream.transferTo(output); - } - }); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/EditStoreExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/EditStoreExchangeImpl.java deleted file mode 100644 index b13c3045c..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/EditStoreExchangeImpl.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.DialogExchangeImpl; -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.EditStoreExchange; -import io.xpipe.core.store.DataStore; - -public class EditStoreExchangeImpl extends EditStoreExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var s = getStoreEntryByName(msg.getName(), false); - var dialog = s.getProvider().dialogForStore(s.getStore()); - var reference = DialogExchangeImpl.add(dialog, (DataStore newStore) -> { - // s.setStore(newStore); - }); - return Response.builder().dialog(reference).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/ListStoresExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/ListStoresExchangeImpl.java deleted file mode 100644 index 09a449776..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/ListStoresExchangeImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.ListStoresExchange; -import io.xpipe.beacon.exchange.data.StoreListEntry; - -import java.util.Comparator; -import java.util.List; - -public class ListStoresExchangeImpl extends ListStoresExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - DataStorage s = DataStorage.get(); - if (s == null) { - return Response.builder().entries(List.of()).build(); - } - - var e = s.getStoreEntries().stream() - .filter(entry -> !entry.isDisabled()) - .map(col -> StoreListEntry.builder() - .id(DataStorage.get().getId(col)) - .type(col.getProvider().getId()) - .build()) - .sorted(Comparator.comparing(en -> en.getId().toString())) - .toList(); - return Response.builder().entries(e).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/ModeExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/ModeExchangeImpl.java deleted file mode 100644 index d08a88c6e..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/ModeExchangeImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.util.ThreadHelper; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.cli.ModeExchange; - -public class ModeExchangeImpl extends ModeExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - // Wait for startup - while (OperationMode.get() == null) { - ThreadHelper.sleep(100); - } - - var mode = OperationMode.map(msg.getMode()); - if (!mode.isSupported()) { - throw new ClientException("Unsupported mode: " + msg.getMode().getDisplayName() + ". Supported: " - + String.join( - ", ", - OperationMode.getAll().stream() - .filter(OperationMode::isSupported) - .map(OperationMode::getId) - .toList())); - } - - OperationMode.switchToSyncIfPossible(mode); - return ModeExchange.Response.builder() - .usedMode(OperationMode.map(OperationMode.get())) - .build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/ReadDrainExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/ReadDrainExchangeImpl.java deleted file mode 100644 index 2cc03a8f4..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/ReadDrainExchangeImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.ReadDrainExchange; - -public class ReadDrainExchangeImpl extends ReadDrainExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - return ReadDrainExchange.Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/RemoveStoreExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/RemoveStoreExchangeImpl.java deleted file mode 100644 index 25ee3208c..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/RemoveStoreExchangeImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.cli.RemoveStoreExchange; -import io.xpipe.core.store.DataStoreId; - -public class RemoveStoreExchangeImpl extends RemoveStoreExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var s = getStoreEntryById(DataStoreId.fromString(msg.getStoreName()), true); - if (!s.getConfiguration().isDeletable()) { - throw new ClientException("Store is not deletable"); - } - - DataStorage.get().deleteStoreEntry(s); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/RenameStoreExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/RenameStoreExchangeImpl.java deleted file mode 100644 index eccd5546e..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/RenameStoreExchangeImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.cli.RenameStoreExchange; -import io.xpipe.core.store.DataStoreId; - -public class RenameStoreExchangeImpl extends RenameStoreExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws ClientException { - var s = getStoreEntryById(DataStoreId.fromString(msg.getStoreName()), true); - s.setName(msg.getNewName()); - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/SinkExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/SinkExchangeImpl.java deleted file mode 100644 index 79ddef7f0..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/SinkExchangeImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.SinkExchange; -import io.xpipe.core.store.ShellStore; - -public class SinkExchangeImpl extends SinkExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) throws Exception { - var ds = getStoreEntryById(msg.getSource(), false); - - if (!(ds.getStore() instanceof ShellStore)) { - throw new ClientException("Can't open file system for connection"); - } - - ShellStore store = ds.getStore().asNeeded(); - try (var fs = store.createFileSystem(); - var inputStream = handler.receiveBody(); - var output = fs.openOutput(msg.getPath(), -1)) { - inputStream.transferTo(output); - } - - return Response.builder().build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/StatusExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/StatusExchangeImpl.java deleted file mode 100644 index 520a2e913..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/StatusExchangeImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.StatusExchange; - -public class StatusExchangeImpl extends StatusExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - String mode; - if (OperationMode.get() == null) { - mode = "none"; - } else { - mode = OperationMode.get().getId(); - } - - return Response.builder().mode(mode).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/StopExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/StopExchangeImpl.java deleted file mode 100644 index df02c0b6d..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/StopExchangeImpl.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.core.mode.OperationMode; -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.util.ThreadHelper; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.StopExchange; - -public class StopExchangeImpl extends StopExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - handler.postResponse(() -> { - ThreadHelper.runAsync(() -> { - ThreadHelper.sleep(1000); - OperationMode.close(); - }); - }); - return Response.builder().success(true).build(); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/StoreAddExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/StoreAddExchangeImpl.java deleted file mode 100644 index ee47a65a9..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/StoreAddExchangeImpl.java +++ /dev/null @@ -1,141 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.DialogExchangeImpl; -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.ext.DataStoreProvider; -import io.xpipe.app.ext.DataStoreProviders; -import io.xpipe.app.storage.DataStorage; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.exchange.cli.StoreAddExchange; -import io.xpipe.core.dialog.Choice; -import io.xpipe.core.dialog.Dialog; -import io.xpipe.core.dialog.QueryConverter; -import io.xpipe.core.store.DataStore; - -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; - -import lombok.SneakyThrows; - -import java.util.List; - -public class StoreAddExchangeImpl extends StoreAddExchange - implements MessageExchangeImpl { - - @Override - @SneakyThrows - public StoreAddExchange.Response handleRequest(BeaconHandler handler, Request msg) { - Dialog creatorDialog; - DataStoreProvider provider; - if (msg.getStoreInput() != null) { - creatorDialog = Dialog.empty().evaluateTo(msg::getStoreInput); - provider = null; - } else { - if (msg.getType() == null) { - throw new ClientException("Missing data store tight"); - } - - provider = DataStoreProviders.byName(msg.getType()).orElseThrow(() -> { - return new ClientException("Unrecognized data store type: " + msg.getType()); - }); - - creatorDialog = provider.dialogForStore(provider.defaultStore()); - } - - var name = new SimpleStringProperty(msg.getName()); - var completeDialog = createCompleteDialog(provider, creatorDialog, name); - var config = DialogExchangeImpl.add(completeDialog, (DataStore store) -> { - if (store == null) { - return; - } - - DataStorage.get().addStoreIfNotPresent(name.getValue(), store); - }); - - return StoreAddExchange.Response.builder().config(config).build(); - } - - private Dialog createCompleteDialog(DataStoreProvider provider, Dialog creator, StringProperty name) { - var validator = Dialog.header(() -> { - DataStore store = creator.getResult(); - if (store == null) { - return "Store is null"; - } - - return null; - }) - .map((String msg) -> { - return msg == null ? creator.getResult() : null; - }); - - var creatorAndValidator = Dialog.chain(creator, Dialog.busy(), validator); - - var nameQ = Dialog.retryIf( - Dialog.query("Store name", true, true, false, name.getValue(), QueryConverter.STRING), - (String r) -> { - return DataStorage.get().getStoreEntryIfPresent(r).isPresent() - ? "Store with name " + r + " already exists" - : null; - }) - .onCompletion((String n) -> name.setValue(n)); - - var display = Dialog.header(() -> { - if (provider == null) { - return "Successfully created data store " + name.get(); - } - - DataStore s = creator.getResult(); - String d = ""; - d = d.indent(2); - return "Successfully created data store " + name.get() + ":\n" + d; - }); - - if (provider == null) { - return Dialog.chain( - creatorAndValidator, Dialog.skipIf(display, () -> creatorAndValidator.getResult() == null)) - .evaluateTo(creatorAndValidator); - } - - var aborted = new SimpleBooleanProperty(); - var addStore = - Dialog.skipIf(Dialog.chain(nameQ, display), () -> aborted.get() || validator.getResult() == null); - - var prop = new SimpleObjectProperty(); - var fork = Dialog.skipIf( - Dialog.fork( - "Choose how to continue", - List.of( - new Choice('r', "Retry"), - new Choice('i', "Ignore and continue"), - new Choice('e', "Edit configuration"), - new Choice('a', "Abort")), - true, - 0, - (Integer choice) -> { - if (choice == 0) { - return Dialog.chain(Dialog.busy(), validator, prop.get()); - } - if (choice == 1) { - return null; - } - if (choice == 2) { - return Dialog.chain(creatorAndValidator, prop.get()); - } - if (choice == 3) { - aborted.set(true); - return null; - } - - throw new AssertionError(); - }) - .evaluateTo(() -> null), - () -> validator.getResult() != null); - prop.set(fork); - - return Dialog.chain(creatorAndValidator, fork, addStore) - .evaluateTo(() -> aborted.get() ? null : creator.getResult()); - } -} diff --git a/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java b/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java deleted file mode 100644 index b89861049..000000000 --- a/app/src/main/java/io/xpipe/app/exchange/cli/StoreProviderListExchangeImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.xpipe.app.exchange.cli; - -import io.xpipe.app.exchange.MessageExchangeImpl; -import io.xpipe.app.ext.DataStoreProvider; -import io.xpipe.app.ext.DataStoreProviders; -import io.xpipe.beacon.BeaconHandler; -import io.xpipe.beacon.exchange.cli.StoreProviderListExchange; -import io.xpipe.beacon.exchange.data.ProviderEntry; - -import java.util.Arrays; -import java.util.stream.Collectors; - -public class StoreProviderListExchangeImpl extends StoreProviderListExchange - implements MessageExchangeImpl { - - @Override - public Response handleRequest(BeaconHandler handler, Request msg) { - var categories = DataStoreProvider.CreationCategory.values(); - var all = DataStoreProviders.getAll(); - var map = Arrays.stream(categories) - .collect(Collectors.toMap(category -> getName(category), category -> all.stream() - .filter(dataStoreProvider -> category.equals(dataStoreProvider.getCreationCategory())) - .map(p -> ProviderEntry.builder() - .id(p.getId()) - .description(p.displayDescription().getValue()) - .hidden(p.getCreationCategory() == null) - .build()) - .toList())); - - return Response.builder().entries(map).build(); - } - - private String getName(DataStoreProvider.CreationCategory category) { - return category.name().substring(0, 1).toUpperCase() - + category.name().substring(1).toLowerCase(); - } -} 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 b47f84e64..c46b7cb21 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherCommand.java @@ -10,12 +10,11 @@ import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.util.ThreadHelper; import io.xpipe.beacon.BeaconServer; -import io.xpipe.beacon.exchange.FocusExchange; -import io.xpipe.beacon.exchange.OpenExchange; +import io.xpipe.beacon.api.FocusExchange; +import io.xpipe.beacon.api.OpenExchange; import io.xpipe.core.process.OsType; import io.xpipe.core.util.XPipeDaemonMode; import io.xpipe.core.util.XPipeInstallation; - import lombok.SneakyThrows; import picocli.CommandLine; @@ -83,10 +82,8 @@ public class LauncherCommand implements Callable { try { if (BeaconServer.isReachable()) { try (var con = new LauncherConnection()) { - con.constructSocket(); - con.performSimpleExchange(FocusExchange.Request.builder() - .mode(getEffectiveMode()) - .build()); + con.establishConnection(); + con.performSimpleExchange(FocusExchange.Request.builder().mode(getEffectiveMode()).build()); if (!inputs.isEmpty()) { con.performSimpleExchange( OpenExchange.Request.builder().arguments(inputs).build()); @@ -94,9 +91,11 @@ public class LauncherCommand implements Callable { if (OsType.getLocal().equals(OsType.MACOS)) { Desktop.getDesktop().setOpenURIHandler(e -> { - con.performSimpleExchange(OpenExchange.Request.builder() - .arguments(List.of(e.getURI().toString())) - .build()); + try { + con.performSimpleExchange(OpenExchange.Request.builder().arguments(List.of(e.getURI().toString())).build()); + } catch (Exception ex) { + ErrorEvent.fromThrowable(ex).expected().omit().handle(); + } }); ThreadHelper.sleep(1000); } diff --git a/app/src/main/java/io/xpipe/app/launcher/LauncherConnection.java b/app/src/main/java/io/xpipe/app/launcher/LauncherConnection.java index fdbe0a25c..e8208924a 100644 --- a/app/src/main/java/io/xpipe/app/launcher/LauncherConnection.java +++ b/app/src/main/java/io/xpipe/app/launcher/LauncherConnection.java @@ -1,18 +1,19 @@ package io.xpipe.app.launcher; import io.xpipe.beacon.BeaconClient; +import io.xpipe.beacon.BeaconClientInformation; import io.xpipe.beacon.BeaconConnection; -import io.xpipe.beacon.BeaconException; +import io.xpipe.beacon.BeaconConnectorException; public class LauncherConnection extends BeaconConnection { @Override - protected void constructSocket() { + protected void establishConnection() throws Exception { try { beaconClient = BeaconClient.establishConnection( - BeaconClient.DaemonInformation.builder().build()); + BeaconClientInformation.DaemonInformation.builder().build()); } catch (Exception ex) { - throw new BeaconException("Unable to connect to running xpipe daemon", ex); + throw new BeaconConnectorException("Unable to connect to running xpipe daemon", ex); } } } diff --git a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java index 936e34e4f..152c02bf6 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java @@ -1,13 +1,12 @@ package io.xpipe.app.util; -import io.xpipe.beacon.ClientException; -import io.xpipe.beacon.ServerException; +import io.xpipe.beacon.BeaconClientException; +import io.xpipe.beacon.BeaconServerException; import io.xpipe.core.process.ProcessControl; import io.xpipe.core.process.ShellControl; import io.xpipe.core.process.TerminalInitScriptConfig; import io.xpipe.core.process.WorkingDirectoryFunction; import io.xpipe.core.store.FilePath; - import lombok.Setter; import lombok.Value; import lombok.experimental.NonFinal; @@ -73,10 +72,10 @@ public class TerminalLauncherManager { return latch; } - public static Path waitForCompletion(UUID request) throws ClientException, ServerException { + public static Path waitForCompletion(UUID request) throws BeaconClientException, BeaconServerException { var e = entries.get(request); if (e == null) { - throw new ClientException("Unknown launch request " + request); + throw new BeaconClientException("Unknown launch request " + request); } while (true) { @@ -89,21 +88,21 @@ public class TerminalLauncherManager { if (r instanceof ResultFailure failure) { entries.remove(request); var t = failure.getThrowable(); - throw new ServerException(t); + throw new BeaconServerException(t); } return ((ResultSuccess) r).getTargetScript(); } } - public static Path performLaunch(UUID request) throws ClientException { + public static Path performLaunch(UUID request) throws BeaconClientException { var e = entries.remove(request); if (e == null) { - throw new ClientException("Unknown launch request " + request); + throw new BeaconClientException("Unknown launch request " + request); } if (!(e.result instanceof ResultSuccess)) { - throw new ClientException("Invalid launch request state " + request); + throw new BeaconClientException("Invalid launch request state " + request); } return ((ResultSuccess) e.getResult()).getTargetScript(); diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index a0d3e8280..205d95cef 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -1,7 +1,7 @@ +import com.fasterxml.jackson.databind.Module; +import io.xpipe.app.beacon.impl.*; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.core.AppLogs; -import io.xpipe.app.exchange.*; -import io.xpipe.app.exchange.cli.*; import io.xpipe.app.ext.*; import io.xpipe.app.issue.EventHandler; import io.xpipe.app.issue.EventHandlerImpl; @@ -10,12 +10,11 @@ import io.xpipe.app.util.AppJacksonModule; import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.ProxyManagerProviderImpl; import io.xpipe.app.util.TerminalLauncher; +import io.xpipe.beacon.BeaconInterface; import io.xpipe.core.util.DataStateProvider; import io.xpipe.core.util.ModuleLayerLoader; import io.xpipe.core.util.ProxyFunction; import io.xpipe.core.util.ProxyManagerProvider; - -import com.fasterxml.jackson.databind.Module; import org.slf4j.spi.SLF4JServiceProvider; open module io.xpipe.app { @@ -52,6 +51,7 @@ open module io.xpipe.app { requires com.vladsch.flexmark; requires com.fasterxml.jackson.core; requires com.fasterxml.jackson.databind; + requires com.fasterxml.jackson.annotation; requires net.synedra.validatorfx; requires org.kordamp.ikonli.feather; requires io.xpipe.modulefs; @@ -79,14 +79,6 @@ open module io.xpipe.app { requires net.steppschuh.markdowngenerator; requires com.shinyhut.vernacular; - // Required by extensions - requires java.security.jgss; - requires java.security.sasl; - requires java.xml; - requires java.xml.crypto; - requires java.sql; - requires java.sql.rowset; - // Required runtime modules requires jdk.charsets; requires jdk.crypto.cryptoki; @@ -100,8 +92,8 @@ open module io.xpipe.app { // For debugging requires jdk.jdwp.agent; requires org.kordamp.ikonli.core; + requires jdk.httpserver; - uses MessageExchangeImpl; uses TerminalLauncher; uses io.xpipe.app.ext.ActionProvider; uses EventHandler; @@ -113,11 +105,11 @@ open module io.xpipe.app { uses BrowserAction; uses LicenseProvider; uses io.xpipe.app.util.LicensedFeature; + uses io.xpipe.beacon.BeaconInterface; provides Module with AppJacksonModule; provides ModuleLayerLoader with - MessageExchangeImpls.Loader, DataStoreProviders.Loader, ActionProvider.Loader, PrefsProvider.Loader, @@ -132,26 +124,15 @@ open module io.xpipe.app { AppLogs.Slf4jProvider; provides EventHandler with EventHandlerImpl; - provides MessageExchangeImpl with - ReadDrainExchangeImpl, - EditStoreExchangeImpl, - StoreProviderListExchangeImpl, + provides BeaconInterface with OpenExchangeImpl, - LaunchExchangeImpl, FocusExchangeImpl, StatusExchangeImpl, - DrainExchangeImpl, - SinkExchangeImpl, StopExchangeImpl, + HandshakeExchangeImpl, ModeExchangeImpl, - DialogExchangeImpl, - RemoveStoreExchangeImpl, - RenameStoreExchangeImpl, - ListStoresExchangeImpl, - StoreAddExchangeImpl, AskpassExchangeImpl, TerminalWaitExchangeImpl, TerminalLaunchExchangeImpl, - QueryStoreExchangeImpl, VersionExchangeImpl; } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java index 8ccf6b9e5..92cb56e41 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java @@ -1,67 +1,28 @@ package io.xpipe.beacon; -import io.xpipe.beacon.exchange.MessageExchanges; -import io.xpipe.beacon.exchange.data.ClientErrorMessage; -import io.xpipe.beacon.exchange.data.ServerErrorMessage; -import io.xpipe.core.util.Deobfuscator; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.xpipe.beacon.api.HandshakeExchange; import io.xpipe.core.util.JacksonMapper; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.node.TextNode; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringWriter; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.util.Optional; -import static io.xpipe.beacon.BeaconConfig.BODY_SEPARATOR; +public class BeaconClient { -public class BeaconClient implements AutoCloseable { + private String token; - @Getter - private final AutoCloseable base; - - private final InputStream in; - private final OutputStream out; - - private BeaconClient(AutoCloseable base, InputStream in, OutputStream out) { - this.base = base; - this.in = in; - this.out = out; - } - - public static BeaconClient establishConnection(ClientInformation information) throws Exception { - var socket = new Socket(); - socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), BeaconConfig.getUsedPort()), 5000); - socket.setSoTimeout(5000); - var client = new BeaconClient(socket, socket.getInputStream(), socket.getOutputStream()); - client.sendObject(JacksonMapper.getDefault().valueToTree(information)); - var res = client.receiveObject(); - if (!res.isTextual() || !"ACK".equals(res.asText())) { - throw new BeaconException("Daemon responded with invalid acknowledgement"); - } - socket.setSoTimeout(0); + public static BeaconClient establishConnection(BeaconClientInformation information) throws Exception { + var client = new BeaconClient(); + HandshakeExchange.Response response = client.performRequest(HandshakeExchange.Request.builder().client(information).build()); + client.token = response.getToken(); return client; } - public static Optional tryEstablishConnection(ClientInformation information) { + public static Optional tryEstablishConnection(BeaconClientInformation information) { try { return Optional.of(establishConnection(information)); } catch (Exception ex) { @@ -69,246 +30,92 @@ public class BeaconClient implements AutoCloseable { } } - public void close() throws ConnectorException { - try { - base.close(); - } catch (Exception ex) { - throw new ConnectorException("Couldn't close client", ex); - } - } - public InputStream receiveBody() throws ConnectorException { - try { - var sep = in.readNBytes(BODY_SEPARATOR.length); - if (sep.length != 0 && !Arrays.equals(BODY_SEPARATOR, sep)) { - throw new ConnectorException("Invalid body separator"); - } - return BeaconFormat.readBlocks(in); - } catch (IOException ex) { - throw new ConnectorException(ex); - } - } - - public OutputStream sendBody() throws ConnectorException { - try { - out.write(BODY_SEPARATOR); - return BeaconFormat.writeBlocks(out); - } catch (IOException ex) { - throw new ConnectorException(ex); - } - } - - public void sendRequest(T req) throws ClientException, ConnectorException { - ObjectNode json = JacksonMapper.getDefault().valueToTree(req); - var prov = MessageExchanges.byRequest(req); - if (prov.isEmpty()) { - throw new ClientException("Unknown request class " + req.getClass()); - } - - json.set("messageType", new TextNode(prov.get().getId())); - json.set("messagePhase", new TextNode("request")); - // json.set("id", new TextNode(UUID.randomUUID().toString())); - var msg = JsonNodeFactory.instance.objectNode(); - msg.set("xPipeMessage", json); - - if (BeaconConfig.printMessages()) { - System.out.println( - "Sending request to server of type " + req.getClass().getName()); - } - - sendObject(msg); - } - - public void sendEOF() throws ConnectorException { - try (OutputStream ignored = BeaconFormat.writeBlocks(out)) { - } catch (IOException ex) { - throw new ConnectorException("Couldn't write to socket", ex); - } - } - - public void sendObject(JsonNode node) throws ConnectorException { - var writer = new StringWriter(); - var mapper = JacksonMapper.getDefault(); - try (JsonGenerator g = mapper.createGenerator(writer).setPrettyPrinter(new DefaultPrettyPrinter())) { - g.writeTree(node); - } catch (IOException ex) { - throw new ConnectorException("Couldn't serialize request", ex); - } - - var content = writer.toString(); + @SuppressWarnings("unchecked") + public RES performRequest(BeaconInterface prov, String rawNode) throws + BeaconConnectorException, BeaconClientException, BeaconServerException { + var content = rawNode; if (BeaconConfig.printMessages()) { System.out.println("Sending raw request:"); System.out.println(content); } - try (OutputStream blockOut = BeaconFormat.writeBlocks(out)) { - blockOut.write(content.getBytes(StandardCharsets.UTF_8)); - } catch (IOException ex) { - throw new ConnectorException("Couldn't write to socket", ex); - } - } - - public T receiveResponse() throws ConnectorException, ClientException, ServerException { - return parseResponse(receiveObject()); - } - - private JsonNode receiveObject() throws ConnectorException, ClientException, ServerException { - JsonNode node; - try (InputStream blockIn = BeaconFormat.readBlocks(in)) { - node = JacksonMapper.getDefault().readTree(blockIn); - } catch (IOException ex) { - throw new ConnectorException("Couldn't read from socket", ex); + var client = HttpClient.newHttpClient(); + HttpResponse response; + try { + var uri = URI.create("http://localhost:" + BeaconConfig.getUsedPort() + prov.getPath()); + var builder = HttpRequest.newBuilder(); + if (token != null) { + builder.header("Authorization", "Bearer " + token); + } + var httpRequest = builder + .uri(uri).POST(HttpRequest.BodyPublishers.ofString(content)).build(); + response = client.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + } catch (Exception ex) { + throw new BeaconConnectorException("Couldn't send request", ex); } if (BeaconConfig.printMessages()) { - System.out.println("Received response:"); - System.out.println(node.toPrettyString()); + System.out.println("Received raw response:"); + System.out.println(response.body()); } - if (node.isMissingNode()) { - throw new ConnectorException("Received unexpected EOF"); - } - - var se = parseServerError(node); + var se = parseServerError(response); if (se.isPresent()) { se.get().throwError(); } - var ce = parseClientError(node); + var ce = parseClientError(response); if (ce.isPresent()) { throw ce.get().throwException(); } - return node; - } - - private Optional parseClientError(JsonNode node) throws ConnectorException { - ObjectNode content = (ObjectNode) node.get("xPipeClientError"); - if (content == null) { - return Optional.empty(); - } - try { - var message = JacksonMapper.getDefault().treeToValue(content, ClientErrorMessage.class); - return Optional.of(message); + var reader = JacksonMapper.getDefault().readerFor(prov.getResponseClass()); + var v = (RES) reader.readValue(response.body()); + return v; } catch (IOException ex) { - throw new ConnectorException("Couldn't parse client error message", ex); + throw new BeaconConnectorException("Couldn't parse response", ex); } } - private Optional parseServerError(JsonNode node) throws ConnectorException { - ObjectNode content = (ObjectNode) node.get("xPipeServerError"); - if (content == null) { - return Optional.empty(); - } - - try { - var message = JacksonMapper.getDefault().treeToValue(content, ServerErrorMessage.class); - Deobfuscator.deobfuscate(message.getError()); - return Optional.of(message); - } catch (IOException ex) { - throw new ConnectorException("Couldn't parse server error message", ex); - } - } - - private T parseResponse(JsonNode header) throws ConnectorException { - ObjectNode content = (ObjectNode) header.required("xPipeMessage"); - - var type = content.required("messageType").textValue(); - var phase = content.required("messagePhase").textValue(); - // var requestId = UUID.fromString(content.required("id").textValue()); - if (!phase.equals("response")) { - throw new IllegalArgumentException(); - } - content.remove("messageType"); - content.remove("messagePhase"); - // content.remove("id"); - - var prov = MessageExchanges.byId(type); + public RES performRequest(REQ req) throws BeaconConnectorException, BeaconClientException, BeaconServerException { + ObjectNode node = JacksonMapper.getDefault().valueToTree(req); + var prov = BeaconInterface.byRequest(req); if (prov.isEmpty()) { - throw new IllegalArgumentException("Unknown response id " + type); + throw new IllegalArgumentException("Unknown request class " + req.getClass()); + } + if (BeaconConfig.printMessages()) { + System.out.println("Sending request to server of type " + req.getClass().getName()); + } + + return performRequest(prov.get(), node.toPrettyString()); + } + + private Optional parseClientError(HttpResponse response) throws BeaconConnectorException { + if (response.statusCode() < 400 || response.statusCode() > 499) { + return Optional.empty(); } try { - var reader = JacksonMapper.getDefault().readerFor(prov.get().getResponseClass()); - return reader.readValue(content); + var v = JacksonMapper.getDefault().readValue(response.body(), BeaconClientErrorResponse.class); + return Optional.of(v); } catch (IOException ex) { - throw new ConnectorException("Couldn't parse response", ex); + throw new BeaconConnectorException("Couldn't parse client error message", ex); } } - public InputStream getRawInputStream() { - return in; - } - - public OutputStream getRawOutputStream() { - return out; - } - - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") - public abstract static class ClientInformation { - - public final CliClientInformation cli() { - return (CliClientInformation) this; + private Optional parseServerError(HttpResponse response) throws BeaconConnectorException { + if (response.statusCode() < 500 || response.statusCode() > 599) { + return Optional.empty(); } - public abstract String toDisplayString(); - } - - @JsonTypeName("cli") - @Value - @Builder - @Jacksonized - @EqualsAndHashCode(callSuper = false) - public static class CliClientInformation extends ClientInformation { - - @Override - public String toDisplayString() { - return "XPipe CLI"; + try { + var v = JacksonMapper.getDefault().readValue(response.body(), BeaconServerErrorResponse.class); + return Optional.of(v); + } catch (IOException ex) { + throw new BeaconConnectorException("Couldn't parse client error message", ex); } } - @JsonTypeName("daemon") - @Value - @Builder - @Jacksonized - @EqualsAndHashCode(callSuper = false) - public static class DaemonInformation extends ClientInformation { - - @Override - public String toDisplayString() { - return "Daemon"; - } - } - - @JsonTypeName("gateway") - @Value - @Builder - @Jacksonized - @EqualsAndHashCode(callSuper = false) - public static class GatewayClientInformation extends ClientInformation { - - String version; - - @Override - public String toDisplayString() { - return "XPipe Gateway " + version; - } - } - - @JsonTypeName("api") - @Value - @Builder - @Jacksonized - @EqualsAndHashCode(callSuper = false) - public static class ApiClientInformation extends ClientInformation { - - String version; - String language; - - @Override - public String toDisplayString() { - return String.format("XPipe %s API v%s", language, version); - } - } } diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ClientErrorMessage.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClientErrorResponse.java similarity index 53% rename from beacon/src/main/java/io/xpipe/beacon/exchange/data/ClientErrorMessage.java rename to beacon/src/main/java/io/xpipe/beacon/BeaconClientErrorResponse.java index 09fd318ee..bd2c196a2 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ClientErrorMessage.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClientErrorResponse.java @@ -1,6 +1,4 @@ -package io.xpipe.beacon.exchange.data; - -import io.xpipe.beacon.ClientException; +package io.xpipe.beacon; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,11 +10,11 @@ import lombok.extern.jackson.Jacksonized; @Builder @Jacksonized @AllArgsConstructor -public class ClientErrorMessage { +public class BeaconClientErrorResponse { String message; - public ClientException throwException() { - return new ClientException(message); + public BeaconClientException throwException() { + return new BeaconClientException(message); } } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClientException.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClientException.java new file mode 100644 index 000000000..a561c777d --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClientException.java @@ -0,0 +1,23 @@ +package io.xpipe.beacon; + +/** + * Indicates that a client request was invalid. + */ +public class BeaconClientException extends Exception { + + public BeaconClientException(String message) { + super(message); + } + + public BeaconClientException(String message, Throwable cause) { + super(message, cause); + } + + public BeaconClientException(Throwable cause) { + super(cause); + } + + public BeaconClientException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClientInformation.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClientInformation.java new file mode 100644 index 000000000..85bce0ba4 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClientInformation.java @@ -0,0 +1,77 @@ +package io.xpipe.beacon; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + property = "type") +public abstract class BeaconClientInformation { + + public final CliClientInformation cli() { + return (CliClientInformation) this; + } + + public abstract String toDisplayString(); + + @JsonTypeName("cli") + @Value + @Builder + @Jacksonized + @EqualsAndHashCode(callSuper = false) + public static class CliClientInformation extends BeaconClientInformation { + + @Override + public String toDisplayString() { + return "XPipe CLI"; + } + } + + @JsonTypeName("daemon") + @Value + @Builder + @Jacksonized + @EqualsAndHashCode(callSuper = false) + public static class DaemonInformation extends BeaconClientInformation { + + @Override + public String toDisplayString() { + return "Daemon"; + } + } + + @JsonTypeName("gateway") + @Value + @Builder + @Jacksonized + @EqualsAndHashCode(callSuper = false) + public static class GatewayClientInformation extends BeaconClientInformation { + + String version; + + @Override + public String toDisplayString() { + return "XPipe Gateway " + version; + } + } + + @JsonTypeName("api") + @Value + @Builder + @Jacksonized + @EqualsAndHashCode(callSuper = false) + public static class ApiClientInformation extends BeaconClientInformation { + + String version; + String language; + + @Override + public String toDisplayString() { + return String.format("XPipe %s API v%s", language, version); + } + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java b/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java index 4e21f3d54..c62af056b 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java @@ -1,15 +1,11 @@ package io.xpipe.beacon; import io.xpipe.core.util.XPipeInstallation; - import lombok.experimental.UtilityClass; -import java.nio.charset.StandardCharsets; - @UtilityClass public class BeaconConfig { - public static final byte[] BODY_SEPARATOR = "\n\n".getBytes(StandardCharsets.UTF_8); public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port"; public static final String DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs"; private static final String PRINT_MESSAGES_PROPERTY = "io.xpipe.beacon.printMessages"; @@ -17,14 +13,6 @@ public class BeaconConfig { private static final String ATTACH_DEBUGGER_PROP = "io.xpipe.beacon.attachDebuggerToDaemon"; private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.printDaemonOutput"; private static final String EXEC_PROCESS_PROP = "io.xpipe.beacon.customDaemonCommand"; - private static final String LOCAL_PROXY_PROP = "io.xpipe.beacon.localProxy"; - - public static boolean localProxy() { - if (System.getProperty(LOCAL_PROXY_PROP) != null) { - return Boolean.parseBoolean(System.getProperty(LOCAL_PROXY_PROP)); - } - return false; - } public static boolean printMessages() { if (System.getProperty(PRINT_MESSAGES_PROPERTY) != null) { diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconConnection.java b/beacon/src/main/java/io/xpipe/beacon/BeaconConnection.java index 509e6d71b..cff8bb0f1 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconConnection.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconConnection.java @@ -1,189 +1,27 @@ package io.xpipe.beacon; -import io.xpipe.core.util.FailableBiConsumer; -import io.xpipe.core.util.FailableConsumer; - import lombok.Getter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - +@Getter public abstract class BeaconConnection implements AutoCloseable { - @Getter protected BeaconClient beaconClient; - private InputStream bodyInput; - private OutputStream bodyOutput; - - protected abstract void constructSocket(); + protected abstract void establishConnection() throws Exception; @Override public void close() { - try { - if (beaconClient != null) { - beaconClient.close(); - } - beaconClient = null; - } catch (Exception e) { - beaconClient = null; - throw new BeaconException("Could not close beacon connection", e); - } - } - - public void withOutputStream(FailableConsumer ex) { - try { - ex.accept(getOutputStream()); - } catch (IOException e) { - throw new BeaconException("Could not write to beacon output stream", e); - } - } - - public void withInputStream(FailableConsumer ex) { - try { - ex.accept(getInputStream()); - } catch (IOException e) { - throw new BeaconException("Could not read from beacon output stream", e); - } + beaconClient = null; } public void checkClosed() { if (beaconClient == null) { - throw new BeaconException("Socket is closed"); + throw new IllegalStateException("Socket is closed"); } } - public OutputStream getOutputStream() { + public RES performSimpleExchange(REQ req) throws Exception { checkClosed(); - - if (bodyOutput == null) { - throw new IllegalStateException("Body output has not started yet"); - } - - return bodyOutput; - } - - public InputStream getInputStream() { - checkClosed(); - - if (bodyInput == null) { - throw new IllegalStateException("Body input has not started yet"); - } - - return bodyInput; - } - - public void performInputExchange( - REQ req, FailableBiConsumer responseConsumer) { - checkClosed(); - - performInputOutputExchange(req, null, responseConsumer); - } - - public void performInputOutputExchange( - REQ req, - FailableConsumer reqWriter, - FailableBiConsumer responseConsumer) { - checkClosed(); - - try { - beaconClient.sendRequest(req); - if (reqWriter != null) { - try (var out = sendBody()) { - reqWriter.accept(out); - } - } - RES res = beaconClient.receiveResponse(); - try (var in = receiveBody()) { - responseConsumer.accept(res, in); - } - } catch (Exception e) { - throw unwrapException(e); - } - } - - public void sendRequest(REQ req) { - checkClosed(); - - try { - beaconClient.sendRequest(req); - } catch (Exception e) { - throw unwrapException(e); - } - } - - public RES receiveResponse() { - checkClosed(); - - try { - return beaconClient.receiveResponse(); - } catch (Exception e) { - throw unwrapException(e); - } - } - - public OutputStream sendBody() { - checkClosed(); - - try { - bodyOutput = beaconClient.sendBody(); - return bodyOutput; - } catch (Exception e) { - throw unwrapException(e); - } - } - - public InputStream receiveBody() { - checkClosed(); - - try { - bodyInput = beaconClient.receiveBody(); - return bodyInput; - } catch (Exception e) { - throw unwrapException(e); - } - } - - public RES performOutputExchange( - REQ req, FailableConsumer reqWriter) { - checkClosed(); - - try { - beaconClient.sendRequest(req); - try (var out = sendBody()) { - reqWriter.accept(out); - } - return beaconClient.receiveResponse(); - } catch (Exception e) { - throw unwrapException(e); - } - } - - public RES performSimpleExchange(REQ req) { - checkClosed(); - - try { - beaconClient.sendRequest(req); - return beaconClient.receiveResponse(); - } catch (Exception e) { - throw unwrapException(e); - } - } - - private BeaconException unwrapException(Exception exception) { - if (exception instanceof ServerException s) { - return new BeaconException("An internal server error occurred", s); - } - - if (exception instanceof ClientException s) { - return new BeaconException("A client error occurred", s); - } - - if (exception instanceof ConnectorException s) { - return new BeaconException("A beacon connection error occurred", s); - } - - return new BeaconException("An unexpected error occurred", exception); + return beaconClient.performRequest(req); } } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconConnectorException.java b/beacon/src/main/java/io/xpipe/beacon/BeaconConnectorException.java new file mode 100644 index 000000000..afdb86b2d --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconConnectorException.java @@ -0,0 +1,25 @@ +package io.xpipe.beacon; + +/** + * Indicates that a connection error occurred. + */ +public class BeaconConnectorException extends Exception { + + public BeaconConnectorException() {} + + public BeaconConnectorException(String message) { + super(message); + } + + public BeaconConnectorException(String message, Throwable cause) { + super(message, cause); + } + + public BeaconConnectorException(Throwable cause) { + super(cause); + } + + public BeaconConnectorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconException.java b/beacon/src/main/java/io/xpipe/beacon/BeaconException.java deleted file mode 100644 index 5c4bd3b63..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconException.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.beacon; - -/** - * An unchecked exception that will be thrown in any case of an underlying exception. - */ -public class BeaconException extends RuntimeException { - - public BeaconException() {} - - public BeaconException(String message) { - super(message); - } - - public BeaconException(String message, Throwable cause) { - super(message, cause); - } - - public BeaconException(Throwable cause) { - super(cause); - } - - public BeaconException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconFormat.java b/beacon/src/main/java/io/xpipe/beacon/BeaconFormat.java deleted file mode 100644 index 029f2305b..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconFormat.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.xpipe.beacon; - -import lombok.experimental.UtilityClass; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -@UtilityClass -public class BeaconFormat { - - private static final int SEGMENT_SIZE = 65536; - - public static OutputStream writeBlocks(OutputStream out) { - return new OutputStream() { - private final byte[] currentBytes = new byte[SEGMENT_SIZE]; - private int index; - - @Override - public void write(int b) throws IOException { - if (isClosed()) { - throw new IllegalStateException("Output is closed"); - } - - if (index == currentBytes.length) { - finishBlock(); - } - - currentBytes[index] = (byte) b; - index++; - } - - @Override - public void close() throws IOException { - if (isClosed()) { - return; - } - - finishBlock(); - out.flush(); - index = -1; - } - - private boolean isClosed() { - return index == -1; - } - - private void finishBlock() throws IOException { - if (isClosed()) { - throw new IllegalStateException("Output is closed"); - } - - if (BeaconConfig.printMessages()) { - System.out.println("Sending data block of length " + index); - } - - int length = index; - var lengthBuffer = ByteBuffer.allocate(4).putInt(length); - out.write(lengthBuffer.array()); - out.write(currentBytes, 0, length); - index = 0; - } - }; - } - - public static InputStream readBlocks(InputStream in) { - return new InputStream() { - - private byte[] currentBytes; - private int index; - private boolean lastBlock; - - @Override - public int read() throws IOException { - if ((currentBytes == null || index == currentBytes.length) && !lastBlock) { - if (!readBlock()) { - return -1; - } - } - - if (currentBytes != null && index == currentBytes.length && lastBlock) { - return -1; - } - - int out = currentBytes[index] & 0xff; - index++; - return out; - } - - private boolean readBlock() throws IOException { - var length = in.readNBytes(4); - if (length.length < 4) { - return false; - } - - var lengthInt = ByteBuffer.wrap(length).getInt(); - - if (BeaconConfig.printMessages()) { - System.out.println("Receiving data block of length " + lengthInt); - } - - currentBytes = in.readNBytes(lengthInt); - index = 0; - if (lengthInt < SEGMENT_SIZE) { - lastBlock = true; - } - return true; - } - }; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconHandler.java b/beacon/src/main/java/io/xpipe/beacon/BeaconHandler.java deleted file mode 100644 index 8b4a960b8..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon; - -import io.xpipe.core.util.FailableRunnable; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * An exchange handler responsible for properly handling a request and sending a response. - */ -public interface BeaconHandler { - - /** - * Execute a Runnable after the initial response has been sent. - * - * @param r the runnable to execute - */ - void postResponse(FailableRunnable r); - - /** - * Prepares to attach a body to a response. - * - * @return the output stream that can be used to write the body payload - */ - OutputStream sendBody() throws IOException; - - /** - * Prepares to read an attached body of a request. - * - * @return the input stream that can be used to read the body payload - */ - InputStream receiveBody() throws IOException; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java new file mode 100644 index 000000000..28ed9f7b6 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java @@ -0,0 +1,74 @@ +package io.xpipe.beacon; + +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; +import java.util.stream.Collectors; + +public abstract class BeaconInterface { + + private static List> ALL; + + public static List> getAll() { + return ALL; + } + + public static Optional> byPath(String path) { + return ALL.stream() + .filter(d -> d.getPath().equals(path)) + .findAny(); + } + + + public static Optional> byRequest(RQ req) { + return ALL.stream() + .filter(d -> d.getRequestClass().equals(req.getClass())) + .findAny(); + } + + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { + var services = layer != null ? ServiceLoader.load(layer, BeaconInterface.class) : ServiceLoader.load(BeaconInterface.class); + ALL = services.stream() + .map(ServiceLoader.Provider::get) + .map(beaconInterface -> (BeaconInterface) beaconInterface) + .collect(Collectors.toList()); + // Remove parent classes + ALL.removeIf(beaconInterface -> ALL.stream().anyMatch(other -> + !other.equals(beaconInterface) && beaconInterface.getClass().isAssignableFrom(other.getClass()))); + } + } + + @SuppressWarnings("unchecked") + @SneakyThrows + public Class getRequestClass() { + var c = getClass().getSuperclass(); + var name = (c.getSuperclass().equals(BeaconInterface.class) ? c : getClass()).getName() + "$Request"; + return (Class) Class.forName(name); + } + + @SuppressWarnings("unchecked") + @SneakyThrows + public Class getResponseClass() { + var c = getClass().getSuperclass(); + var name = (c.getSuperclass().equals(BeaconInterface.class) ? c : getClass()).getName() + "$Response"; + return (Class) Class.forName(name); + } + + public boolean requiresAuthentication() { + return true; + } + + public abstract String getPath(); + + public Object handle(HttpExchange exchange, T body) throws IOException, BeaconClientException, BeaconServerException { + throw new UnsupportedOperationException(); + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconJacksonModule.java b/beacon/src/main/java/io/xpipe/beacon/BeaconJacksonModule.java index 9a8da0e17..b89ca4775 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconJacksonModule.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconJacksonModule.java @@ -8,8 +8,8 @@ public class BeaconJacksonModule extends SimpleModule { @Override public void setupModule(SetupContext context) { context.registerSubtypes( - new NamedType(BeaconClient.ApiClientInformation.class), - new NamedType(BeaconClient.CliClientInformation.class), - new NamedType(BeaconClient.DaemonInformation.class)); + new NamedType(BeaconClientInformation.ApiClientInformation.class), + new NamedType(BeaconClientInformation.CliClientInformation.class), + new NamedType(BeaconClientInformation.DaemonInformation.class)); } } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java b/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java index b151ef9ba..4e482d830 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconServer.java @@ -1,6 +1,6 @@ package io.xpipe.beacon; -import io.xpipe.beacon.exchange.StopExchange; +import io.xpipe.beacon.api.StopExchange; import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileNames; import io.xpipe.core.util.XPipeDaemonMode; @@ -108,8 +108,7 @@ public class BeaconServer { } public static boolean tryStop(BeaconClient client) throws Exception { - client.sendRequest(StopExchange.Request.builder().build()); - StopExchange.Response res = client.receiveResponse(); + StopExchange.Response res = client.performRequest(StopExchange.Request.builder().build()); return res.isSuccess(); } diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconServerErrorResponse.java b/beacon/src/main/java/io/xpipe/beacon/BeaconServerErrorResponse.java new file mode 100644 index 000000000..28f634504 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconServerErrorResponse.java @@ -0,0 +1,20 @@ +package io.xpipe.beacon; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +@SuppressWarnings("ClassCanBeRecord") +@Value +@Builder +@Jacksonized +@AllArgsConstructor +public class BeaconServerErrorResponse { + + Throwable error; + + public void throwError() throws BeaconServerException { + throw new BeaconServerException(error.getMessage(), error); + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconServerException.java b/beacon/src/main/java/io/xpipe/beacon/BeaconServerException.java new file mode 100644 index 000000000..8247bc0ae --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconServerException.java @@ -0,0 +1,23 @@ +package io.xpipe.beacon; + +/** + * Indicates that an internal server error occurred. + */ +public class BeaconServerException extends Exception { + + public BeaconServerException(String message) { + super(message); + } + + public BeaconServerException(String message, Throwable cause) { + super(message, cause); + } + + public BeaconServerException(Throwable cause) { + super(cause); + } + + public BeaconServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/ClientException.java b/beacon/src/main/java/io/xpipe/beacon/ClientException.java deleted file mode 100644 index 784d9b642..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/ClientException.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.beacon; - -/** - * Indicates that a client request caused an issue. - */ -public class ClientException extends Exception { - - public ClientException() {} - - public ClientException(String message) { - super(message); - } - - public ClientException(String message, Throwable cause) { - super(message, cause); - } - - public ClientException(Throwable cause) { - super(cause); - } - - public ClientException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/ConnectorException.java b/beacon/src/main/java/io/xpipe/beacon/ConnectorException.java deleted file mode 100644 index 83a14dbcf..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/ConnectorException.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.beacon; - -/** - * Indicates that a connection error occurred. - */ -public class ConnectorException extends Exception { - - public ConnectorException() {} - - public ConnectorException(String message) { - super(message); - } - - public ConnectorException(String message, Throwable cause) { - super(message, cause); - } - - public ConnectorException(Throwable cause) { - super(cause); - } - - public ConnectorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/RequestMessage.java b/beacon/src/main/java/io/xpipe/beacon/RequestMessage.java deleted file mode 100644 index 9f9a5c2da..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/RequestMessage.java +++ /dev/null @@ -1,3 +0,0 @@ -package io.xpipe.beacon; - -public interface RequestMessage {} diff --git a/beacon/src/main/java/io/xpipe/beacon/ResponseMessage.java b/beacon/src/main/java/io/xpipe/beacon/ResponseMessage.java deleted file mode 100644 index ec167994d..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/ResponseMessage.java +++ /dev/null @@ -1,3 +0,0 @@ -package io.xpipe.beacon; - -public interface ResponseMessage {} diff --git a/beacon/src/main/java/io/xpipe/beacon/ServerException.java b/beacon/src/main/java/io/xpipe/beacon/ServerException.java deleted file mode 100644 index d25c2272e..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/ServerException.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.beacon; - -/** - * Indicates that an internal server error occurred. - */ -public class ServerException extends Exception { - - public ServerException() {} - - public ServerException(String message) { - super(message); - } - - public ServerException(String message, Throwable cause) { - super(message, cause); - } - - public ServerException(Throwable cause) { - super(cause); - } - - public ServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/AskpassExchange.java similarity index 53% rename from beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java rename to beacon/src/main/java/io/xpipe/beacon/api/AskpassExchange.java index 8a1be7caa..e5f9f0ae8 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/AskpassExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/api/AskpassExchange.java @@ -1,9 +1,7 @@ -package io.xpipe.beacon.exchange; +package io.xpipe.beacon.api; -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; +import io.xpipe.beacon.BeaconInterface; import io.xpipe.core.util.SecretValue; - import lombok.Builder; import lombok.NonNull; import lombok.Value; @@ -11,17 +9,17 @@ import lombok.extern.jackson.Jacksonized; import java.util.UUID; -public class AskpassExchange implements MessageExchange { +public class AskpassExchange extends BeaconInterface { @Override - public String getId() { - return "askpass"; + public String getPath() { + return "/askpass"; } @Jacksonized @Builder @Value - public static class Request implements RequestMessage { + public static class Request { UUID secretId; @NonNull @@ -33,7 +31,7 @@ public class AskpassExchange implements MessageExchange { @Jacksonized @Builder @Value - public static class Response implements ResponseMessage { + public static class Response { SecretValue value; } } diff --git a/beacon/src/main/java/io/xpipe/beacon/api/FocusExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/FocusExchange.java new file mode 100644 index 000000000..aac28bdbc --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/FocusExchange.java @@ -0,0 +1,29 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import io.xpipe.core.util.XPipeDaemonMode; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class FocusExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/focus"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + @NonNull + XPipeDaemonMode mode; + } + + @Jacksonized + @Builder + @Value + public static class Response {} +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/HandshakeExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/HandshakeExchange.java new file mode 100644 index 000000000..2379db5d6 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/HandshakeExchange.java @@ -0,0 +1,34 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconClientInformation; +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class HandshakeExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/handshake"; + } + + @Override + public boolean requiresAuthentication() { + return false; + } + + @Jacksonized + @Builder + @Value + public static class Request { + BeaconClientInformation client; + } + + @Jacksonized + @Builder + @Value + public static class Response { + String token; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/ModeExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/ModeExchange.java new file mode 100644 index 000000000..c11a98ee2 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/ModeExchange.java @@ -0,0 +1,32 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import io.xpipe.core.util.XPipeDaemonMode; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class ModeExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/mode"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + @NonNull + XPipeDaemonMode mode; + } + + @Jacksonized + @Builder + @Value + public static class Response { + @NonNull + XPipeDaemonMode usedMode; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/OpenExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/OpenExchange.java new file mode 100644 index 000000000..62172093c --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/OpenExchange.java @@ -0,0 +1,30 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.util.List; + +public class OpenExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/open"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + @NonNull + List arguments; + } + + @Jacksonized + @Builder + @Value + public static class Response {} +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/StatusExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/StatusExchange.java new file mode 100644 index 000000000..0c4a2eade --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/StatusExchange.java @@ -0,0 +1,27 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class StatusExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/status"; + } + + @Value + @Jacksonized + @Builder + public static class Request { + } + + @Jacksonized + @Builder + @Value + public static class Response { + String mode; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/StopExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/StopExchange.java new file mode 100644 index 000000000..abfcf693f --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/StopExchange.java @@ -0,0 +1,30 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +/** + * Requests the daemon to stop. + */ +public class StopExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/stop"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + } + + @Jacksonized + @Builder + @Value + public static class Response { + boolean success; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/TerminalLaunchExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/TerminalLaunchExchange.java similarity index 50% rename from beacon/src/main/java/io/xpipe/beacon/exchange/TerminalLaunchExchange.java rename to beacon/src/main/java/io/xpipe/beacon/api/TerminalLaunchExchange.java index 6f314a643..82d53dbd0 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/TerminalLaunchExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/api/TerminalLaunchExchange.java @@ -1,8 +1,6 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; +package io.xpipe.beacon.api; +import io.xpipe.beacon.BeaconInterface; import lombok.Builder; import lombok.NonNull; import lombok.Value; @@ -11,17 +9,17 @@ import lombok.extern.jackson.Jacksonized; import java.nio.file.Path; import java.util.UUID; -public class TerminalLaunchExchange implements MessageExchange { +public class TerminalLaunchExchange extends BeaconInterface { @Override - public String getId() { - return "terminalLaunch"; + public String getPath() { + return "/terminalLaunch"; } @Jacksonized @Builder @Value - public static class Request implements RequestMessage { + public static class Request { @NonNull UUID request; } @@ -29,7 +27,7 @@ public class TerminalLaunchExchange implements MessageExchange { @Jacksonized @Builder @Value - public static class Response implements ResponseMessage { + public static class Response { @NonNull Path targetFile; } diff --git a/beacon/src/main/java/io/xpipe/beacon/api/TerminalWaitExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/TerminalWaitExchange.java new file mode 100644 index 000000000..da4d91d6d --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/TerminalWaitExchange.java @@ -0,0 +1,30 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.NonNull; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +import java.util.UUID; + +public class TerminalWaitExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/terminalWait"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + @NonNull + UUID request; + } + + @Jacksonized + @Builder + @Value + public static class Response {} +} diff --git a/beacon/src/main/java/io/xpipe/beacon/api/VersionExchange.java b/beacon/src/main/java/io/xpipe/beacon/api/VersionExchange.java new file mode 100644 index 000000000..42d4fa5e0 --- /dev/null +++ b/beacon/src/main/java/io/xpipe/beacon/api/VersionExchange.java @@ -0,0 +1,30 @@ +package io.xpipe.beacon.api; + +import io.xpipe.beacon.BeaconInterface; +import lombok.Builder; +import lombok.Value; +import lombok.extern.jackson.Jacksonized; + +public class VersionExchange extends BeaconInterface { + + @Override + public String getPath() { + return "/version"; + } + + @Jacksonized + @Builder + @Value + public static class Request { + } + + @Jacksonized + @Builder + @Value + public static class Response { + + String version; + String buildVersion; + String jvmVersion; + } +} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/DrainExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/DrainExchange.java deleted file mode 100644 index 573b2ad6d..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/DrainExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.core.store.DataStoreId; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class DrainExchange implements MessageExchange { - - @Override - public String getId() { - return "drain"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - DataStoreId source; - - @NonNull - String path; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/FocusExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/FocusExchange.java deleted file mode 100644 index f9082bda8..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/FocusExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.core.util.XPipeDaemonMode; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class FocusExchange implements MessageExchange { - - @Override - public String getId() { - return "focus"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - XPipeDaemonMode mode; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/LaunchExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/LaunchExchange.java deleted file mode 100644 index 2b1e03cc2..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/LaunchExchange.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.core.store.DataStoreId; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; - -public class LaunchExchange implements MessageExchange { - - @Override - public String getId() { - return "launch"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - DataStoreId id; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - List command; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchange.java deleted file mode 100644 index 999cd7057..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange; - -import lombok.SneakyThrows; - -/** - * A message exchange scheme that implements a certain functionality. - */ -public interface MessageExchange { - - /** - * The unique id of this exchange that will be included in the messages. - */ - String getId(); - - /** - * Returns the request class, needed for serialization. - */ - @SneakyThrows - default Class getRequestClass() { - var c = getClass().getSuperclass(); - var name = (MessageExchange.class.isAssignableFrom(c) ? c : getClass()).getName() + "$Request"; - return Class.forName(name); - } - - /** - * Returns the response class, needed for serialization. - */ - @SneakyThrows - default Class getResponseClass() { - var c = getClass().getSuperclass(); - var name = (MessageExchange.class.isAssignableFrom(c) ? c : getClass()).getName() + "$Response"; - return Class.forName(name); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchanges.java b/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchanges.java deleted file mode 100644 index 54c0db988..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/MessageExchanges.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; - -import java.util.List; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.stream.Collectors; - -public class MessageExchanges { - - private static List ALL; - - public static void loadAll() { - if (ALL == null) { - ALL = ServiceLoader.load(MessageExchange.class).stream() - .map(s -> { - return s.get(); - }) - .collect(Collectors.toList()); - } - } - - public static Optional byId(String name) { - loadAll(); - return ALL.stream().filter(d -> d.getId().equals(name)).findAny(); - } - - public static Optional byRequest(RQ req) { - loadAll(); - return ALL.stream() - .filter(d -> d.getRequestClass().equals(req.getClass())) - .findAny(); - } - - public static Optional byResponse(RP rep) { - loadAll(); - return ALL.stream() - .filter(d -> d.getResponseClass().equals(rep.getClass())) - .findAny(); - } - - public static List getAll() { - loadAll(); - return ALL; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/OpenExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/OpenExchange.java deleted file mode 100644 index 29533f64a..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/OpenExchange.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; - -public class OpenExchange implements MessageExchange { - - @Override - public String getId() { - return "open"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - List arguments; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/QueryStoreExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/QueryStoreExchange.java deleted file mode 100644 index e656a72e5..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/QueryStoreExchange.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.core.store.DataStore; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.LinkedHashMap; - -/** - * Queries general information about a data source. - */ -public class QueryStoreExchange implements MessageExchange { - - @Override - public String getId() { - return "queryStore"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String name; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - String name; - - String information; - - String summary; - - @NonNull - String provider; - - @NonNull - LinkedHashMap config; - - DataStore internalStore; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/SinkExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/SinkExchange.java deleted file mode 100644 index 8f5f308ef..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/SinkExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.core.store.DataStoreId; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class SinkExchange implements MessageExchange { - - @Override - public String getId() { - return "sink"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - DataStoreId source; - - @NonNull - String path; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/StopExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/StopExchange.java deleted file mode 100644 index 6ee1475ac..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/StopExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -/** - * Requests the daemon to stop. - */ -public class StopExchange implements MessageExchange { - - @Override - public String getId() { - return "stop"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - boolean success; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/TerminalWaitExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/TerminalWaitExchange.java deleted file mode 100644 index a0cf98f9e..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/TerminalWaitExchange.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.beacon.exchange; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.UUID; - -public class TerminalWaitExchange implements MessageExchange { - - @Override - public String getId() { - return "terminalWait"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - UUID request; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/DialogExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/DialogExchange.java deleted file mode 100644 index dfa50dbc3..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/DialogExchange.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.core.dialog.DialogElement; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.UUID; - -public class DialogExchange implements MessageExchange { - - @Override - public String getId() { - return "dialog"; - } - - @Override - public Class getRequestClass() { - return DialogExchange.Request.class; - } - - @Override - public Class getResponseClass() { - return DialogExchange.Response.class; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - UUID dialogKey; - - String value; - boolean cancel; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - DialogElement element; - String errorMsg; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java deleted file mode 100644 index 351dd69e7..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/EditStoreExchange.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.core.dialog.DialogReference; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class EditStoreExchange implements MessageExchange { - - @Override - public String getId() { - return "editEntry"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String name; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - DialogReference dialog; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListCollectionsExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListCollectionsExchange.java deleted file mode 100644 index 270f04470..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListCollectionsExchange.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.beacon.exchange.data.CollectionListEntry; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; - -public class ListCollectionsExchange implements MessageExchange { - - @Override - public String getId() { - return "listCollections"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - List entries; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListEntriesExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListEntriesExchange.java deleted file mode 100644 index f7a0a5773..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListEntriesExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.beacon.exchange.data.EntryListEntry; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; - -public class ListEntriesExchange implements MessageExchange { - - @Override - public String getId() { - return "listEntries"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - String collection; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - List entries; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListStoresExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListStoresExchange.java deleted file mode 100644 index cb5377d69..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ListStoresExchange.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.beacon.exchange.data.StoreListEntry; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; - -public class ListStoresExchange implements MessageExchange { - - @Override - public String getId() { - return "listStores"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - List entries; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ModeExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ModeExchange.java deleted file mode 100644 index b9ad4cfd4..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ModeExchange.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.core.util.XPipeDaemonMode; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class ModeExchange implements MessageExchange { - - @Override - public String getId() { - return "mode"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - XPipeDaemonMode mode; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - XPipeDaemonMode usedMode; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ReadDrainExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ReadDrainExchange.java deleted file mode 100644 index 1cc2bd2cb..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/ReadDrainExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class ReadDrainExchange implements MessageExchange { - - @Override - public String getId() { - return "readDrain"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String name; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveCollectionExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveCollectionExchange.java deleted file mode 100644 index bde33574d..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveCollectionExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class RemoveCollectionExchange implements MessageExchange { - - @Override - public String getId() { - return "removeCollection"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String collectionName; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveStoreExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveStoreExchange.java deleted file mode 100644 index 0c6dacf58..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RemoveStoreExchange.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class RemoveStoreExchange implements MessageExchange { - - @Override - public String getId() { - return "removeStore"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String storeName; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameCollectionExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameCollectionExchange.java deleted file mode 100644 index 693179a7a..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameCollectionExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class RenameCollectionExchange implements MessageExchange { - - @Override - public String getId() { - return "renameCollection"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String collectionName; - - @NonNull - String newName; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameStoreExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameStoreExchange.java deleted file mode 100644 index f7c9a98f0..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/RenameStoreExchange.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class RenameStoreExchange implements MessageExchange { - - @Override - public String getId() { - return "renameStore"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - @NonNull - String storeName; - - @NonNull - String newName; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage {} -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StatusExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StatusExchange.java deleted file mode 100644 index 7d08abae0..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StatusExchange.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class StatusExchange implements MessageExchange { - - @Override - public String getId() { - return "status"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - String mode; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreAddExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreAddExchange.java deleted file mode 100644 index 898a591b6..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreAddExchange.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.core.dialog.DialogReference; -import io.xpipe.core.store.DataStore; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class StoreAddExchange implements MessageExchange { - - @Override - public String getId() { - return "storeAdd"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage { - DataStore storeInput; - - String type; - String name; - } - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - DialogReference config; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java deleted file mode 100644 index d7a173e90..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/StoreProviderListExchange.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; -import io.xpipe.beacon.exchange.data.ProviderEntry; - -import lombok.Builder; -import lombok.NonNull; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.List; -import java.util.Map; - -public class StoreProviderListExchange implements MessageExchange { - - @Override - public String getId() { - return "storeProviderList"; - } - - @Jacksonized - @Builder - @Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - @NonNull - Map> entries; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/VersionExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/cli/VersionExchange.java deleted file mode 100644 index 14155cd77..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/cli/VersionExchange.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.xpipe.beacon.exchange.cli; - -import io.xpipe.beacon.RequestMessage; -import io.xpipe.beacon.ResponseMessage; -import io.xpipe.beacon.exchange.MessageExchange; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -public class VersionExchange implements MessageExchange { - - @Override - public String getId() { - return "version"; - } - - @lombok.extern.jackson.Jacksonized - @lombok.Builder - @lombok.Value - public static class Request implements RequestMessage {} - - @Jacksonized - @Builder - @Value - public static class Response implements ResponseMessage { - - String version; - String buildVersion; - String jvmVersion; - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/CollectionListEntry.java b/beacon/src/main/java/io/xpipe/beacon/exchange/data/CollectionListEntry.java deleted file mode 100644 index 93e802846..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/CollectionListEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.xpipe.beacon.exchange.data; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; - -@Value -@Jacksonized -@Builder -public class CollectionListEntry { - - String name; - int size; - Instant lastUsed; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/EntryListEntry.java b/beacon/src/main/java/io/xpipe/beacon/exchange/data/EntryListEntry.java deleted file mode 100644 index 0df3fdb71..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/EntryListEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.xpipe.beacon.exchange.data; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; - -@Value -@Jacksonized -@Builder -public class EntryListEntry { - String name; - String type; - String description; - Instant lastUsed; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ProviderEntry.java b/beacon/src/main/java/io/xpipe/beacon/exchange/data/ProviderEntry.java deleted file mode 100644 index 4b67c194a..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ProviderEntry.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.xpipe.beacon.exchange.data; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Value -@Jacksonized -@Builder -public class ProviderEntry { - String id; - String description; - boolean hidden; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ServerErrorMessage.java b/beacon/src/main/java/io/xpipe/beacon/exchange/data/ServerErrorMessage.java deleted file mode 100644 index 5e0e6e20e..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/ServerErrorMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.xpipe.beacon.exchange.data; - -import io.xpipe.beacon.ServerException; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -import java.util.UUID; - -@SuppressWarnings("ClassCanBeRecord") -@Value -@Builder -@Jacksonized -@AllArgsConstructor -public class ServerErrorMessage { - - UUID requestId; - Throwable error; - - public void throwError() throws ServerException { - throw new ServerException(error.getMessage(), error); - } -} diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/data/StoreListEntry.java b/beacon/src/main/java/io/xpipe/beacon/exchange/data/StoreListEntry.java deleted file mode 100644 index 1853245ed..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/data/StoreListEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.xpipe.beacon.exchange.data; - -import io.xpipe.core.store.DataStoreId; - -import lombok.Builder; -import lombok.Value; -import lombok.extern.jackson.Jacksonized; - -@Value -@Jacksonized -@Builder -public class StoreListEntry { - - DataStoreId id; - String type; - String information; -} diff --git a/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonController.java b/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonController.java index a5569604f..5aafc0e34 100644 --- a/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonController.java +++ b/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonController.java @@ -1,6 +1,7 @@ package io.xpipe.beacon.test; import io.xpipe.beacon.BeaconClient; +import io.xpipe.beacon.BeaconClientInformation; import io.xpipe.beacon.BeaconServer; import io.xpipe.core.util.XPipeDaemonMode; import io.xpipe.core.util.XPipeInstallation; @@ -41,7 +42,7 @@ public class BeaconDaemonController { return; } - var client = BeaconClient.establishConnection(BeaconClient.ApiClientInformation.builder() + var client = BeaconClient.establishConnection(BeaconClientInformation.ApiClientInformation.builder() .version("?") .language("Java API Test") .build()); @@ -67,7 +68,7 @@ public class BeaconDaemonController { } catch (InterruptedException ignored) { } - var s = BeaconClient.tryEstablishConnection(BeaconClient.ApiClientInformation.builder() + var s = BeaconClient.tryEstablishConnection(BeaconClientInformation.ApiClientInformation.builder() .version("?") .language("Java") .build()); diff --git a/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonExtensionTest.java b/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonExtensionTest.java index 9e1e1cdba..a66c469c6 100644 --- a/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonExtensionTest.java +++ b/beacon/src/main/java/io/xpipe/beacon/test/BeaconDaemonExtensionTest.java @@ -1,9 +1,8 @@ package io.xpipe.beacon.test; import io.xpipe.core.process.OsType; -import io.xpipe.core.util.JacksonMapper; +import io.xpipe.core.util.ModuleLayerLoader; import io.xpipe.core.util.XPipeDaemonMode; - import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -11,7 +10,7 @@ public class BeaconDaemonExtensionTest { @BeforeAll public static void setup() throws Exception { - JacksonMapper.initModularized(ModuleLayer.boot()); + ModuleLayerLoader.loadAll(ModuleLayer.boot(),throwable -> throwable.printStackTrace()); BeaconDaemonController.start( OsType.getLocal().equals(OsType.WINDOWS) ? XPipeDaemonMode.TRAY : XPipeDaemonMode.BACKGROUND); } diff --git a/beacon/src/main/java/io/xpipe/beacon/util/QuietDialogHandler.java b/beacon/src/main/java/io/xpipe/beacon/util/QuietDialogHandler.java deleted file mode 100644 index d77b07205..000000000 --- a/beacon/src/main/java/io/xpipe/beacon/util/QuietDialogHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -package io.xpipe.beacon.util; - -import io.xpipe.beacon.BeaconConnection; -import io.xpipe.beacon.BeaconException; -import io.xpipe.beacon.exchange.cli.DialogExchange; -import io.xpipe.core.dialog.BaseQueryElement; -import io.xpipe.core.dialog.ChoiceElement; -import io.xpipe.core.dialog.DialogElement; -import io.xpipe.core.dialog.DialogReference; - -import java.util.Map; -import java.util.UUID; - -public class QuietDialogHandler { - - private final UUID dialogKey; - private final BeaconConnection connection; - private final Map overrides; - private DialogElement element; - - public QuietDialogHandler(DialogReference ref, BeaconConnection connection, Map overrides) { - this.dialogKey = ref.getDialogId(); - this.element = ref.getStart(); - this.connection = connection; - this.overrides = overrides; - } - - public static void handle(DialogReference ref, BeaconConnection connection) { - new QuietDialogHandler(ref, connection, Map.of()).handle(); - } - - public void handle() { - String response = null; - - if (element instanceof ChoiceElement c) { - response = handleChoice(c); - } - - if (element instanceof BaseQueryElement q) { - response = handleQuery(q); - } - - DialogExchange.Response res = connection.performSimpleExchange(DialogExchange.Request.builder() - .dialogKey(dialogKey) - .value(response) - .build()); - if (res.getElement() != null && element.equals(res.getElement())) { - throw new BeaconException( - "Invalid value for key " + res.getElement().toDisplayString()); - } - - element = res.getElement(); - - if (element != null) { - handle(); - } - } - - private String handleQuery(BaseQueryElement q) { - if (q.isRequired() && !overrides.containsKey(q.getDescription())) { - throw new IllegalStateException("Missing required config parameter: " + q.getDescription()); - } - - return overrides.get(q.getDescription()); - } - - private String handleChoice(ChoiceElement c) { - if (c.isRequired() && !overrides.containsKey(c.getDescription())) { - throw new IllegalStateException("Missing required config parameter: " + c.getDescription()); - } - - return overrides.get(c.getDescription()); - } -} diff --git a/beacon/src/main/java/module-info.java b/beacon/src/main/java/module-info.java index 64ed19851..ce377700d 100644 --- a/beacon/src/main/java/module-info.java +++ b/beacon/src/main/java/module-info.java @@ -1,49 +1,32 @@ -import io.xpipe.beacon.BeaconJacksonModule; -import io.xpipe.beacon.exchange.*; -import io.xpipe.beacon.exchange.cli.*; -import io.xpipe.core.util.ProxyFunction; - import com.fasterxml.jackson.databind.Module; +import io.xpipe.beacon.BeaconInterface; +import io.xpipe.beacon.BeaconJacksonModule; +import io.xpipe.beacon.api.*; +import io.xpipe.core.util.ModuleLayerLoader; open module io.xpipe.beacon { exports io.xpipe.beacon; - exports io.xpipe.beacon.exchange; - exports io.xpipe.beacon.exchange.data; - exports io.xpipe.beacon.exchange.cli; - exports io.xpipe.beacon.util; exports io.xpipe.beacon.test; + exports io.xpipe.beacon.api; requires static com.fasterxml.jackson.core; + requires static com.fasterxml.jackson.annotation; requires static com.fasterxml.jackson.databind; requires transitive io.xpipe.core; requires static lombok; requires static org.junit.jupiter.api; + requires jdk.httpserver; + requires java.net.http; - uses MessageExchange; - uses ProxyFunction; + uses io.xpipe.beacon.BeaconInterface; + provides ModuleLayerLoader with + BeaconInterface.Loader; provides Module with BeaconJacksonModule; - provides io.xpipe.beacon.exchange.MessageExchange with - SinkExchange, - DrainExchange, - LaunchExchange, - EditStoreExchange, - StoreProviderListExchange, - ModeExchange, - QueryStoreExchange, - StatusExchange, - FocusExchange, - OpenExchange, - StopExchange, - RenameStoreExchange, - RemoveStoreExchange, - StoreAddExchange, - ReadDrainExchange, + provides BeaconInterface with ModeExchange,StatusExchange, FocusExchange, OpenExchange, StopExchange, HandshakeExchange, AskpassExchange, TerminalWaitExchange, TerminalLaunchExchange, - ListStoresExchange, - DialogExchange, VersionExchange; } diff --git a/beacon/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader b/beacon/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader new file mode 100644 index 000000000..c70568c84 --- /dev/null +++ b/beacon/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader @@ -0,0 +1 @@ +io.xpipe.beacon.BeaconInterface$Loader \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index db7993e74..df8952576 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -14,9 +14,7 @@ compileJava { dependencies { api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "2.17.1" - implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-parameter-names', version: "2.17.1" implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: "2.17.1" - implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jdk8', version: "2.17.1" } version = rootProject.versionString diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialects.java b/core/src/main/java/io/xpipe/core/process/ShellDialects.java index c17fb2b8b..3110814bb 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialects.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialects.java @@ -58,10 +58,15 @@ public class ShellDialects { @Override public void init(ModuleLayer layer) { - ServiceLoader.load(layer, ShellDialect.class).stream().forEach(moduleLayerLoaderProvider -> { + var services = layer != null ? ServiceLoader.load(layer, ShellDialect.class) : ServiceLoader.load(ShellDialect.class); + services.stream().forEach(moduleLayerLoaderProvider -> { ALL.add(moduleLayerLoaderProvider.get()); }); + if (ALL.isEmpty()) { + return; + } + CMD = byId("cmd"); POWERSHELL = byId("powershell"); POWERSHELL_CORE = byId("pwsh"); diff --git a/core/src/main/java/io/xpipe/core/util/JacksonMapper.java b/core/src/main/java/io/xpipe/core/util/JacksonMapper.java index 8699ffbd7..0b3dd93c6 100644 --- a/core/src/main/java/io/xpipe/core/util/JacksonMapper.java +++ b/core/src/main/java/io/xpipe/core/util/JacksonMapper.java @@ -49,14 +49,14 @@ public class JacksonMapper { mapper.accept(INSTANCE); } - public static synchronized void initClassBased() { - initModularized(null); - } + public static class Loader implements ModuleLayerLoader { - public static synchronized void initModularized(ModuleLayer layer) { - List MODULES = findModules(layer); - INSTANCE.registerModules(MODULES); - init = true; + @Override + public void init(ModuleLayer layer) { + List MODULES = findModules(layer); + INSTANCE.registerModules(MODULES); + init = true; + } } private static List findModules(ModuleLayer layer) { diff --git a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java index 216c97ec1..e78dcab28 100644 --- a/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java +++ b/core/src/main/java/io/xpipe/core/util/ModuleLayerLoader.java @@ -6,7 +6,8 @@ import java.util.function.Consumer; public interface ModuleLayerLoader { static void loadAll(ModuleLayer layer, Consumer errorHandler) { - ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> { + var loaded = layer != null ? ServiceLoader.load(layer, ModuleLayerLoader.class) : ServiceLoader.load(ModuleLayerLoader.class); + loaded.stream().forEach(moduleLayerLoaderProvider -> { var instance = moduleLayerLoaderProvider.get(); try { instance.init(layer); diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 287db7ad3..adad3ca1a 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -2,6 +2,7 @@ import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.ShellDialect; import io.xpipe.core.process.ShellDialects; import io.xpipe.core.util.CoreJacksonModule; +import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.ModuleLayerLoader; open module io.xpipe.core { @@ -11,8 +12,8 @@ open module io.xpipe.core { exports io.xpipe.core.process; requires com.fasterxml.jackson.datatype.jsr310; - requires com.fasterxml.jackson.module.paramnames; requires static com.fasterxml.jackson.core; + requires static com.fasterxml.jackson.annotation; requires static com.fasterxml.jackson.databind; requires java.net.http; requires static lombok; @@ -24,7 +25,7 @@ open module io.xpipe.core { uses ModuleLayerLoader; uses ShellDialect; - provides ModuleLayerLoader with + provides ModuleLayerLoader with JacksonMapper.Loader, ShellDialects.Loader; provides com.fasterxml.jackson.databind.Module with CoreJacksonModule; diff --git a/core/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader b/core/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader new file mode 100644 index 000000000..c61f23fd2 --- /dev/null +++ b/core/src/main/resources/META-INF/services/io.xpipe.core.util.ModuleLayerLoader @@ -0,0 +1,2 @@ +io.xpipe.core.util.JacksonMapper$Loader +io.xpipe.core.process.ShellDialects$Loader \ No newline at end of file diff --git a/dist/changelogs/10.0.md b/dist/changelogs/10.0.md new file mode 100644 index 000000000..74e0683a7 --- /dev/null +++ b/dist/changelogs/10.0.md @@ -0,0 +1,3 @@ +This is an experimental implementation of an HTTP server to provide an API for XPipe that is easy to use and access. The existing interface used by the CLI has been completely ported over to that, so there might be a few behavior changes for the CLI. + +## It is not recommended to use this version for now unless you're interested in development. diff --git a/dist/licenses/prettytime.license b/dist/licenses/prettytime.license deleted file mode 100644 index f433b1a53..000000000 --- a/dist/licenses/prettytime.license +++ /dev/null @@ -1,177 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/dist/licenses/prettytime.properties b/dist/licenses/prettytime.properties deleted file mode 100644 index 0c67b4121..000000000 --- a/dist/licenses/prettytime.properties +++ /dev/null @@ -1,4 +0,0 @@ -name=Prettytime -version=5.0.7.Final -license=Apache License 2.0 -link=https://github.com/ocpsoft/prettytime \ No newline at end of file diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index 447e8f0ad..c0bd8f03b 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -22,6 +22,7 @@ open module io.xpipe.ext.base { requires java.desktop; requires io.xpipe.core; requires com.fasterxml.jackson.databind; + requires com.fasterxml.jackson.annotation; requires java.net.http; requires static lombok; requires static javafx.controls; diff --git a/gradle/gradle_scripts/dev_default.properties b/gradle/gradle_scripts/dev_default.properties index f12fd39e3..cc12f335e 100644 --- a/gradle/gradle_scripts/dev_default.properties +++ b/gradle/gradle_scripts/dev_default.properties @@ -12,3 +12,6 @@ io.xpipe.app.showcase=false # Location in which your local development connection should be stored. If left empty, it will use your global XPipe storage in ~/.xpipe. io.xpipe.app.dataDir=local + +# When enabled, all http server input and output is printed. Useful for debugging +io.xpipe.beacon.printMessages=false diff --git a/gradle/gradle_scripts/modules.gradle b/gradle/gradle_scripts/modules.gradle index 41a253fba..94055a9f5 100644 --- a/gradle/gradle_scripts/modules.gradle +++ b/gradle/gradle_scripts/modules.gradle @@ -24,12 +24,6 @@ extraJavaModuleInfo { } } -extraJavaModuleInfo { - module("org.ocpsoft.prettytime:prettytime", "org.ocpsoft.prettytime") { - exportAllPackages() - } -} - extraJavaModuleInfo { module("com.vladsch.flexmark:flexmark", "com.vladsch.flexmark") { mergeJar('com.vladsch.flexmark:flexmark-util-data') diff --git a/version b/version index c3cae12bc..2f52450b3 100644 --- a/version +++ b/version @@ -1 +1 @@ -9.3 +10.0