forked from GitHub-Mirror/riotX-android
Merge pull request #468 from vector-im/feature/fix_realm_issues
Feature/fix realm issues
This commit is contained in:
commit
7fef063e15
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.api.session.room.send
|
package im.vector.matrix.android.api.session.room.send
|
||||||
|
|
||||||
|
|
||||||
enum class SendState {
|
enum class SendState {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
// the event has not been sent
|
// the event has not been sent
|
||||||
@ -33,16 +34,19 @@ enum class SendState {
|
|||||||
// the event failed to be sent because some unknown devices have been found while encrypting it
|
// the event failed to be sent because some unknown devices have been found while encrypting it
|
||||||
FAILED_UNKNOWN_DEVICES;
|
FAILED_UNKNOWN_DEVICES;
|
||||||
|
|
||||||
fun isSent(): Boolean {
|
internal companion object {
|
||||||
return this == SENT || this == SYNCED
|
val HAS_FAILED_STATES = listOf(UNDELIVERED, FAILED_UNKNOWN_DEVICES)
|
||||||
|
val IS_SENT_STATES = listOf(SENT, SYNCED)
|
||||||
|
val IS_SENDING_STATES = listOf(UNSENT, ENCRYPTING, SENDING)
|
||||||
|
val PENDING_STATES = IS_SENDING_STATES + HAS_FAILED_STATES
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasFailed(): Boolean {
|
fun isSent() = IS_SENT_STATES.contains(this)
|
||||||
return this == UNDELIVERED || this == FAILED_UNKNOWN_DEVICES
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSending(): Boolean {
|
fun hasFailed() = HAS_FAILED_STATES.contains(this)
|
||||||
return this == UNSENT || this == ENCRYPTING || this == SENDING
|
|
||||||
}
|
fun isSending() = IS_SENDING_STATES.contains(this)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ internal open class ChunkEntity(@Index var prevToken: String? = null,
|
|||||||
var forwardsStateIndex: Int? = null
|
var forwardsStateIndex: Int? = null
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
|
fun identifier() = "${prevToken}_${nextToken}"
|
||||||
|
|
||||||
@LinkingObjects("chunks")
|
@LinkingObjects("chunks")
|
||||||
val room: RealmResults<RoomEntity>? = null
|
val room: RealmResults<RoomEntity>? = null
|
||||||
|
|
||||||
|
@ -18,20 +18,20 @@ package im.vector.matrix.android.internal.database.model
|
|||||||
|
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
import kotlin.properties.Delegates
|
|
||||||
|
|
||||||
internal open class GroupEntity(@PrimaryKey var groupId: String = ""
|
internal open class GroupEntity(@PrimaryKey var groupId: String = ""
|
||||||
|
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
private var membershipStr: String = Membership.NONE.name
|
private var membershipStr: String = Membership.NONE.name
|
||||||
|
var membership: Membership
|
||||||
@delegate:Ignore
|
get() {
|
||||||
var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue ->
|
return Membership.valueOf(membershipStr)
|
||||||
membershipStr = newValue.name
|
}
|
||||||
}
|
set(value) {
|
||||||
|
membershipStr = value.name
|
||||||
|
}
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
|
||||||
|
@ -19,9 +19,7 @@ package im.vector.matrix.android.internal.database.model
|
|||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
import kotlin.properties.Delegates
|
|
||||||
|
|
||||||
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
||||||
var chunks: RealmList<ChunkEntity> = RealmList(),
|
var chunks: RealmList<ChunkEntity> = RealmList(),
|
||||||
@ -31,11 +29,13 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "",
|
|||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
private var membershipStr: String = Membership.NONE.name
|
private var membershipStr: String = Membership.NONE.name
|
||||||
|
var membership: Membership
|
||||||
@delegate:Ignore
|
get() {
|
||||||
var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue ->
|
return Membership.valueOf(membershipStr)
|
||||||
membershipStr = newValue.name
|
}
|
||||||
}
|
set(value) {
|
||||||
|
membershipStr = value.name
|
||||||
|
}
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,7 @@ import im.vector.matrix.android.api.session.room.model.Membership
|
|||||||
import im.vector.matrix.android.api.session.room.model.VersioningState
|
import im.vector.matrix.android.api.session.room.model.VersioningState
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.RealmObject
|
import io.realm.RealmObject
|
||||||
import io.realm.annotations.Ignore
|
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.annotations.PrimaryKey
|
||||||
import kotlin.properties.Delegates
|
|
||||||
|
|
||||||
internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||||
var displayName: String? = "",
|
var displayName: String? = "",
|
||||||
@ -41,18 +39,22 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
private var membershipStr: String = Membership.NONE.name
|
private var membershipStr: String = Membership.NONE.name
|
||||||
|
var membership: Membership
|
||||||
|
get() {
|
||||||
|
return Membership.valueOf(membershipStr)
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
membershipStr = value.name
|
||||||
|
}
|
||||||
|
|
||||||
private var versioningStateStr: String = VersioningState.NONE.name
|
private var versioningStateStr: String = VersioningState.NONE.name
|
||||||
|
var versioningState: VersioningState
|
||||||
|
get() {
|
||||||
@delegate:Ignore
|
return VersioningState.valueOf(versioningStateStr)
|
||||||
var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue ->
|
}
|
||||||
membershipStr = newValue.name
|
set(value) {
|
||||||
}
|
versioningStateStr = value.name
|
||||||
|
}
|
||||||
@delegate:Ignore
|
|
||||||
var versioningState: VersioningState by Delegates.observable(VersioningState.valueOf(versioningStateStr)) { _, _, newValue ->
|
|
||||||
versioningStateStr = newValue.name
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
|
|
||||||
|
@ -16,12 +16,10 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.database.query
|
package im.vector.matrix.android.internal.database.query
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.internal.database.model.*
|
import im.vector.matrix.android.internal.database.model.*
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
|
import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.*
|
||||||
import io.realm.Realm
|
import io.realm.*
|
||||||
import io.realm.RealmList
|
|
||||||
import io.realm.RealmQuery
|
|
||||||
import io.realm.Sort
|
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
internal fun TimelineEventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<TimelineEventEntity> {
|
internal fun TimelineEventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<TimelineEventEntity> {
|
||||||
@ -114,3 +112,15 @@ internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEvent
|
|||||||
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId)
|
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun TimelineEventEntity.Companion.findAllInRoomWithSendStates(realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
sendStates: List<SendState>)
|
||||||
|
: RealmResults<TimelineEventEntity> {
|
||||||
|
|
||||||
|
val sendStatesStr = sendStates.map { it.name }.toTypedArray()
|
||||||
|
return realm.where<TimelineEventEntity>()
|
||||||
|
.equalTo(TimelineEventEntityFields.ROOM_ID, roomId)
|
||||||
|
.`in`(TimelineEventEntityFields.ROOT.SEND_STATE_STR,sendStatesStr)
|
||||||
|
.findAll()
|
||||||
|
}
|
@ -34,6 +34,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
|
|||||||
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.model.RoomEntity
|
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
|
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
|
||||||
@ -188,48 +189,47 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
|
|||||||
|
|
||||||
override fun resendAllFailedMessages() {
|
override fun resendAllFailedMessages() {
|
||||||
monarchy.writeAsync { realm ->
|
monarchy.writeAsync { realm ->
|
||||||
RoomEntity.where(realm, roomId).findFirst()?.let { room ->
|
TimelineEventEntity
|
||||||
room.sendingTimelineEvents.filter {
|
.findAllInRoomWithSendStates(realm, roomId, SendState.HAS_FAILED_STATES)
|
||||||
it.root?.sendState?.hasFailed() ?: false
|
.sortedBy { it.root?.originServerTs ?: 0 }
|
||||||
}.sortedBy { it.root?.originServerTs ?: 0 }.forEach { timelineEventEntity ->
|
.forEach { timelineEventEntity ->
|
||||||
timelineEventEntity.root?.let {
|
timelineEventEntity.root?.let {
|
||||||
val event = it.asDomain()
|
val event = it.asDomain()
|
||||||
when (event.getClearType()) {
|
when (event.getClearType()) {
|
||||||
EventType.MESSAGE,
|
EventType.MESSAGE,
|
||||||
EventType.REDACTION,
|
EventType.REDACTION,
|
||||||
EventType.REACTION -> {
|
EventType.REACTION -> {
|
||||||
val content = event.getClearContent().toModel<MessageContent>()
|
val content = event.getClearContent().toModel<MessageContent>()
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
when (content.type) {
|
when (content.type) {
|
||||||
MessageType.MSGTYPE_EMOTE,
|
MessageType.MSGTYPE_EMOTE,
|
||||||
MessageType.MSGTYPE_NOTICE,
|
MessageType.MSGTYPE_NOTICE,
|
||||||
MessageType.MSGTYPE_LOCATION,
|
MessageType.MSGTYPE_LOCATION,
|
||||||
MessageType.MSGTYPE_TEXT -> {
|
MessageType.MSGTYPE_TEXT -> {
|
||||||
it.sendState = SendState.UNSENT
|
it.sendState = SendState.UNSENT
|
||||||
sendEvent(event)
|
sendEvent(event)
|
||||||
}
|
}
|
||||||
MessageType.MSGTYPE_FILE,
|
MessageType.MSGTYPE_FILE,
|
||||||
MessageType.MSGTYPE_VIDEO,
|
MessageType.MSGTYPE_VIDEO,
|
||||||
MessageType.MSGTYPE_IMAGE,
|
MessageType.MSGTYPE_IMAGE,
|
||||||
MessageType.MSGTYPE_AUDIO -> {
|
MessageType.MSGTYPE_AUDIO -> {
|
||||||
//need to resend the attachement
|
//need to resend the attachement
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Timber.e("Cannot resend message ${event.type} / ${content.type}")
|
Timber.e("Cannot resend message ${event.type} / ${content.type}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Timber.e("Unsupported message to resend ${event.type}")
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
Timber.e("Unsupported message to resend ${event.type}")
|
Timber.e("Unsupported message to resend ${event.type}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
|
||||||
Timber.e("Unsupported message to resend ${event.type}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,16 +19,14 @@ package im.vector.matrix.android.internal.session.room.timeline
|
|||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||||
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.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.util.CancelableBag
|
import im.vector.matrix.android.api.util.CancelableBag
|
||||||
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.model.*
|
import im.vector.matrix.android.internal.database.model.*
|
||||||
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.findIncludingEvent
|
import im.vector.matrix.android.internal.database.query.*
|
||||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
|
||||||
import im.vector.matrix.android.internal.database.query.whereInRoom
|
|
||||||
import im.vector.matrix.android.internal.task.TaskConstraints
|
import im.vector.matrix.android.internal.task.TaskConstraints
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
@ -208,21 +206,15 @@ internal class DefaultTimeline(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun pendingEventCount(): Int {
|
override fun pendingEventCount(): Int {
|
||||||
var count = 0
|
return Realm.getInstance(realmConfiguration).use {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0
|
||||||
count = RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.count() ?: 0
|
|
||||||
}
|
}
|
||||||
return count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun failedToDeliverEventCount(): Int {
|
override fun failedToDeliverEventCount(): Int {
|
||||||
var count = 0
|
return Realm.getInstance(realmConfiguration).use {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
TimelineEventEntity.findAllInRoomWithSendStates(it, roomId, SendState.HAS_FAILED_STATES).count()
|
||||||
count = RoomEntity.where(it, roomId).findFirst()?.sendingTimelineEvents?.filter {
|
|
||||||
it.root?.sendState?.hasFailed() ?: false
|
|
||||||
}?.count() ?: 0
|
|
||||||
}
|
}
|
||||||
return count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
@ -278,30 +270,32 @@ internal class DefaultTimeline(
|
|||||||
// Private methods *****************************************************************************
|
// Private methods *****************************************************************************
|
||||||
|
|
||||||
private fun hasMoreInCache(direction: Timeline.Direction): Boolean {
|
private fun hasMoreInCache(direction: Timeline.Direction): Boolean {
|
||||||
val localRealm = Realm.getInstance(realmConfiguration)
|
return Realm.getInstance(realmConfiguration).use { localRealm ->
|
||||||
val timelineEventEntity = buildEventQuery(localRealm).findFirst(direction) ?: return false
|
val timelineEventEntity = buildEventQuery(localRealm).findFirst(direction)
|
||||||
val hasMoreInCache = if (direction == Timeline.Direction.FORWARDS) {
|
?: return false
|
||||||
val firstEvent = builtEvents.firstOrNull() ?: return true
|
if (direction == Timeline.Direction.FORWARDS) {
|
||||||
firstEvent.displayIndex < timelineEventEntity.root!!.displayIndex
|
if (findCurrentChunk(localRealm)?.isLastForward == true) {
|
||||||
} else {
|
return false
|
||||||
val lastEvent = builtEvents.lastOrNull() ?: return true
|
}
|
||||||
lastEvent.displayIndex > timelineEventEntity.root!!.displayIndex
|
val firstEvent = builtEvents.firstOrNull() ?: return true
|
||||||
|
firstEvent.displayIndex < timelineEventEntity.root!!.displayIndex
|
||||||
|
} else {
|
||||||
|
val lastEvent = builtEvents.lastOrNull() ?: return true
|
||||||
|
lastEvent.displayIndex > timelineEventEntity.root!!.displayIndex
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localRealm.close()
|
|
||||||
return hasMoreInCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasReachedEnd(direction: Timeline.Direction): Boolean {
|
private fun hasReachedEnd(direction: Timeline.Direction): Boolean {
|
||||||
val localRealm = Realm.getInstance(realmConfiguration)
|
return Realm.getInstance(realmConfiguration).use { localRealm ->
|
||||||
val currentChunk = findCurrentChunk(localRealm) ?: return false
|
val currentChunk = findCurrentChunk(localRealm) ?: return false
|
||||||
val hasReachedEnd = if (direction == Timeline.Direction.FORWARDS) {
|
if (direction == Timeline.Direction.FORWARDS) {
|
||||||
currentChunk.isLastForward
|
currentChunk.isLastForward
|
||||||
} else {
|
} else {
|
||||||
val eventEntity = buildEventQuery(localRealm).findFirst(direction)
|
val eventEntity = buildEventQuery(localRealm).findFirst(direction)
|
||||||
currentChunk.isLastBackward || eventEntity?.root?.type == EventType.STATE_ROOM_CREATE
|
currentChunk.isLastBackward || eventEntity?.root?.type == EventType.STATE_ROOM_CREATE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
localRealm.close()
|
|
||||||
return hasReachedEnd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user