package com.mkfunproj.mobilemkch.data import android.content.Context import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.io.File class Cache(private val context: Context) { private val json = Json private val dir: File by lazy { File(context.cacheDir, "mkch_cache").apply { mkdirs() } } suspend fun set(key: String, value: T, encoder: (T) -> String, ttlSeconds: Long) = withContext(Dispatchers.IO) { val file = File(dir, safeName(key)) val wrapper = CacheWrapper(System.currentTimeMillis(), ttlSeconds, encoder(value)) file.writeText(json.encodeToString(wrapper)) } suspend fun get(key: String, decoder: (String) -> T): T? = withContext(Dispatchers.IO) { val file = File(dir, safeName(key)) if (!file.exists()) return@withContext null val wrapper = runCatching { json.decodeFromString(CacheWrapper.serializer(), file.readText()) }.getOrNull() ?: return@withContext null val ageSec = (System.currentTimeMillis() - wrapper.timestampMs) / 1000 if (ageSec > wrapper.ttlSeconds) return@withContext null return@withContext decoder(wrapper.payload) } suspend fun getStale(key: String, decoder: (String) -> T): T? = withContext(Dispatchers.IO) { val file = File(dir, safeName(key)) if (!file.exists()) return@withContext null val wrapper = runCatching { json.decodeFromString(CacheWrapper.serializer(), file.readText()) }.getOrNull() ?: return@withContext null return@withContext decoder(wrapper.payload) } suspend fun delete(key: String) = withContext(Dispatchers.IO) { File(dir, safeName(key)).delete() } private fun safeName(key: String) = key.hashCode().toString(16) + ".json" } @kotlinx.serialization.Serializable private data class CacheWrapper( val timestampMs: Long, val ttlSeconds: Long, val payload: String )