commonMain.ru.alexey.event.threads.secure.SecureRealm.kt Maven / Gradle / Ivy
package ru.alexey.event.threads.secure
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import ru.alexey.event.threads.resources.ObservableResource
import kotlin.jvm.JvmInline
import kotlin.random.Random
import kotlin.reflect.KClass
@JvmInline
value class Seed(val seed: Long)
fun createConfig(vararg objects: KClass, seed: Seed, config: RealmConfiguration.Builder.() -> Unit) =
RealmConfiguration.Builder(
objects.toSet()
).apply(config)
.encryptionKey(
Random(seed.seed).nextBytes(64)
)
.build()
interface WrappedList {
val list: List
}
fun List.wrap() = object : WrappedList {
override val list: List = this@wrap
}
class SecureRealm>(
private val realm: Realm,
private val clazz: KClass,
private val source: StateFlow,
) : StateFlow by source, ObservableResource {
override suspend fun update(block: (T) -> T) {
realm.write {
val old = query(clazz = clazz).find()
val new = old.wrap().apply { block(this as T) }.list
old.filter { it !in new }.forEach { delete(it) }
new.filter { it !in old }.forEach { copyToRealm(it) }
}
}
}
inline fun > secureDatabase(
realm: Realm,
scope: CoroutineScope
): ObservableResource {
val source: StateFlow = realm.query(clazz = R::class).find().asFlow().map {
it.list.wrap() as T
}.stateIn(
scope = scope,
initialValue = emptyList().wrap() as T,
started = SharingStarted.Lazily
)
return SecureRealm(
realm,
clazz = R::class,
source = source
)
}