fix: reuse cached gateway downloads within a 10-minute TTL (#915)
Every tap on a gateway attachment re-downloaded the whole file: the cache write used a random UUID prefix, so no two fetches ever produced the same filename and old copies were never looked up. Cache files are now named deterministically from the gateway path (UUID3 hash + filename), so repeat opens within the TTL (10 min) reuse the existing download and skip the network entirely. Stale entries fall through to a fresh fetch that overwrites the cache via temp-file + rename, so a failed re-download never destroys a previously-good copy. Content types are remembered in-memory per path so cache hits still hand the viewer the right MIME. Also adds isFreshCacheFile()/cacheFileNameFor() unit tests. Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
b653903fa8
commit
d8be45b8fc
2 files changed
+83
-12
No files matched your search
@@ -13,6 +13,7 @@ import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
@@ -108,6 +109,31 @@ class GatewayFileClientTest {
|
||||
assertEquals("a b.png", GatewayFileClient.parseFilename("inline; filename*=UTF-8''a%20b.png"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cacheFileNameFor is deterministic per path`() {
|
||||
val first = GatewayFileClient.cacheFileNameFor("/tmp/report.pdf")
|
||||
val second = GatewayFileClient.cacheFileNameFor("/tmp/report.pdf")
|
||||
val other = GatewayFileClient.cacheFileNameFor("/tmp/other.pdf")
|
||||
assertEquals(first, second)
|
||||
assertNotEquals(first, other)
|
||||
assertTrue(first.endsWith("-report.pdf"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isFreshCacheFile respects the TTL`() {
|
||||
val dir = java.io.File(System.getProperty("java.io.tmpdir"), "gwcache_${System.nanoTime()}").apply { mkdirs() }
|
||||
try {
|
||||
val fresh = java.io.File(dir, "fresh").apply { writeText("x") }
|
||||
fresh.setLastModified(System.currentTimeMillis() - 60_000L) // 1 min old
|
||||
val stale = java.io.File(dir, "stale").apply { writeText("x") }
|
||||
stale.setLastModified(System.currentTimeMillis() - 60 * 60 * 1000L) // 1 h old
|
||||
assertTrue(GatewayFileClient.isFreshCacheFile(fresh))
|
||||
assertFalse(GatewayFileClient.isFreshCacheFile(stale))
|
||||
} finally {
|
||||
dir.deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `copyChunked copies input to output byte-for-byte`() =
|
||||
runTest {
|
||||
|
||||
Reference in new issue
Block a user