feat: gateway files client — fetch any gateway-hosted file over HTTP (#726)
* feat: gateway files client — fetch any gateway-hosted file over HTTP Add GatewayFileClient: a typed client for the gateway's managed-files download endpoint (GET /api/files/download?path=<enc>&token=<enc>), which streams the raw bytes of any file living on the gateway host. This is the mobile equivalent of desktop's mediaExternalUrl() and works on a remote phone (real HTTP, not a host-local file read). - buildDownloadUrl(): pure authed-URL builder (null on blank creds / non-absolute path), mirrors desktop's token-in-query auth. - fetch(): OkHttp GET via the shared client, maps 401/403/404/413 to typed GatewayFileResult variants; returns GatewayFile(name, mime, bytes). - MediaTypes: IMAGE/AUDIO/VIDEO/FILE classification by extension (mirrors desktop MEDIA_BY_EXT) so future consumers can present images, audio, video, or generic files — beyond just images. Pure builders/classifiers are unit-tested. Mobile-only, backend untouched. This is the foundation PR; issue #724's MEDIA: rendering will consume it. * fix: decode filename + handle download-URL in mediaNameFromPath - GatewayFileClient.parseFilename now URL-decodes the captured value so filename*=UTF-8''a%20b.png yields 'a b.png'. - MediaTypes.mediaNameFromPath extracts the filename from the percent-encoded path= query param of a full /api/files/download?path=<enc> URL (the real case), not just a bare path. * fix(remote): fix unit tests for gateway file client and media parsing Replace plus-encoded spaces with %20 in download URL builder, URL-decode filenames in parseFilename, and extract target filename from URL path parameters. --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
5e409e8dc6
commit
439ae9fcba
4 files changed
+385
No files matched your search
@@ -0,0 +1,38 @@
|
||||
package com.m57.hermescontrol.ui.chat
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class MediaTypesTest {
|
||||
@Test
|
||||
fun `classifies known image extensions`() {
|
||||
assertEquals(MediaKind.IMAGE, mediaKindForPath("/tmp/foo.png"))
|
||||
assertEquals(MediaKind.IMAGE, mediaKindForPath("a/b.jpg"))
|
||||
assertEquals(MediaKind.IMAGE, mediaKindForPath("x.WEBP"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `classifies audio and video`() {
|
||||
assertEquals(MediaKind.AUDIO, mediaKindForPath("/tmp/clip.mp3"))
|
||||
assertEquals(MediaKind.VIDEO, mediaKindForPath("/tmp/mov.mkv"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unknown extension falls back to file`() {
|
||||
assertEquals(MediaKind.FILE, mediaKindForPath("/tmp/notes.txt"))
|
||||
assertEquals(MediaKind.FILE, mediaKindForPath("/tmp/noext"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `mime lookup matches kind`() {
|
||||
assertEquals("image/png", mediaMimeForPath("/tmp/x.png"))
|
||||
assertEquals("audio/mpeg", mediaMimeForPath("/tmp/x.mp3"))
|
||||
assertEquals("application/octet-stream", mediaMimeForPath("/tmp/x.weird"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `name extraction handles urls and paths`() {
|
||||
assertEquals("report.pdf", mediaNameFromPath("https://gw/api/files/download?path=%2Ftmp%2Freport.pdf"))
|
||||
assertEquals("a.png", mediaNameFromPath("/home/u/a.png"))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user