Fix beacon issues

This commit is contained in:
crschnick
2026-09-13 16:29:21 +00:00
parent 8f7abea554
commit 02618a0fec
3 changed files with 55 additions and 16 deletions
@@ -1,6 +1,8 @@
package io.xpipe.app.beacon;
import io.xpipe.app.beacon.api.HandshakeExchange;
import io.xpipe.app.beacon.mcp.AppMcpServer;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppLocalTemp;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEventFactory;
@@ -62,6 +64,7 @@ public class AppBeaconServer {
AppProperties.get().queryEffectiveBeaconPort(false).orElseThrow());
INSTANCE.initAuthSecret();
INSTANCE.start();
INSTANCE.testConnection();
TrackEvent.withInfo("Started http server")
.tag("port", INSTANCE.getPort())
.build()
@@ -145,6 +148,26 @@ public class AppBeaconServer {
}
}
private void testConnection() {
var address = "127.0.0.1";
var client = new BeaconClient(address, port);
var method = BeaconAuthMethod.Local.builder().authFileContent(localAuthSecret).build();
var info = BeaconClientInformation.Daemon.builder().build();
try {
client.performRequest(HandshakeExchange.Request.builder().client(info).auth(method).build(), 5);
} catch (Exception ex) {
if (AppProperties.get().isPrintBeaconMessages()) {
ErrorEventFactory.fromThrowable(ex).description("Failed to connect to beacon server " + address + ":" + port)
.omit().expected().handle();
}
var msg = "Unable to connect to local running HTTP server on http://localhost:" + port +
". Is something on your system interfering with HTTP connections or TCP sockets?";
ErrorEventFactory.fromMessage(msg).handle();
}
}
private void start() throws IOException {
executor = Executors.newFixedThreadPool(3, r -> {
Thread t = Executors.defaultThreadFactory().newThread(r);
@@ -1,7 +1,10 @@
package io.xpipe.app.beacon;
import io.xpipe.app.beacon.api.HandshakeExchange;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.util.JacksonMapper;
import lombok.SneakyThrows;
@@ -13,31 +16,34 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Optional;
public class BeaconClient {
private final String address;
private final int port;
private String token;
public BeaconClient(int port) {
public BeaconClient(String address, int port) {
this.address = address;
this.port = port;
}
public static BeaconClient establishConnection(int port, BeaconClientInformation information, Path authFile)
throws Exception {
var client = new BeaconClient(port);
public static BeaconClient establishConnection(int port, BeaconClientInformation information, Path authFile) throws Exception {
var addr = "127.0.0.1";
var client = new BeaconClient(addr, port);
var auth = Files.readString(authFile);
HandshakeExchange.Response response = client.performRequest(HandshakeExchange.Request.builder()
.client(information)
.auth(BeaconAuthMethod.Local.builder().authFileContent(auth).build())
.build());
.build(), 5);
client.token = response.getSessionToken();
return client;
}
@SuppressWarnings("unchecked")
public <RES> RES performRequest(BeaconInterface<?> prov, String rawNode)
public <RES> RES performRequest(BeaconInterface<?> prov, String rawNode, int timeoutSeconds)
throws BeaconConnectorException, BeaconClientException, BeaconServerException {
var content = rawNode;
if (AppProperties.get().isPrintBeaconMessages()) {
@@ -46,20 +52,24 @@ public class BeaconClient {
}
var client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.version(HttpClient.Version.HTTP_1_1)
.proxy(HttpClient.Builder.NO_PROXY)
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
HttpResponse<String> response;
try {
// Use direct IP to prevent DNS lookups and potential blocks (e.g. portmaster)
var uri = URI.create("http://127.0.0.1:" + port + prov.getPath());
var uri = URI.create("http://" + address + ":" + port + 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();
var b = builder.uri(uri).POST(HttpRequest.BodyPublishers.ofString(content));
if (timeoutSeconds != -1) {
b.timeout(Duration.ofSeconds(timeoutSeconds));
}
var httpRequest = b.build();
response = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
} catch (Exception ex) {
throw new BeaconConnectorException("Couldn't send request", ex);
@@ -107,6 +117,11 @@ public class BeaconClient {
public <REQ, RES> RES performRequest(REQ req)
throws BeaconConnectorException, BeaconClientException, BeaconServerException {
return performRequest(req, -1);
}
public <REQ, RES> RES performRequest(REQ req, int timeoutSeconds)
throws BeaconConnectorException, BeaconClientException, BeaconServerException {
ObjectNode node = JacksonMapper.getDefault().valueToTree(req);
var prov = BeaconInterface.byRequest(req);
if (prov.isEmpty()) {
@@ -114,10 +129,10 @@ public class BeaconClient {
}
if (AppProperties.get().isPrintBeaconMessages()) {
System.out.println(
"Sending request to server of type " + req.getClass().getName());
"Sending request to server " + address + ":" + port + " of type " + req.getClass().getName());
}
return performRequest(prov.get(), node.toPrettyString());
return performRequest(prov.get(), node.toPrettyString(), timeoutSeconds);
}
private Optional<BeaconClientErrorResponse> parseClientError(HttpResponse<String> response)
@@ -6,10 +6,7 @@ import io.xpipe.app.process.ProcessOutputException;
import io.xpipe.app.util.OsType;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.AccessDeniedException;
import java.nio.file.FileSystemException;
import java.nio.file.InvalidPathException;
import java.nio.file.NoSuchFileException;
import java.nio.file.*;
import java.util.*;
public class ErrorEventFactory {
@@ -70,6 +67,10 @@ public class ErrorEventFactory {
return "No such file: " + nsfe.getMessage();
}
if (t instanceof FileAlreadyExistsException faee) {
return "File already exists: " + faee.getMessage();
}
if (t instanceof InvalidPathException ipe) {
return "Invalid file path: " + ipe.getMessage();
}