forked from GitHub-Mirror/riotX-android
Use WorkManager for process we don't want to loose
This commit is contained in:
parent
a5bd5c8fb1
commit
0f34daf3b3
@ -39,10 +39,11 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val m
|
|||||||
if (changeSet == null) {
|
if (changeSet == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val indexes = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
val updateIndexes = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
||||||
process(changeSet.realmResults, indexes)
|
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
|
package im.vector.matrix.android.internal.session
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
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.group.GroupService
|
||||||
import im.vector.matrix.android.api.session.room.RoomService
|
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.database.LiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.session.events.prune.EventsPruner
|
import im.vector.matrix.android.internal.session.events.prune.EventsPruner
|
||||||
import im.vector.matrix.android.internal.session.group.DefaultGroupService
|
import im.vector.matrix.android.internal.session.group.DefaultGroupService
|
||||||
@ -66,7 +66,7 @@ internal class SessionModule(private val sessionParams: SessionParams) : Module
|
|||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
val roomSummaryUpdater = RoomSummaryUpdater(get(), get(), get(), get(), sessionParams.credentials)
|
val roomSummaryUpdater = RoomSummaryUpdater(get(), get(), get(), get(), sessionParams.credentials)
|
||||||
val groupSummaryUpdater = GroupSummaryUpdater(get(), get())
|
val groupSummaryUpdater = GroupSummaryUpdater(get())
|
||||||
val eventsPruner = EventsPruner(get())
|
val eventsPruner = EventsPruner(get())
|
||||||
listOf<LiveEntityObserver>(roomSummaryUpdater, groupSummaryUpdater, eventsPruner)
|
listOf<LiveEntityObserver>(roomSummaryUpdater, groupSummaryUpdater, eventsPruner)
|
||||||
}
|
}
|
||||||
|
@ -1,68 +1,35 @@
|
|||||||
package im.vector.matrix.android.internal.session.events.prune
|
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 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.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
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.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.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import io.realm.Realm
|
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
|
||||||
|
private const val PRUNE_EVENT_WORKER = "PRUNE_EVENT_WORKER"
|
||||||
|
|
||||||
internal class EventsPruner(monarchy: Monarchy) :
|
internal class EventsPruner(monarchy: Monarchy) :
|
||||||
RealmLiveEntityObserver<EventEntity>(monarchy) {
|
RealmLiveEntityObserver<EventEntity>(monarchy) {
|
||||||
|
|
||||||
override val query = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.REDACTION) }
|
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() }
|
val redactionEvents = results.map { it.asDomain() }
|
||||||
monarchy.writeAsync { realm ->
|
val pruneEventWorkerParams = PruneEventWorkerParams(redactionEvents, updateIndexes.toList(), deletionIndexes.toList())
|
||||||
indexes.forEach { index ->
|
val workData = pruneEventWorkerParams.toData()
|
||||||
val data = redactionEvents[index]
|
|
||||||
pruneEvent(realm, data)
|
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)
|
return CancelableCoroutine(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGroupData(groupId: String): Try<Unit> {
|
fun getGroupData(groupId: String): Try<Unit> {
|
||||||
return Try.monad().binding {
|
return Try.monad().binding {
|
||||||
|
|
||||||
val groupSummary = executeRequest<GroupSummaryResponse> {
|
val groupSummary = executeRequest<GroupSummaryResponse> {
|
||||||
|
@ -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
|
package im.vector.matrix.android.internal.session.group
|
||||||
|
|
||||||
|
import androidx.work.*
|
||||||
import com.zhuinden.monarchy.Monarchy
|
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.RealmLiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
|
||||||
internal class GroupSummaryUpdater(monarchy: Monarchy,
|
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||||
private val getGroupDataRequest: GetGroupDataRequest
|
|
||||||
|
internal class GroupSummaryUpdater(monarchy: Monarchy
|
||||||
) : RealmLiveEntityObserver<GroupEntity>(monarchy) {
|
) : RealmLiveEntityObserver<GroupEntity>(monarchy) {
|
||||||
|
|
||||||
override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }
|
override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }
|
||||||
|
|
||||||
override fun process(results: RealmResults<GroupEntity>, indexes: IntArray) {
|
private val workConstraints = Constraints.Builder()
|
||||||
indexes.forEach { index ->
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
val data = results[index]
|
.build()
|
||||||
fetchGroupData(data)
|
|
||||||
}
|
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 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() }
|
val rooms = results.map { it.asDomain() }
|
||||||
monarchy.writeAsync { realm ->
|
monarchy.writeAsync { realm ->
|
||||||
indexes.forEach { index ->
|
updateIndexes.forEach { index ->
|
||||||
val data = rooms[index]
|
val data = rooms[index]
|
||||||
updateRoom(realm, data)
|
updateRoom(realm, data)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user