diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java index b69d85a2..111708ee 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconClient.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.node.TextNode; import io.xpipe.beacon.exchange.MessageExchanges; import io.xpipe.beacon.exchange.data.ClientErrorMessage; import io.xpipe.beacon.exchange.data.ServerErrorMessage; -import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.store.ShellStore; import io.xpipe.core.util.JacksonMapper; import lombok.Builder; @@ -107,16 +106,10 @@ public class BeaconClient implements AutoCloseable { public static BeaconClient connectProxy(ShellStore proxy) throws Exception { var control = proxy.create().start(); var command = control.command("xpipe beacon").start(); - return BeaconClient.connectGateway( - command, - BeaconClient.GatewayClientInformation.builder() - .build()); - } - - private static BeaconClient connectGateway(CommandProcessControl control, GatewayClientInformation information) throws Exception { - var client = new BeaconClient(() -> {}, control.getStdout(), control.getStdin()); - client.sendObject(JacksonMapper.newMapper().valueToTree(information)); - return client; + command.discardErr(); + return new BeaconClient(() -> { + command.close(); + }, command.getStdout(), command.getStdin()); } public static Optional tryConnect(ClientInformation information) { diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java b/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java index 47b8a610..c1c2dcf8 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconConfig.java @@ -16,6 +16,14 @@ public class BeaconConfig { 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 DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs"; + 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/NamedFunction.java b/beacon/src/main/java/io/xpipe/beacon/NamedFunction.java index 8ba15c16..2565856a 100644 --- a/beacon/src/main/java/io/xpipe/beacon/NamedFunction.java +++ b/beacon/src/main/java/io/xpipe/beacon/NamedFunction.java @@ -1,17 +1,70 @@ package io.xpipe.beacon; -import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.xpipe.beacon.exchange.NamedFunctionExchange; -import io.xpipe.core.util.Proxyable; +import io.xpipe.core.util.JacksonMapper; import lombok.Getter; import lombok.SneakyThrows; +import java.io.IOException; import java.util.Arrays; @Getter -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) public abstract class NamedFunction { + private static ModuleLayer layer; + + public static void init(ModuleLayer l) { + layer = l; + } + + public static class Serializer extends StdSerializer { + + protected Serializer() { + super(NamedFunction.class); + } + + @Override + public void serialize(NamedFunction value, JsonGenerator gen, SerializerProvider provider) throws IOException { + var node = (ObjectNode) JacksonMapper.getDefault().valueToTree(value); + node.set("module", new TextNode(value.getClass().getModule().getName())); + node.set("class", new TextNode(value.getClass().getName())); + gen.writeTree(node); + } + } + + public static class Deserializer extends StdDeserializer> { + + protected Deserializer() { + super(NamedFunction.class); + } + + @Override + @SneakyThrows + public NamedFunction deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException, JacksonException { + var tree = (ObjectNode) JacksonMapper.getDefault().readTree(p); + var moduleReference = tree.remove("module").asText(); + var classReference = tree.remove("class").asText(); + var module = layer.findModule(moduleReference).orElseThrow(); + var targetClass = Class.forName(module, classReference); + + if (targetClass == null) { + throw new IllegalArgumentException("Named function class not found: " + classReference); + } + + return (NamedFunction) JacksonMapper.getDefault().treeToValue(tree, targetClass); + } + } + @SneakyThrows public T call() { var proxyStore = Proxyable.getProxy(getProxyBase()); diff --git a/core/src/main/java/io/xpipe/core/util/Proxyable.java b/beacon/src/main/java/io/xpipe/beacon/Proxyable.java similarity index 79% rename from core/src/main/java/io/xpipe/core/util/Proxyable.java rename to beacon/src/main/java/io/xpipe/beacon/Proxyable.java index de6afcba..2dad3b72 100644 --- a/core/src/main/java/io/xpipe/core/util/Proxyable.java +++ b/beacon/src/main/java/io/xpipe/beacon/Proxyable.java @@ -1,4 +1,4 @@ -package io.xpipe.core.util; +package io.xpipe.beacon; import io.xpipe.core.store.ShellStore; @@ -6,7 +6,7 @@ public interface Proxyable { public static ShellStore getProxy(Object base) { var proxy = base instanceof Proxyable p ? p.getProxy() : null; - return ShellStore.isLocal(proxy) ? null : proxy; + return ShellStore.isLocal(proxy) ? (BeaconConfig.localProxy() ? proxy : null) : proxy; } public static boolean isRemote(Object base) { diff --git a/beacon/src/main/java/io/xpipe/beacon/exchange/NamedFunctionExchange.java b/beacon/src/main/java/io/xpipe/beacon/exchange/NamedFunctionExchange.java index 1b2c485c..f952d365 100644 --- a/beacon/src/main/java/io/xpipe/beacon/exchange/NamedFunctionExchange.java +++ b/beacon/src/main/java/io/xpipe/beacon/exchange/NamedFunctionExchange.java @@ -1,5 +1,7 @@ package io.xpipe.beacon.exchange; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.xpipe.beacon.NamedFunction; import io.xpipe.beacon.RequestMessage; import io.xpipe.beacon.ResponseMessage; @@ -18,6 +20,9 @@ public class NamedFunctionExchange implements MessageExchange { @Builder @Value public static class Request implements RequestMessage { + + @JsonSerialize(using = NamedFunction.Serializer.class, as = NamedFunction.class) + @JsonDeserialize(using = NamedFunction.Deserializer.class, as = NamedFunction.class) NamedFunction function; } diff --git a/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java b/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java new file mode 100644 index 00000000..edf8d5a7 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/impl/LocalProcessControlProvider.java @@ -0,0 +1,26 @@ +package io.xpipe.core.impl; + +import io.xpipe.core.process.ShellProcessControl; + +import java.util.ServiceLoader; + +public abstract class LocalProcessControlProvider { + + private static LocalProcessControlProvider INSTANCE; + + public static void init(ModuleLayer layer) { + INSTANCE = layer != null + ? ServiceLoader.load(layer, LocalProcessControlProvider.class) + .findFirst() + .orElseThrow() + : ServiceLoader.load(LocalProcessControlProvider.class) + .findFirst() + .orElseThrow(); + } + + public static ShellProcessControl create() { + return INSTANCE.createProcessControl(); + } + + public abstract ShellProcessControl createProcessControl(); +} diff --git a/core/src/main/java/io/xpipe/core/impl/LocalStore.java b/core/src/main/java/io/xpipe/core/impl/LocalStore.java index dbdc7515..b1a5d461 100644 --- a/core/src/main/java/io/xpipe/core/impl/LocalStore.java +++ b/core/src/main/java/io/xpipe/core/impl/LocalStore.java @@ -10,7 +10,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ServiceLoader; @JsonTypeName("local") public class LocalStore extends JacksonizedValue implements FileSystemStore, MachineStore { @@ -51,18 +50,4 @@ public class LocalStore extends JacksonizedValue implements FileSystemStore, Mac return LocalProcessControlProvider.create(); } - public static abstract class LocalProcessControlProvider { - - private static LocalProcessControlProvider INSTANCE; - - public static void init(ModuleLayer layer) { - INSTANCE = ServiceLoader.load(layer, LocalProcessControlProvider.class).findFirst().orElseThrow(); - } - - public static ShellProcessControl create() { - return INSTANCE.createProcessControl(); - } - - public abstract ShellProcessControl createProcessControl(); - } } diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 795f0837..0a2ba3a8 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -1,4 +1,4 @@ -import io.xpipe.core.impl.LocalStore; +import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.source.WriteMode; import io.xpipe.core.util.CoreJacksonModule; @@ -24,7 +24,7 @@ open module io.xpipe.core { uses com.fasterxml.jackson.databind.Module; uses io.xpipe.core.source.WriteMode; - uses LocalStore.LocalProcessControlProvider; + uses LocalProcessControlProvider; 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/XPipeServiceProviders.java b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java index a7fdbbee..8c223943 100644 --- a/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java +++ b/extension/src/main/java/io/xpipe/extension/XPipeServiceProviders.java @@ -1,7 +1,8 @@ package io.xpipe.extension; import com.fasterxml.jackson.databind.jsontype.NamedType; -import io.xpipe.core.impl.LocalStore; +import io.xpipe.beacon.NamedFunction; +import io.xpipe.core.impl.LocalProcessControlProvider; import io.xpipe.core.util.JacksonMapper; import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.prefs.PrefsProviders; @@ -9,7 +10,7 @@ import io.xpipe.extension.prefs.PrefsProviders; public class XPipeServiceProviders { public static void load(ModuleLayer layer) { - LocalStore.LocalProcessControlProvider.init(layer); + LocalProcessControlProvider.init(layer); TrackEvent.info("Loading extension providers ..."); DataSourceProviders.init(layer); @@ -35,6 +36,7 @@ public class XPipeServiceProviders { SupportedApplicationProviders.loadAll(layer); PrefsProviders.init(layer); + NamedFunction.init(layer); TrackEvent.info("Finished loading extension providers"); } }