forked from GitHub-Mirror/riotX-android
Sync : start insertion in DB
This commit is contained in:
@ -0,0 +1,25 @@
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import com.squareup.moshi.Types
|
||||
import im.vector.matrix.android.api.events.Event
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
|
||||
|
||||
object EventMapper {
|
||||
|
||||
private val moshi = MoshiProvider.providesMoshi()
|
||||
private val type = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
|
||||
private val adapter = moshi.adapter<Map<String, Any>>(type)
|
||||
|
||||
fun map(event: Event): EventEntity {
|
||||
val eventEntity = EventEntity()
|
||||
eventEntity.eventId = event.eventId
|
||||
eventEntity.content = adapter.toJson(event.content)
|
||||
eventEntity.prevContent = adapter.toJson(event.prevContent)
|
||||
eventEntity.stateKey = event.stateKey
|
||||
eventEntity.type = event.type
|
||||
return eventEntity
|
||||
}
|
||||
|
||||
}
|
@ -6,9 +6,9 @@ import io.objectbox.annotation.Id
|
||||
@Entity
|
||||
class EventEntity {
|
||||
@Id var id: Long = 0
|
||||
lateinit var eventId: String
|
||||
lateinit var type: String
|
||||
lateinit var content: String
|
||||
var eventId: String? = null
|
||||
var prevContent: String? = null
|
||||
var stateKey: String? = null
|
||||
}
|
@ -1,12 +1,37 @@
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.objectbox.annotation.Convert
|
||||
import io.objectbox.annotation.Entity
|
||||
import io.objectbox.annotation.Id
|
||||
import io.objectbox.converter.PropertyConverter
|
||||
import io.objectbox.relation.ToMany
|
||||
|
||||
@Entity
|
||||
class RoomEntity {
|
||||
@Id var id: Long = 0
|
||||
@Convert(converter = MembershipConverter::class, dbType = String::class)
|
||||
var membership: Membership = Membership.NONE
|
||||
lateinit var roomId: String
|
||||
lateinit var chunks: ToMany<ChunkEntity>
|
||||
|
||||
companion object;
|
||||
|
||||
enum class Membership {
|
||||
JOINED,
|
||||
LEFT,
|
||||
INVITED,
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
class MembershipConverter : PropertyConverter<RoomEntity.Membership, String> {
|
||||
|
||||
override fun convertToDatabaseValue(entityProperty: RoomEntity.Membership?): String? {
|
||||
return entityProperty?.name
|
||||
}
|
||||
|
||||
override fun convertToEntityProperty(databaseValue: String?): RoomEntity.Membership? {
|
||||
return databaseValue?.let { RoomEntity.Membership.valueOf(databaseValue) }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity_
|
||||
import io.objectbox.Box
|
||||
|
||||
fun RoomEntity.Companion.getForId(roomBox: Box<RoomEntity>, roomId: String): RoomEntity? {
|
||||
return roomBox
|
||||
.query()
|
||||
.equal(RoomEntity_.roomId, roomId)
|
||||
.build()
|
||||
.findUnique()
|
||||
}
|
||||
|
||||
fun RoomEntity.Companion.getAll(roomBox: Box<RoomEntity>, membership: RoomEntity.Membership? = null): List<RoomEntity> {
|
||||
val query = roomBox.query()
|
||||
if (membership != null) {
|
||||
query.filter { it.membership == membership }
|
||||
}
|
||||
return query.build().find()
|
||||
}
|
@ -1,9 +1,61 @@
|
||||
package im.vector.matrix.android.internal.events.sync
|
||||
|
||||
class RoomSyncHandler() {
|
||||
import im.vector.matrix.android.internal.database.mapper.EventMapper
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
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.query.getForId
|
||||
import im.vector.matrix.android.internal.events.sync.data.RoomSync
|
||||
import io.objectbox.Box
|
||||
import io.objectbox.BoxStore
|
||||
|
||||
|
||||
class RoomSyncHandler(
|
||||
boxStore: BoxStore
|
||||
) {
|
||||
|
||||
private val eventBox: Box<EventEntity> = boxStore.boxFor(EventEntity::class.java)
|
||||
private val chunkBox: Box<ChunkEntity> = boxStore.boxFor(ChunkEntity::class.java)
|
||||
private val roomBox: Box<RoomEntity> = boxStore.boxFor(RoomEntity::class.java)
|
||||
|
||||
fun handleJoinedRooms(roomSyncByRoom: Map<String, RoomSync>?) {
|
||||
if (roomSyncByRoom == null) {
|
||||
return
|
||||
}
|
||||
val roomEntities = ArrayList<RoomEntity>()
|
||||
roomSyncByRoom.forEach { roomId, roomSync ->
|
||||
val roomEntity = handleJoinedRoom(roomId, roomSync)
|
||||
roomEntities.add(roomEntity)
|
||||
}
|
||||
roomBox.put(roomEntities)
|
||||
}
|
||||
|
||||
private fun handleJoinedRoom(roomId: String, roomSync: RoomSync): RoomEntity {
|
||||
val roomEntity = RoomEntity.getForId(roomBox, roomId) ?: RoomEntity().apply { this.roomId = roomId }
|
||||
if (roomEntity.membership == RoomEntity.Membership.INVITED) {
|
||||
roomEntity.chunks
|
||||
.map { it.events }
|
||||
.forEach { eventBox.remove(it) }
|
||||
chunkBox.remove(roomEntity.chunks)
|
||||
}
|
||||
roomEntity.membership = RoomEntity.Membership.JOINED
|
||||
if (roomSync.timeline != null) {
|
||||
val chunkEntity = ChunkEntity()
|
||||
chunkEntity.prevToken = roomSync.timeline.prevBatch
|
||||
roomSync.timeline.events
|
||||
.map { event -> EventMapper.map(event) }
|
||||
.forEach { chunkEntity.events.add(it) }
|
||||
roomEntity.chunks.add(chunkEntity)
|
||||
}
|
||||
|
||||
if (roomSync.state != null) {
|
||||
val chunkEntity = ChunkEntity()
|
||||
roomSync.state.events
|
||||
.map { event -> EventMapper.map(event) }
|
||||
.forEach { chunkEntity.events.add(it) }
|
||||
roomEntity.chunks.add(chunkEntity)
|
||||
}
|
||||
return roomEntity
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,11 @@ class SyncModule : Module {
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
SyncResponseHandler(get())
|
||||
RoomSyncHandler(get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
SyncResponseHandler(get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
@ -8,21 +8,14 @@ import im.vector.matrix.android.internal.legacy.data.Room
|
||||
import im.vector.matrix.android.internal.legacy.data.store.IMXStore
|
||||
import im.vector.matrix.android.internal.legacy.data.store.MXMemoryStore
|
||||
import im.vector.matrix.android.internal.legacy.rest.client.AccountDataRestClient
|
||||
import im.vector.matrix.android.internal.legacy.rest.model.RoomMember
|
||||
import im.vector.matrix.android.internal.legacy.rest.model.bingrules.PushRulesResponse
|
||||
import im.vector.matrix.android.internal.legacy.util.JsonUtils
|
||||
import timber.log.Timber
|
||||
import java.util.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.Map
|
||||
import kotlin.collections.MutableList
|
||||
import kotlin.collections.MutableMap
|
||||
import kotlin.collections.emptyList
|
||||
import kotlin.collections.isNotEmpty
|
||||
import kotlin.collections.set
|
||||
|
||||
class SyncResponseHandler(private val dataHandler: MXDataHandler) {
|
||||
class SyncResponseHandler(
|
||||
private val roomSyncHandler: RoomSyncHandler,
|
||||
private val dataHandler: MXDataHandler
|
||||
) {
|
||||
|
||||
private val store = dataHandler.store
|
||||
private val leftRoomsStore = MXMemoryStore()
|
||||
@ -34,6 +27,13 @@ class SyncResponseHandler(private val dataHandler: MXDataHandler) {
|
||||
return
|
||||
}
|
||||
Timber.v("Handle sync response")
|
||||
|
||||
if (syncResponse.rooms != null) {
|
||||
// joined rooms events
|
||||
roomSyncHandler.handleJoinedRooms(syncResponse.rooms.join)
|
||||
}
|
||||
|
||||
/*
|
||||
val isInitialSync = null == fromToken
|
||||
var isEmptyResponse = true
|
||||
|
||||
@ -50,21 +50,8 @@ class SyncResponseHandler(private val dataHandler: MXDataHandler) {
|
||||
manageAccountData(syncResponse.accountData, isInitialSync)
|
||||
}
|
||||
|
||||
// sanity check
|
||||
|
||||
if (syncResponse.rooms != null) {
|
||||
// joined rooms events
|
||||
if (syncResponse.rooms.join.isNotEmpty()) {
|
||||
val roomIds = syncResponse.rooms.join.keys
|
||||
// Handle first joined rooms
|
||||
for (roomId in roomIds) {
|
||||
if (null != leftRoomsStore.getRoom(roomId)) {
|
||||
leftRoomsStore.deleteRoom(roomId)
|
||||
}
|
||||
// TODO handle joined room
|
||||
//getRoom(roomId).handleJoinedRoomSync(syncResponse.rooms.join[roomId], isInitialSync)
|
||||
}
|
||||
isEmptyResponse = false
|
||||
}
|
||||
|
||||
// invited room management
|
||||
if (syncResponse.rooms.invite.isNotEmpty()) {
|
||||
@ -117,131 +104,137 @@ class SyncResponseHandler(private val dataHandler: MXDataHandler) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isEmptyResponse = false
|
||||
|
||||
if (hasChanged) {
|
||||
// Update account data to add new direct chat room(s)
|
||||
/* mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES,
|
||||
updatedDirectChatRoomsDict, object : ApiCallback<Void> {
|
||||
override fun onSuccess(info: Void) {
|
||||
}
|
||||
|
||||
override fun onNetworkError(e: Exception) {
|
||||
// TODO: we should try again.
|
||||
}
|
||||
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
}
|
||||
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
}
|
||||
})*/
|
||||
}
|
||||
}
|
||||
|
||||
// left room management
|
||||
// it should be done at the end but it seems there is a server issue
|
||||
// when inviting after leaving a room, the room is defined in the both leave & invite rooms list.
|
||||
if (syncResponse.rooms.leave.isNotEmpty()) {
|
||||
val roomIds = syncResponse.rooms.leave.keys
|
||||
for (roomId in roomIds) {
|
||||
// RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId);
|
||||
isEmptyResponse = false
|
||||
|
||||
// Presently we remove the existing room from the rooms list.
|
||||
// FIXME SYNC V2 Archive/Display the left rooms!
|
||||
// For that create 'handleArchivedRoomSync' method
|
||||
if (hasChanged) {
|
||||
// Update account data to add new direct chat room(s)
|
||||
/* mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES,
|
||||
updatedDirectChatRoomsDict, object : ApiCallback<Void> {
|
||||
override fun onSuccess(info: Void) {
|
||||
}
|
||||
|
||||
var membership = RoomMember.MEMBERSHIP_LEAVE
|
||||
val room = getRoom(roomId)
|
||||
override fun onNetworkError(e: Exception) {
|
||||
// TODO: we should try again.
|
||||
}
|
||||
|
||||
// Retrieve existing room
|
||||
// The room will then be able to notify its listeners.
|
||||
// TODO handle
|
||||
// room.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)
|
||||
override fun onMatrixError(e: MatrixError) {
|
||||
}
|
||||
|
||||
val member = room.getMember(dataHandler.userId)
|
||||
if (null != member) {
|
||||
membership = member.membership
|
||||
}
|
||||
if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) {
|
||||
// ensure that the room data are properly deleted
|
||||
store.deleteRoom(roomId)
|
||||
dataHandler.onLeaveRoom(roomId)
|
||||
} else {
|
||||
dataHandler.onRoomKick(roomId)
|
||||
}
|
||||
// don't add to the left rooms if the user has been kicked / banned
|
||||
if (areLeftRoomsSynced && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) {
|
||||
val leftRoom = getRoom(leftRoomsStore, roomId, true)
|
||||
//Todo handle
|
||||
//leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)
|
||||
}
|
||||
}
|
||||
isEmptyResponse = false
|
||||
override fun onUnexpectedError(e: Exception) {
|
||||
}
|
||||
})*/
|
||||
}
|
||||
}
|
||||
|
||||
// groups
|
||||
if (null != syncResponse.groups) {
|
||||
// left room management
|
||||
// it should be done at the end but it seems there is a server issue
|
||||
// when inviting after leaving a room, the room is defined in the both leave & invite rooms list.
|
||||
if (syncResponse.rooms.leave.isNotEmpty()) {
|
||||
val roomIds = syncResponse.rooms.leave.keys
|
||||
for (roomId in roomIds) {
|
||||
// RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId);
|
||||
|
||||
// Presently we remove the existing room from the rooms list.
|
||||
// FIXME SYNC V2 Archive/Display the left rooms!
|
||||
// For that create 'handleArchivedRoomSync' method
|
||||
|
||||
var membership = RoomMember.MEMBERSHIP_LEAVE
|
||||
val room = getRoom(roomId)
|
||||
|
||||
// Retrieve existing room
|
||||
// The room will then be able to notify its listeners.
|
||||
// TODO handle
|
||||
// room.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)
|
||||
|
||||
val member = room.getMember(dataHandler.userId)
|
||||
if (null != member) {
|
||||
membership = member.membership
|
||||
}
|
||||
if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) {
|
||||
// ensure that the room data are properly deleted
|
||||
store.deleteRoom(roomId)
|
||||
dataHandler.onLeaveRoom(roomId)
|
||||
} else {
|
||||
dataHandler.onRoomKick(roomId)
|
||||
}
|
||||
// don't add to the left rooms if the user has been kicked / banned
|
||||
if (areLeftRoomsSynced && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) {
|
||||
val leftRoom = getRoom(leftRoomsStore, roomId, true)
|
||||
//Todo handle
|
||||
//leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave[roomId], isInitialSync)
|
||||
}
|
||||
}
|
||||
isEmptyResponse = false
|
||||
}
|
||||
}
|
||||
|
||||
// groups
|
||||
if (null != syncResponse.groups)
|
||||
{
|
||||
// Handle invited groups
|
||||
if (null != syncResponse.groups.invite && !syncResponse.groups.invite.isEmpty()) {
|
||||
// Handle invited groups
|
||||
if (null != syncResponse.groups.invite && !syncResponse.groups.invite.isEmpty()) {
|
||||
// Handle invited groups
|
||||
for (groupId in syncResponse.groups.invite.keys) {
|
||||
val invitedGroupSync = syncResponse.groups.invite[groupId]
|
||||
dataHandler.groupsManager.onNewGroupInvitation(groupId, invitedGroupSync?.profile, invitedGroupSync?.inviter, !isInitialSync)
|
||||
}
|
||||
for (groupId in syncResponse.groups.invite.keys) {
|
||||
val invitedGroupSync = syncResponse.groups.invite[groupId]
|
||||
dataHandler.groupsManager.onNewGroupInvitation(groupId, invitedGroupSync?.profile, invitedGroupSync?.inviter, !isInitialSync)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle joined groups
|
||||
if (null != syncResponse.groups.join && !syncResponse.groups.join.isEmpty()) {
|
||||
for (groupId in syncResponse.groups.join.keys) {
|
||||
dataHandler.groupsManager.onJoinGroup(groupId, !isInitialSync)
|
||||
}
|
||||
}
|
||||
// Handle left groups
|
||||
if (null != syncResponse.groups.leave && !syncResponse.groups.leave.isEmpty()) {
|
||||
// Handle joined groups
|
||||
if (null != syncResponse.groups.join && !syncResponse.groups.join.isEmpty()) {
|
||||
for (groupId in syncResponse.groups.join.keys) {
|
||||
dataHandler.groupsManager.onJoinGroup(groupId, !isInitialSync)
|
||||
}
|
||||
}
|
||||
// Handle left groups
|
||||
if (null != syncResponse.groups.leave && !syncResponse.groups.leave.isEmpty()) {
|
||||
// Handle joined groups
|
||||
for (groupId in syncResponse.groups.leave.keys) {
|
||||
dataHandler.groupsManager.onLeaveGroup(groupId, !isInitialSync)
|
||||
}
|
||||
for (groupId in syncResponse.groups.leave.keys) {
|
||||
dataHandler.groupsManager.onLeaveGroup(groupId, !isInitialSync)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle presence of other users
|
||||
if (syncResponse.presence?.events != null) {
|
||||
for (presenceEvent in syncResponse.presence.events) {
|
||||
handlePresenceEvent(presenceEvent)
|
||||
}
|
||||
}
|
||||
dataHandler.crypto?.onSyncCompleted(syncResponse, fromToken, isCatchingUp)
|
||||
if (!isEmptyResponse) {
|
||||
store.eventStreamToken = syncResponse.nextBatch
|
||||
store.commit()
|
||||
// Handle presence of other users
|
||||
if (syncResponse.presence?.events != null)
|
||||
{
|
||||
for (presenceEvent in syncResponse.presence.events) {
|
||||
handlePresenceEvent(presenceEvent)
|
||||
}
|
||||
}
|
||||
dataHandler.crypto?.onSyncCompleted(syncResponse, fromToken, isCatchingUp)
|
||||
if (!isEmptyResponse)
|
||||
{
|
||||
store.eventStreamToken = syncResponse.nextBatch
|
||||
store.commit()
|
||||
}
|
||||
|
||||
if (isInitialSync) {
|
||||
if (!isCatchingUp) {
|
||||
dataHandler.startCrypto(true)
|
||||
} else {
|
||||
// the events thread sends a dummy initial sync event
|
||||
// when the application is restarted.
|
||||
isStartingCryptoWithInitialSync = !isEmptyResponse
|
||||
}
|
||||
|
||||
dataHandler.onInitialSyncComplete(syncResponse?.nextBatch)
|
||||
if (isInitialSync)
|
||||
{
|
||||
if (!isCatchingUp) {
|
||||
dataHandler.startCrypto(true)
|
||||
} else {
|
||||
|
||||
if (!isCatchingUp) {
|
||||
dataHandler.startCrypto(isStartingCryptoWithInitialSync)
|
||||
}
|
||||
|
||||
dataHandler.onLiveEventsChunkProcessed(fromToken, syncResponse.nextBatch)
|
||||
dataHandler.callsManager?.checkPendingIncomingCalls()
|
||||
|
||||
// the events thread sends a dummy initial sync event
|
||||
// when the application is restarted.
|
||||
isStartingCryptoWithInitialSync = !isEmptyResponse
|
||||
}
|
||||
|
||||
dataHandler.onInitialSyncComplete(syncResponse?.nextBatch)
|
||||
} else
|
||||
{
|
||||
|
||||
if (!isCatchingUp) {
|
||||
dataHandler.startCrypto(isStartingCryptoWithInitialSync)
|
||||
}
|
||||
|
||||
dataHandler.onLiveEventsChunkProcessed(fromToken, syncResponse.nextBatch)
|
||||
dataHandler.callsManager?.checkPendingIncomingCalls()
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun manageAccountData(accountData: Map<String, Any>, isInitialSync: Boolean) {
|
||||
|
@ -1,21 +1,7 @@
|
||||
/*
|
||||
* Copyright 2016 OpenMarket Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.events.sync.data
|
||||
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.events.Event
|
||||
|
||||
@ -26,4 +12,5 @@ data class RoomSyncState(
|
||||
/**
|
||||
* List of state events (array of Event). The resulting state corresponds to the *start* of the timeline.
|
||||
*/
|
||||
val events: List<Event>? = null)
|
||||
@Json(name = "events") val events: List<Event> = emptyList()
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ data class RoomSyncTimeline(
|
||||
/**
|
||||
* List of events (array of Event).
|
||||
*/
|
||||
val events: List<Event>? = null,
|
||||
val events: List<Event> = emptyList(),
|
||||
|
||||
/**
|
||||
* Boolean which tells whether there are more events on the server
|
||||
|
Reference in New Issue
Block a user