diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21362637f..2f20918a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,7 @@ jobs: with: version: '21.3.0' java-version: '17' + github-token: ${{ secrets.JRELEASER_GITHUB_TOKEN }} - name: Verify Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 157b144c1..2193ae01f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,6 +19,7 @@ jobs: with: version: '21.3.0' java-version: '17' + github-token: ${{ secrets.JRELEASER_GITHUB_TOKEN }} - name: Verify Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java index e2c19c860..ecd5df766 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java @@ -14,6 +14,7 @@ import io.xpipe.beacon.exchange.data.ServerErrorMessage; import io.xpipe.core.store.ShellStore; import io.xpipe.core.util.Deobfuscator; import io.xpipe.core.util.JacksonMapper; +import io.xpipe.core.util.ProxyManagerProvider; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -122,6 +123,9 @@ public class BeaconClient implements AutoCloseable { public static BeaconClient connectProxy(ShellStore proxy) throws Exception { var control = proxy.create().start(); + if (!ProxyManagerProvider.get().setup(control)) { + throw new IOException("X-Pipe connector required to perform operation"); + } var command = control.command("xpipe beacon --raw").start(); command.discardErr(); return new BeaconClient(command, command.getStdout(), command.getStdin()) { diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconProxyImpl.java b/beacon/src/main/java/io/xpipe/beacon/BeaconProxyImpl.java index 6e92eafdc..0b2bb14ea 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconProxyImpl.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconProxyImpl.java @@ -26,15 +26,6 @@ import java.util.function.Function; public class BeaconProxyImpl extends ProxyProvider { - @SneakyThrows - private static DataSource downstreamTransform(DataSource input, ShellStore proxy) { - var proxyNode = JacksonMapper.newMapper().valueToTree(proxy); - var inputNode = JacksonMapper.newMapper().valueToTree(input); - var localNode = JacksonMapper.newMapper().valueToTree(ShellStore.local()); - replace(inputNode, node -> node.equals(proxyNode) ? Optional.of(localNode) : Optional.empty()); - return JacksonMapper.newMapper().treeToValue(inputNode, DataSource.class); - } - private static JsonNode replace(JsonNode node, Function> function) { var value = function.apply(node); if (value.isPresent()) { @@ -55,6 +46,17 @@ public class BeaconProxyImpl extends ProxyProvider { return replacement; } + @Override + @SneakyThrows + @SuppressWarnings("unchecked") + public T downstreamTransform(T object, ShellStore proxy) { + var proxyNode = JacksonMapper.getDefault().valueToTree(proxy); + var inputNode = JacksonMapper.getDefault().valueToTree(object); + var localNode = JacksonMapper.getDefault().valueToTree(ShellStore.local()); + replace(inputNode, node -> node.equals(proxyNode) ? Optional.of(localNode) : Optional.empty()); + return (T) JacksonMapper.getDefault().treeToValue(inputNode, object.getClass()); + } + @Override public ShellStore getProxy(Object base) { var proxy = base instanceof Proxyable p ? p.getProxy() : null; diff --git a/core/src/main/java/io/xpipe/core/util/ProxyManagerProvider.java b/core/src/main/java/io/xpipe/core/util/ProxyManagerProvider.java new file mode 100644 index 000000000..f369e8ec5 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/util/ProxyManagerProvider.java @@ -0,0 +1,25 @@ +package io.xpipe.core.util; + +import io.xpipe.core.process.ShellProcessControl; + +import java.util.Optional; +import java.util.ServiceLoader; + +public abstract class ProxyManagerProvider { + + private static ProxyManagerProvider INSTANCE; + + public static ProxyManagerProvider get() { + if (INSTANCE == null) { + INSTANCE = ServiceLoader.load(ModuleLayer.boot(), ProxyManagerProvider.class) + .findFirst() + .orElseThrow(); + } + + return INSTANCE; + } + + public abstract Optional checkCompatibility(ShellProcessControl pc) throws Exception; + + public abstract boolean setup(ShellProcessControl pc) throws Exception; +} diff --git a/core/src/main/java/io/xpipe/core/util/ProxyProvider.java b/core/src/main/java/io/xpipe/core/util/ProxyProvider.java index ec47e95b6..41aebb1e5 100644 --- a/core/src/main/java/io/xpipe/core/util/ProxyProvider.java +++ b/core/src/main/java/io/xpipe/core/util/ProxyProvider.java @@ -22,6 +22,8 @@ public abstract class ProxyProvider { return INSTANCE; } + public abstract T downstreamTransform(T object, ShellStore proxy); + public abstract ShellStore getProxy(Object base); public abstract boolean isRemote(Object base); diff --git a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java index b8cce360a..eb5fee522 100644 --- a/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java +++ b/core/src/main/java/io/xpipe/core/util/XPipeInstallation.java @@ -12,7 +12,7 @@ import java.util.List; public class XPipeInstallation { public static String getInstallationBasePathForCLI(ShellProcessControl p, String cliExecutable) throws Exception { - var defaultInstallation = getDefaultInstallationBasePath(p); + var defaultInstallation = getDefaultInstallationBasePath(p, true); if (p.getOsType().equals(OsType.LINUX) && cliExecutable.equals("/usr/bin/xpipe")) { return defaultInstallation; } @@ -32,18 +32,6 @@ public class XPipeInstallation { } } - public static boolean containsCompatibleDefaultInstallation(ShellProcessControl p, String version) throws Exception { - var defaultBase = getDefaultInstallationBasePath(p); - var executable = getInstallationExecutable(p, defaultBase); - if (!p.executeBooleanSimpleCommand(p.getShellType().createFileExistsCommand(executable))) { - return false; - } - - try (CommandProcessControl c = p.command(List.of(executable, "version")).start()) { - return c.readOrThrow().equals(version); - } - } - public static String getInstallationExecutable(ShellProcessControl p, String installation) throws Exception { var executable = getDaemonExecutablePath(p.getOsType()); var file = FileNames.join(installation, executable); @@ -61,14 +49,16 @@ public class XPipeInstallation { public static String getDefaultInstallationBasePath() throws Exception { try (ShellProcessControl pc = new LocalStore().create().start()) { - return getDefaultInstallationBasePath(pc); + return getDefaultInstallationBasePath(pc, true); } } - public static String getDefaultInstallationBasePath(ShellProcessControl p) throws Exception { - var customHome = p.executeStringSimpleCommand(p.getShellType().getPrintVariableCommand("XPIPE_HOME")); - if (!customHome.isEmpty()) { - return customHome; + public static String getDefaultInstallationBasePath(ShellProcessControl p, boolean acceptPortable) throws Exception { + if (acceptPortable) { + var customHome = p.executeStringSimpleCommand(p.getShellType().getPrintVariableCommand("XPIPE_HOME")); + if (!customHome.isEmpty()) { + return customHome; + } } String path = null; diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index f488c7259..f3a2aec04 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -26,6 +26,7 @@ open module io.xpipe.core { uses io.xpipe.core.source.WriteMode; uses LocalProcessControlProvider; uses io.xpipe.core.util.ProxyProvider; + uses io.xpipe.core.util.ProxyManagerProvider; provides WriteMode with WriteMode.Replace, WriteMode.Append, WriteMode.Prepend; provides com.fasterxml.jackson.databind.Module with diff --git a/extension/src/main/java/io/xpipe/extension/XPipeProxy.java b/extension/src/main/java/io/xpipe/extension/XPipeProxy.java deleted file mode 100644 index 6747d4385..000000000 --- a/extension/src/main/java/io/xpipe/extension/XPipeProxy.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.xpipe.extension; - -import io.xpipe.core.impl.FileNames; -import io.xpipe.core.process.ShellProcessControl; -import io.xpipe.core.store.ShellStore; -import io.xpipe.core.util.XPipeInstallation; -import io.xpipe.extension.util.XPipeDaemon; - -import java.io.IOException; - -public class XPipeProxy { - - public static void checkSupport(ShellStore store) throws Exception { - if (store == null || ShellStore.isLocal(store)) { - return; - } - - var version = XPipeDaemon.getInstance().getVersion(); - try (ShellProcessControl s = store.create().start()) { - var defaultInstallationExecutable = FileNames.join( - XPipeInstallation.getDefaultInstallationBasePath(s), - XPipeInstallation.getDaemonExecutablePath(s.getOsType())); - if (!s.executeBooleanSimpleCommand( - s.getShellType().createFileExistsCommand(defaultInstallationExecutable))) { - throw new IOException(I18n.get("noInstallationFound")); - } - - var installationVersion = XPipeInstallation.queryInstallationVersion(s, defaultInstallationExecutable); - if (!version.equals(installationVersion)) { - throw new IOException(I18n.get("versionMismatch", version, installationVersion)); - } - } - } -}