Skip to content

Instantly share code, notes, and snippets.

@vlad-kasprov
Last active October 29, 2023 08:59
Show Gist options
  • Save vlad-kasprov/83337787c0026fec59a88e0723fcebef to your computer and use it in GitHub Desktop.
Save vlad-kasprov/83337787c0026fec59a88e0723fcebef to your computer and use it in GitHub Desktop.
interface ExampleRemoteDataSource {
suspend fun fetch(): Result<Example>
}
class ExampleRepository(
private val exampleRemoteDataSource: ExampleRemoteDataSource,
) {
private val cache = MutableStateFlow<Example?>(null)
private val lastUpdateStopwatch = Stopwatch()
private val mutex = Mutex()
fun observe(): Flow<Example?> = cache.asStateFlow()
fun get(): Example? = cache.value
suspend fun updateAndGet(updateStrategy: UpdateStrategy): Result<Example> {
val value = get()
if (value != null && !updateStrategy.shouldUpdate()) {
return Result.success(value)
}
return mutex.withLock {
val valueUnderLock = get()
if (valueUnderLock != null && !updateStrategy.shouldUpdate()) {
return@withLock Result.success(valueUnderLock)
}
exampleRemoteDataSource.fetch()
.onSuccess { newValue ->
cache.update { newValue }
lastUpdateStopwatch.restart()
}
}
}
private fun UpdateStrategy.shouldUpdate(): Boolean = when (this) {
is Always -> true
is IfEmpty -> lastUpdateStopwatch.sinceStarted == null
is IfStale -> lastUpdateStopwatch.sinceStarted?.let { it > maxAge } ?: true
}
suspend fun set(value: Example) = mutex.withLock {
cache.update { value }
lastUpdateStopwatch.restart()
}
suspend fun clear() = mutex.withLock {
cache.update { null }
lastUpdateStopwatch.stop()
}
}
class Stopwatch {
@Volatile
private var startedAt: Duration? = null
val sinceStarted
get() = startedAt?.let { sinceBoot - it }
private val sinceBoot
get() = SystemClock.elapsedRealtime().nanoseconds
fun restart() {
startedAt = sinceBoot
}
fun stop() {
startedAt = null
}
}
sealed interface UpdateStrategy {
object Always : UpdateStrategy
object IfEmpty : UpdateStrategy
class IfStale(val maxAge: Duration) : UpdateStrategy
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment