From f98c637cd9d78e49e3e0bc9d18810efd181d410e Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Sun, 13 Sep 2026 01:07:07 +0100 Subject: [PATCH] feat(maestro): add Android terminal attach URL builder TerminalPageUrl builds the file:///android_asset/terminal/index.html URL for one session, with the WS /api/attach/:id URL Routes already knows how to build passed through as an encoded query param. --- .../maestro/ui/terminal/TerminalPageUrl.kt | 21 ++++++++++++++ .../ui/terminal/TerminalPageUrlTest.kt | 29 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 android/app/src/main/java/pt/naps/maestro/ui/terminal/TerminalPageUrl.kt create mode 100644 android/app/src/test/java/pt/naps/maestro/ui/terminal/TerminalPageUrlTest.kt diff --git a/android/app/src/main/java/pt/naps/maestro/ui/terminal/TerminalPageUrl.kt b/android/app/src/main/java/pt/naps/maestro/ui/terminal/TerminalPageUrl.kt new file mode 100644 index 0000000..b69542a --- /dev/null +++ b/android/app/src/main/java/pt/naps/maestro/ui/terminal/TerminalPageUrl.kt @@ -0,0 +1,21 @@ +package pt.naps.maestro.ui.terminal + +import java.net.URLEncoder +import pt.naps.maestro.api.Routes +import pt.naps.maestro.data.Uuid + +/** + * The `file:///android_asset/terminal/index.html` URL a [TerminalWebView] + * loads for one session. The embedded xterm.js page reads its `ws` query + * param and opens that as its own `WS /api/attach/:id` connection directly + * — this object only computes the URL, it never touches the socket. + */ +object TerminalPageUrl { + private const val ASSET_URL = "file:///android_asset/terminal/index.html" + + fun build(daemonBaseUrl: String, sessionId: Uuid): String { + val wsUrl = Routes.attachWsUrl(daemonBaseUrl, sessionId) + val encoded = URLEncoder.encode(wsUrl, "UTF-8") + return "$ASSET_URL?ws=$encoded" + } +} diff --git a/android/app/src/test/java/pt/naps/maestro/ui/terminal/TerminalPageUrlTest.kt b/android/app/src/test/java/pt/naps/maestro/ui/terminal/TerminalPageUrlTest.kt new file mode 100644 index 0000000..30a3124 --- /dev/null +++ b/android/app/src/test/java/pt/naps/maestro/ui/terminal/TerminalPageUrlTest.kt @@ -0,0 +1,29 @@ +package pt.naps.maestro.ui.terminal + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class TerminalPageUrlTest { + @Test + fun `builds asset url with the encoded attach ws url`() { + val url = TerminalPageUrl.build("http://192.168.1.5:7070", "abc-123") + assertEquals( + "file:///android_asset/terminal/index.html" + + "?ws=ws%3A%2F%2F192.168.1.5%3A7070%2Fapi%2Fattach%2Fabc-123", + url, + ) + } + + @Test + fun `swaps an https base to wss`() { + val url = TerminalPageUrl.build("https://daemon.example.com", "s1") + assertTrue(url.contains("wss%3A%2F%2Fdaemon.example.com")) + } + + @Test + fun `strips a trailing slash from the daemon base url`() { + val url = TerminalPageUrl.build("http://host:7070/", "s1") + assertTrue(url.contains("ws%3A%2F%2Fhost%3A7070%2Fapi%2Fattach%2Fs1")) + } +}