mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-21 17:05:39 +03:00
Use WorkManager for process we don't want to loose
This commit is contained in:
parent
a5bd5c8fb1
commit
0f34daf3b3
10 changed files with 221 additions and 72 deletions
|
@ -39,10 +39,11 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val m
|
|||
if (changeSet == null) {
|
||||
return
|
||||
}
|
||||
val indexes = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
||||
process(changeSet.realmResults, indexes)
|
||||
val updateIndexes = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
||||
val deletionIndexes = changeSet.orderedCollectionChangeSet.deletions
|
||||
process(changeSet.realmResults, updateIndexes, deletionIndexes)
|
||||
}
|
||||
|
||||
abstract fun process(results: RealmResults<T>, indexes: IntArray)
|
||||
abstract fun process(results: RealmResults<T>, updateIndexes: IntArray, deletionIndexes: IntArray)
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package im.vector.matrix.android.internal.session
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||
import im.vector.matrix.android.internal.session.events.prune.EventsPruner
|
||||
import im.vector.matrix.android.internal.session.group.DefaultGroupService
|
||||
|
@ -66,7 +66,7 @@ internal class SessionModule(private val sessionParams: SessionParams) : Module
|
|||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
val roomSummaryUpdater = RoomSummaryUpdater(get(), get(), get(), get(), sessionParams.credentials)
|
||||
val groupSummaryUpdater = GroupSummaryUpdater(get(), get())
|
||||
val groupSummaryUpdater = GroupSummaryUpdater(get())
|
||||
val eventsPruner = EventsPruner(get())
|
||||
listOf<LiveEntityObserver>(roomSummaryUpdater, groupSummaryUpdater, eventsPruner)
|
||||
}
|
||||
|
|
|
@ -1,68 +1,35 @@
|
|||
package im.vector.matrix.android.internal.session.events.prune
|
||||
|
||||
import arrow.core.Option
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
|
||||
private const val PRUNE_EVENT_WORKER = "PRUNE_EVENT_WORKER"
|
||||
|
||||
internal class EventsPruner(monarchy: Monarchy) :
|
||||
RealmLiveEntityObserver<EventEntity>(monarchy) {
|
||||
|
||||
override val query = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.REDACTION) }
|
||||
|
||||
override fun process(results: RealmResults<EventEntity>, indexes: IntArray) {
|
||||
override fun process(results: RealmResults<EventEntity>, updateIndexes: IntArray, deletionIndexes: IntArray) {
|
||||
val redactionEvents = results.map { it.asDomain() }
|
||||
monarchy.writeAsync { realm ->
|
||||
indexes.forEach { index ->
|
||||
val data = redactionEvents[index]
|
||||
pruneEvent(realm, data)
|
||||
}
|
||||
}
|
||||
val pruneEventWorkerParams = PruneEventWorkerParams(redactionEvents, updateIndexes.toList(), deletionIndexes.toList())
|
||||
val workData = pruneEventWorkerParams.toData()
|
||||
|
||||
val sendWork = OneTimeWorkRequestBuilder<PruneEventWorker>()
|
||||
.setInputData(workData)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance()
|
||||
.beginUniqueWork(PRUNE_EVENT_WORKER, ExistingWorkPolicy.APPEND, sendWork)
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun pruneEvent(realm: Realm, redactionEvent: Event?) {
|
||||
if (redactionEvent == null || redactionEvent.redacts.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
val eventToPrune = EventEntity.where(realm, eventId = redactionEvent.redacts).findFirst()?.asDomain()
|
||||
?: return
|
||||
|
||||
val allowedKeys = computeAllowedKeys(eventToPrune.type)
|
||||
val prunedContent = allowedKeys.fold(
|
||||
{ eventToPrune.content },
|
||||
{ eventToPrune.content?.filterKeys { key -> it.contains(key) } }
|
||||
)
|
||||
val eventToPruneEntity = eventToPrune.copy(content = prunedContent).asEntity()
|
||||
realm.insertOrUpdate(eventToPruneEntity)
|
||||
}
|
||||
|
||||
private fun computeAllowedKeys(type: String): Option<List<String>> {
|
||||
// Add filtered content, allowed keys in content depends on the event type
|
||||
val result = when (type) {
|
||||
EventType.STATE_ROOM_MEMBER -> listOf("membership")
|
||||
EventType.STATE_ROOM_CREATE -> listOf("creator")
|
||||
EventType.STATE_ROOM_JOIN_RULES -> listOf("join_rule")
|
||||
EventType.STATE_ROOM_POWER_LEVELS -> listOf("users",
|
||||
"users_default",
|
||||
"events",
|
||||
"events_default",
|
||||
"state_default",
|
||||
"ban",
|
||||
"kick",
|
||||
"redact",
|
||||
"invite")
|
||||
EventType.STATE_ROOM_ALIASES -> listOf("aliases")
|
||||
EventType.STATE_CANONICAL_ALIAS -> listOf("alias")
|
||||
EventType.FEEDBACK -> listOf("type", "target_event_id")
|
||||
else -> null
|
||||
}
|
||||
return Option.fromNullable(result)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package im.vector.matrix.android.internal.session.events.prune
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import arrow.core.Option
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.util.tryTransactionAsync
|
||||
import io.realm.Realm
|
||||
import org.koin.standalone.KoinComponent
|
||||
import org.koin.standalone.inject
|
||||
|
||||
internal class PruneEventWorker(context: Context,
|
||||
workerParameters: WorkerParameters
|
||||
) : Worker(context, workerParameters), KoinComponent {
|
||||
|
||||
private val monarchy by inject<Monarchy>()
|
||||
|
||||
override fun doWork(): Result {
|
||||
val params = PruneEventWorkerParams.fromData(inputData) ?: return Result.FAILURE
|
||||
val result = monarchy.tryTransactionAsync { realm ->
|
||||
params.updateIndexes.forEach { index ->
|
||||
val data = params.redactionEvents[index]
|
||||
pruneEvent(realm, data)
|
||||
}
|
||||
}
|
||||
return result.fold({ Result.RETRY }, { Result.SUCCESS })
|
||||
}
|
||||
|
||||
private fun pruneEvent(realm: Realm, redactionEvent: Event?) {
|
||||
if (redactionEvent == null || redactionEvent.redacts.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
val eventToPrune = EventEntity.where(realm, eventId = redactionEvent.redacts).findFirst()?.asDomain()
|
||||
?: return
|
||||
|
||||
val allowedKeys = computeAllowedKeys(eventToPrune.type)
|
||||
val prunedContent = allowedKeys.fold(
|
||||
{ eventToPrune.content },
|
||||
{ eventToPrune.content?.filterKeys { key -> it.contains(key) } }
|
||||
)
|
||||
val eventToPruneEntity = eventToPrune.copy(content = prunedContent).asEntity()
|
||||
realm.insertOrUpdate(eventToPruneEntity)
|
||||
}
|
||||
|
||||
private fun computeAllowedKeys(type: String): Option<List<String>> {
|
||||
// Add filtered content, allowed keys in content depends on the event type
|
||||
val result = when (type) {
|
||||
EventType.STATE_ROOM_MEMBER -> listOf("membership")
|
||||
EventType.STATE_ROOM_CREATE -> listOf("creator")
|
||||
EventType.STATE_ROOM_JOIN_RULES -> listOf("join_rule")
|
||||
EventType.STATE_ROOM_POWER_LEVELS -> listOf("users",
|
||||
"users_default",
|
||||
"events",
|
||||
"events_default",
|
||||
"state_default",
|
||||
"ban",
|
||||
"kick",
|
||||
"redact",
|
||||
"invite")
|
||||
EventType.STATE_ROOM_ALIASES -> listOf("aliases")
|
||||
EventType.STATE_CANONICAL_ALIAS -> listOf("alias")
|
||||
EventType.FEEDBACK -> listOf("type", "target_event_id")
|
||||
else -> null
|
||||
}
|
||||
return Option.fromNullable(result)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package im.vector.matrix.android.internal.session.events.prune
|
||||
|
||||
import androidx.work.Data
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class PruneEventWorkerParams(
|
||||
val redactionEvents: List<Event>,
|
||||
val updateIndexes: List<Int>,
|
||||
val deletionIndexes: List<Int>
|
||||
) {
|
||||
|
||||
fun toData(): Data {
|
||||
val json = adapter.toJson(this)
|
||||
return Data.Builder().putString(KEY, json).build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val moshi = MoshiProvider.providesMoshi()
|
||||
private val adapter = moshi.adapter(PruneEventWorkerParams::class.java)
|
||||
private const val KEY = "PruneEventWorkerParams"
|
||||
|
||||
fun fromData(data: Data): PruneEventWorkerParams? {
|
||||
val json = data.getString(KEY)
|
||||
return if (json == null) {
|
||||
null
|
||||
} else {
|
||||
adapter.fromJson(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ internal class GetGroupDataRequest(
|
|||
return CancelableCoroutine(job)
|
||||
}
|
||||
|
||||
private fun getGroupData(groupId: String): Try<Unit> {
|
||||
fun getGroupData(groupId: String): Try<Unit> {
|
||||
return Try.monad().binding {
|
||||
|
||||
val groupSummary = executeRequest<GroupSummaryResponse> {
|
||||
|
@ -64,7 +64,7 @@ internal class GetGroupDataRequest(
|
|||
return monarchy
|
||||
.tryTransactionSync { realm ->
|
||||
val groupSummaryEntity = GroupSummaryEntity.where(realm, groupId).findFirst()
|
||||
?: realm.createObject(groupId)
|
||||
?: realm.createObject(groupId)
|
||||
|
||||
groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: ""
|
||||
val name = groupSummary.profile?.name
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import arrow.core.Try
|
||||
import org.koin.standalone.KoinComponent
|
||||
import org.koin.standalone.inject
|
||||
|
||||
internal class GetGroupDataWorker(context: Context,
|
||||
workerParameters: WorkerParameters
|
||||
) : Worker(context, workerParameters), KoinComponent {
|
||||
|
||||
private val getGroupDataRequest by inject<GetGroupDataRequest>()
|
||||
|
||||
override fun doWork(): Result {
|
||||
val params = GetGroupDataWorkerParams.fromData(inputData) ?: return Result.FAILURE
|
||||
val results = params.updateIndexes.map { index ->
|
||||
val groupId = params.groupIds[index]
|
||||
fetchGroupData(groupId)
|
||||
}
|
||||
val isSuccessful = results.none { it.isFailure() }
|
||||
return if (isSuccessful) Result.SUCCESS else Result.RETRY
|
||||
}
|
||||
|
||||
private fun fetchGroupData(groupId: String): Try<Unit> {
|
||||
return getGroupDataRequest.getGroupData(groupId)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import androidx.work.Data
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class GetGroupDataWorkerParams(
|
||||
val groupIds: List<String>,
|
||||
val updateIndexes: List<Int>,
|
||||
val deletionIndexes: List<Int>
|
||||
) {
|
||||
|
||||
fun toData(): Data {
|
||||
val json = adapter.toJson(this)
|
||||
return Data.Builder().putString(KEY, json).build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val moshi = MoshiProvider.providesMoshi()
|
||||
private val adapter = moshi.adapter(GetGroupDataWorkerParams::class.java)
|
||||
private const val KEY = "GetGroupDataWorkerParams"
|
||||
|
||||
fun fromData(data: Data): GetGroupDataWorkerParams? {
|
||||
val json = data.getString(KEY)
|
||||
return if (json == null) {
|
||||
null
|
||||
} else {
|
||||
adapter.fromJson(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +1,37 @@
|
|||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import androidx.work.*
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.RealmResults
|
||||
|
||||
internal class GroupSummaryUpdater(monarchy: Monarchy,
|
||||
private val getGroupDataRequest: GetGroupDataRequest
|
||||
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||
|
||||
internal class GroupSummaryUpdater(monarchy: Monarchy
|
||||
) : RealmLiveEntityObserver<GroupEntity>(monarchy) {
|
||||
|
||||
override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }
|
||||
|
||||
override fun process(results: RealmResults<GroupEntity>, indexes: IntArray) {
|
||||
indexes.forEach { index ->
|
||||
val data = results[index]
|
||||
fetchGroupData(data)
|
||||
}
|
||||
private val workConstraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
|
||||
override fun process(results: RealmResults<GroupEntity>, updateIndexes: IntArray, deletionIndexes: IntArray) {
|
||||
val groupIds = results.map { it.groupId }
|
||||
val getGroupDataWorkerParams = GetGroupDataWorkerParams(groupIds, updateIndexes.toList(), deletionIndexes.toList())
|
||||
val workData = getGroupDataWorkerParams.toData()
|
||||
|
||||
val sendWork = OneTimeWorkRequestBuilder<GetGroupDataWorker>()
|
||||
.setInputData(workData)
|
||||
.setConstraints(workConstraints)
|
||||
.build()
|
||||
|
||||
WorkManager.getInstance()
|
||||
.beginUniqueWork(GET_GROUP_DATA_WORKER, ExistingWorkPolicy.APPEND, sendWork)
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun fetchGroupData(data: GroupEntity?) {
|
||||
if (data == null) {
|
||||
return
|
||||
}
|
||||
getGroupDataRequest.execute(data.groupId, object : MatrixCallback<Boolean> {})
|
||||
}
|
||||
|
||||
}
|
|
@ -28,10 +28,10 @@ internal class RoomSummaryUpdater(monarchy: Monarchy,
|
|||
|
||||
override val query = Monarchy.Query<RoomEntity> { RoomEntity.where(it) }
|
||||
|
||||
override fun process(results: RealmResults<RoomEntity>, indexes: IntArray) {
|
||||
override fun process(results: RealmResults<RoomEntity>, updateIndexes: IntArray, deletionIndexes: IntArray) {
|
||||
val rooms = results.map { it.asDomain() }
|
||||
monarchy.writeAsync { realm ->
|
||||
indexes.forEach { index ->
|
||||
updateIndexes.forEach { index ->
|
||||
val data = rooms[index]
|
||||
updateRoom(realm, data)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue