Skip to content

Commit 4a50f6a

Browse files
committed
more fidelity with the official one
1 parent 4c1a368 commit 4a50f6a

File tree

2 files changed

+33
-27
lines changed

2 files changed

+33
-27
lines changed

KtorKMPFileCaching/src/localStorageSystemMain/kotlin/fr/frankois944/ktorfilecaching/KtorFileCaching.localStorageSystemMain.kt

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ package fr.frankois944.ktorfilecaching
55
import io.ktor.client.plugins.cache.storage.CacheStorage
66
import io.ktor.client.plugins.cache.storage.CachedResponseData
77
import io.ktor.http.Url
8+
import io.ktor.util.collections.ConcurrentMap
89
import kotlinx.coroutines.CoroutineDispatcher
10+
import kotlinx.coroutines.coroutineScope
911
import kotlinx.coroutines.sync.Mutex
1012
import kotlinx.coroutines.sync.withLock
1113
import kotlinx.coroutines.withContext
@@ -37,7 +39,7 @@ internal class FileCacheStorage(
3739
val dispatcher: CoroutineDispatcher,
3840
val fileSystem: FileSystem = filesystem(),
3941
) : CacheStorage {
40-
private val lock = Mutex() // Coroutine-friendly lock for thread safety
42+
private val mutexes = ConcurrentMap<String, Mutex>()
4143

4244
override suspend fun store(
4345
url: Url,
@@ -70,23 +72,24 @@ internal class FileCacheStorage(
7072
private suspend fun writeCache(
7173
urlHex: String,
7274
caches: List<CachedResponseData>,
73-
) = withContext(dispatcher) {
74-
lock.withLock {
75+
) = coroutineScope {
76+
val mutex = mutexes.computeIfAbsent(urlHex) { Mutex() }
77+
mutex.withLock {
7578
val serializedData = Cbor.encodeToHexString(caches.map { SerializableCachedResponseData(it) })
7679
Window.setItem("${prefix}_$urlHex", serializedData)
7780
}
7881
}
7982

80-
private suspend fun readCache(urlHex: String): List<CachedResponseData> =
81-
withContext(dispatcher) {
82-
lock.withLock {
83-
val item = Window.getItem("${prefix}_$urlHex")
84-
if (item == null) return@withContext emptyList()
85-
return@withContext try {
86-
Cbor.decodeFromHexString<List<SerializableCachedResponseData>>(item).map { it.cachedResponseData }
87-
} catch (e: Exception) {
88-
emptyList()
89-
}
83+
private suspend fun readCache(urlHex: String): List<CachedResponseData> {
84+
val mutex = mutexes.computeIfAbsent(urlHex) { Mutex() }
85+
return mutex.withLock {
86+
val item = Window.getItem("${prefix}_$urlHex")
87+
if (item == null) return@withLock emptyList()
88+
try {
89+
Cbor.decodeFromHexString<List<SerializableCachedResponseData>>(item).map { it.cachedResponseData }
90+
} catch (e: Exception) {
91+
emptyList()
9092
}
9193
}
94+
}
9295
}

KtorKMPFileCaching/src/okioFileSystemMain/kotlin/fr/frankois944/ktorfilecaching/KtorFileCaching.okioFileSystem.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ package fr.frankois944.ktorfilecaching
55
import io.ktor.client.plugins.cache.storage.CacheStorage
66
import io.ktor.client.plugins.cache.storage.CachedResponseData
77
import io.ktor.http.Url
8+
import io.ktor.util.collections.ConcurrentMap
89
import kotlinx.coroutines.CoroutineDispatcher
10+
import kotlinx.coroutines.coroutineScope
911
import kotlinx.coroutines.sync.Mutex
1012
import kotlinx.coroutines.sync.withLock
1113
import kotlinx.coroutines.withContext
@@ -36,7 +38,7 @@ internal class FileCacheStorage(
3638
val dispatcher: CoroutineDispatcher,
3739
val fileSystem: FileSystem = filesystem(),
3840
) : CacheStorage {
39-
private val lock = Mutex() // Coroutine-friendly lock for thread safety
41+
private val mutexes = ConcurrentMap<String, Mutex>()
4042
private val baseDir = "$directoryPath${Path.DIRECTORY_SEPARATOR}$storedCacheDirectory"
4143

4244
init {
@@ -74,25 +76,26 @@ internal class FileCacheStorage(
7476
private suspend fun writeCache(
7577
urlHex: String,
7678
caches: List<CachedResponseData>,
77-
) = withContext(dispatcher) {
78-
lock.withLock {
79+
) = coroutineScope {
80+
val mutex = mutexes.computeIfAbsent(urlHex) { Mutex() }
81+
mutex.withLock {
7982
val filePath = "$baseDir${Path.DIRECTORY_SEPARATOR}$urlHex".toPath()
8083
val serializedData = Cbor.encodeToByteArray(caches.map { SerializableCachedResponseData(it) })
8184
fileSystem.write(filePath) { write(serializedData) }
8285
}
8386
}
8487

85-
private suspend fun readCache(urlHex: String): List<CachedResponseData> =
86-
withContext(dispatcher) {
87-
lock.withLock {
88-
val filePath = "$baseDir${Path.DIRECTORY_SEPARATOR}$urlHex".toPath()
89-
if (!fileSystem.exists(filePath)) return@withContext emptyList()
90-
return@withContext try {
91-
val bytes = fileSystem.read(filePath) { readByteArray() }
92-
Cbor.decodeFromByteArray<List<SerializableCachedResponseData>>(bytes).map { it.cachedResponseData }
93-
} catch (e: Exception) {
94-
emptyList()
95-
}
88+
private suspend fun readCache(urlHex: String): List<CachedResponseData> {
89+
val mutex = mutexes.computeIfAbsent(urlHex) { Mutex() }
90+
return mutex.withLock {
91+
val filePath = "$baseDir${Path.DIRECTORY_SEPARATOR}$urlHex".toPath()
92+
if (!fileSystem.exists(filePath)) return emptyList()
93+
try {
94+
val bytes = fileSystem.read(filePath) { readByteArray() }
95+
Cbor.decodeFromByteArray<List<SerializableCachedResponseData>>(bytes).map { it.cachedResponseData }
96+
} catch (e: Exception) {
97+
emptyList()
9698
}
9799
}
100+
}
98101
}

0 commit comments

Comments
 (0)