From a38fe4eaa30f7399cc878ded2c1abf6fb21d7435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Fri, 21 Nov 2025 13:12:58 +0000 Subject: [PATCH] Garmin: Handle HTTP requests for image service --- .../devices/garmin/http/HttpHandler.java | 11 +++- .../garmin/http/ImageServiceHandler.java | 57 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/ImageServiceHandler.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/HttpHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/HttpHandler.java index 032d7d37bb..1781ff9120 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/HttpHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/HttpHandler.java @@ -21,11 +21,13 @@ public class HttpHandler { private final AgpsHandler agpsHandler; private final ContactsHandler contactsHandler; private final OauthHandler oauthHandler; + private final ImageServiceHandler imageServiceHandler; public HttpHandler(GarminSupport deviceSupport) { agpsHandler = new AgpsHandler(deviceSupport); contactsHandler = new ContactsHandler(deviceSupport); oauthHandler = new OauthHandler(deviceSupport); + imageServiceHandler = new ImageServiceHandler(); } public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) { @@ -62,6 +64,9 @@ public class HttpHandler { } else if (request.getPath().startsWith("/api/oauth") || request.getPath().startsWith("/oauthTokenExchangeService")) { LOG.info("Got OAuth request for {}", request.getPath()); response = oauthHandler.handleRequest(request); + } else if (request.getPath().startsWith("/image-service/")) { + LOG.info("Got image service request for {}", request.getPath()); + response = imageServiceHandler.handleRequest(request); } else { LOG.warn("Unhandled path {}", request.getPath()); response = null; @@ -92,9 +97,9 @@ public class HttpHandler { ); } - if (response.getStatus() == 200 && request.getRawRequest().hasUseDataXfer() && request.getRawRequest().getUseDataXfer()) { + if (request.getRawRequest().hasUseDataXfer() && request.getRawRequest().getUseDataXfer()) { LOG.debug("Data will be returned using data_xfer"); - int id = DataTransferHandler.registerData(response.getBody()); + final int id = DataTransferHandler.registerData(response.getBody()); if (response.getOnDataSuccessfullySentListener() != null) { DataTransferHandler.addOnDataSuccessfullySentListener(id, response.getOnDataSuccessfullySentListener()); } @@ -136,7 +141,7 @@ public class HttpHandler { } return GdiHttpService.HttpService.RawResponse.newBuilder() - .setStatus(response.getStatus() / 100 == 2 ? GdiHttpService.HttpService.Status.OK : GdiHttpService.HttpService.Status.UNKNOWN_STATUS) + .setStatus(GdiHttpService.HttpService.Status.OK) .setHttpStatus(response.getStatus()) .setBody(ByteString.copyFrom(responseBody)) .addAllHeader(responseHeaders) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/ImageServiceHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/ImageServiceHandler.java new file mode 100644 index 0000000000..2d60f829bc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/garmin/http/ImageServiceHandler.java @@ -0,0 +1,57 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiHttpService; + +public class ImageServiceHandler { + private static final Logger LOG = LoggerFactory.getLogger(ImageServiceHandler.class); + + private static final Gson GSON = new GsonBuilder() + //.serializeNulls() + .create(); + + public GarminHttpResponse handleRequest(final GarminHttpRequest request) { + if (request.getRawRequest().getMethod() != GdiHttpService.HttpService.Method.GET) { + LOG.warn("Known image service requests should be GET"); + return null; + } + + if (!request.getPath().equals("/image-service/v2/device/images/details")) { + LOG.warn("Unknown image service path {}", request.getPath()); + return null; + } + + final String ownerAliasId = request.getQuery().get("ownerAliasId"); + + final String requestId = UUID.randomUUID().toString(); + + final ErrorResponse errorResponse = new ErrorResponse(requestId, Collections.singletonList(new Error( + "Owner alias (" + ownerAliasId + ") not found", + "NOT_FOUND" + ))); + + final GarminHttpResponse response = new GarminHttpResponse(); + response.setStatus(404); + response.setBody(GSON.toJson(errorResponse).getBytes(StandardCharsets.UTF_8)); + response.getHeaders().put("Content-Type", "application/json"); + response.getHeaders().put("x-request-id", requestId); + + return response; + } + + public record ErrorResponse(String requestId, List errors) { + } + + public record Error(String message, String type) { + } +}