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.
This commit is contained in:
Miguel Palhas
2026-09-13 01:07:07 +01:00
parent 554182d956
commit f98c637cd9
2 changed files with 50 additions and 0 deletions
@@ -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"
}
}
@@ -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"))
}
}