-
Notifications
You must be signed in to change notification settings - Fork 749
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes myroomnick changing Display Name #5618
Changes from 1 commit
bbfefbf
4c1e651
927eeb3
0200f48
6c1f6dc
7f64c62
25ca684
c650843
981d157
c1b1386
6c3c309
304e2f1
669af4d
4465525
de8cc07
b88eaf1
e80386b
f103d46
5d5a06b
2337b18
8964b55
5f949e9
dd988d0
8b80cf0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,27 +33,31 @@ internal class RoomMemberEventHandler @Inject constructor( | |
@UserId private val myUserId: String | ||
) { | ||
|
||
fun handle(realm: Realm, | ||
roomId: String, | ||
event: Event, | ||
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { | ||
fun handleInitialSync(realm: Realm, | ||
roomId: String, | ||
currentUserId: String, | ||
event: Event, | ||
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { | ||
if (event.type != EventType.STATE_ROOM_MEMBER) { | ||
return false | ||
} | ||
val roomMember = event.getFixedRoomMemberContent() ?: return false | ||
val userId = event.stateKey ?: return false | ||
val eventUserId = event.stateKey ?: return false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why those 2 lines of code have been reordered? I think it's better to restore the original order since it's faster to first check for the |
||
|
||
return handle(realm, roomId, userId, roomMember, event.resolvedPrevContent(), aggregator) | ||
return handleInitialSync(realm, roomId, currentUserId, eventUserId, roomMember, aggregator) | ||
} | ||
|
||
private fun handle(realm: Realm, | ||
roomId: String, | ||
userId: String, | ||
roomMember: RoomMemberContent, | ||
prevContent: Map<String, Any>?, | ||
aggregator: SyncResponsePostTreatmentAggregator?): Boolean { | ||
saveRoomMemberEntityLocally(realm, roomId, userId, roomMember) | ||
saveUserEntityLocallyIfNecessary(realm, userId, roomMember, prevContent) | ||
private fun handleInitialSync(realm: Realm, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having two methods with the same name, one public, one private is not ideal to me. |
||
roomId: String, | ||
currentUserId: String, | ||
eventUserId: String, | ||
roomMember: RoomMemberContent, | ||
aggregator: SyncResponsePostTreatmentAggregator?): Boolean { | ||
if (currentUserId != eventUserId) { | ||
saveRoomMemberEntityLocally(realm, roomId, eventUserId, roomMember) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always save RoomMember even if its our userId, but don't save User |
||
saveUserEntityLocallyIfNecessary(realm, eventUserId, roomMember) | ||
} | ||
|
||
updateDirectChatsIfNecessary(roomId, roomMember, aggregator) | ||
return true | ||
} | ||
|
@@ -72,15 +76,18 @@ internal class RoomMemberEventHandler @Inject constructor( | |
realm.insertOrUpdate(roomMemberEntity) | ||
} | ||
|
||
/** | ||
* Get the already existing presence state for a specific user & room in order NOT to be replaced in RoomMemberSummaryEntity | ||
* by NULL value. | ||
*/ | ||
private fun getExistingPresenceState(realm: Realm, roomId: String, userId: String): UserPresenceEntity? { | ||
return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity | ||
} | ||
|
||
private fun saveUserEntityLocallyIfNecessary(realm: Realm, | ||
userId: String, | ||
roomMember: RoomMemberContent, | ||
prevContent: Map<String, Any>?) { | ||
val previousDisplayName = prevContent?.get("displayname") | ||
val shouldLocallySaveUser = roomMember.membership.isActive() && | ||
(previousDisplayName == null || previousDisplayName == roomMember.displayName) | ||
|
||
if (shouldLocallySaveUser) { | ||
roomMember: RoomMemberContent) { | ||
if (roomMember.membership.isActive()) { | ||
saveUserLocally(realm, userId, roomMember) | ||
} | ||
} | ||
|
@@ -101,12 +108,38 @@ internal class RoomMemberEventHandler @Inject constructor( | |
} | ||
} | ||
|
||
/** | ||
* Get the already existing presence state for a specific user & room in order NOT to be replaced in RoomMemberSummaryEntity | ||
* by NULL value. | ||
*/ | ||
fun handleIncrementalSync(roomId: String, | ||
event: Event, | ||
aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { | ||
if (event.type != EventType.STATE_ROOM_MEMBER) { | ||
return false | ||
} | ||
val roomMember = event.getFixedRoomMemberContent() ?: return false | ||
val eventUserId = event.stateKey ?: return false | ||
|
||
private fun getExistingPresenceState(realm: Realm, roomId: String, userId: String): UserPresenceEntity? { | ||
return RoomMemberSummaryEntity.where(realm, roomId, userId).findFirst()?.userPresenceEntity | ||
return handleIncrementalSync(roomId, eventUserId, roomMember, event.resolvedPrevContent(), aggregator) | ||
} | ||
|
||
private fun handleIncrementalSync(roomId: String, | ||
eventUserId: String, | ||
roomMember: RoomMemberContent, | ||
prevContent: Map<String, Any>?, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be of type |
||
aggregator: SyncResponsePostTreatmentAggregator?): Boolean { | ||
val previousDisplayName = prevContent?.get("displayname") | ||
val previousAvatar = prevContent?.get("avatar_url") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add |
||
|
||
if (previousDisplayName.isDifferentFrom(roomMember.displayName) || | ||
previousAvatar.isDifferentFrom(roomMember.avatarUrl)) { | ||
aggregator?.usersToFetch?.add(eventUserId) | ||
} | ||
|
||
// At the end of the sync, fetch all the profiles from the aggregator | ||
updateDirectChatsIfNecessary(roomId, roomMember, aggregator) | ||
return true | ||
} | ||
|
||
private fun Any?.isDifferentFrom(value: Any?) = when { | ||
this == null || this == value -> false | ||
else -> true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,22 +16,30 @@ | |
|
||
package org.matrix.android.sdk.internal.session.sync.handler | ||
|
||
import com.zhuinden.monarchy.Monarchy | ||
import org.matrix.android.sdk.api.MatrixPatterns | ||
import org.matrix.android.sdk.api.session.profile.ProfileService | ||
import org.matrix.android.sdk.api.util.MatrixItem | ||
import org.matrix.android.sdk.internal.di.SessionDatabase | ||
import org.matrix.android.sdk.internal.session.sync.RoomSyncEphemeralTemporaryStore | ||
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator | ||
import org.matrix.android.sdk.internal.session.sync.model.accountdata.toMutable | ||
import org.matrix.android.sdk.internal.session.user.UserEntityFactory | ||
import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper | ||
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask | ||
import javax.inject.Inject | ||
|
||
internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( | ||
private val directChatsHelper: DirectChatsHelper, | ||
private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore, | ||
private val updateUserAccountDataTask: UpdateUserAccountDataTask | ||
private val updateUserAccountDataTask: UpdateUserAccountDataTask, | ||
private val profileService: ProfileService, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should not inject Service in SDK classes. Services are meant to be used by the client app. |
||
@SessionDatabase private val monarchy: Monarchy, | ||
) { | ||
suspend fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) { | ||
cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete) | ||
updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck) | ||
suspend fun handle(aggregator: SyncResponsePostTreatmentAggregator) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for having renamed this parameter which was quite typoed :) |
||
cleanupEphemeralFiles(aggregator.ephemeralFilesToDelete) | ||
updateDirectUserIds(aggregator.directChatsToCheck) | ||
fetchAndUpdateUsers(aggregator.usersToFetch) | ||
} | ||
|
||
private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List<String>) { | ||
|
@@ -68,4 +76,27 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( | |
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats)) | ||
} | ||
} | ||
|
||
private suspend fun fetchAndUpdateUsers(usersToFetch: MutableList<String>) { | ||
val userProfiles = fetchUsers(usersToFetch) | ||
userProfiles.forEach { saveUserLocally(monarchy, it) } | ||
usersToFetch.clear() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably not necessary to clear the list. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't though, wouldn't we keep fetching the same users even when we don't need to fetch them anymore? I think it could increase bandwith and performance usage the longer the app is kept on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope. A brand new There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahhh this wasn't clear to me at first. Changes pushed |
||
} | ||
|
||
private fun saveUserLocally(monarchy: Monarchy, userItem: MatrixItem.UserItem) { | ||
val userEntity = UserEntityFactory.create(userItem) | ||
monarchy.doWithRealm { | ||
it.insertOrUpdate(userEntity) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's good to split code into several smaller methods, but it's maybe harder to read in this particular case. What about replacing those 3 methods with a single one: private suspend fun fetchAndUpdateUsers(usersToFetch: List<String>) {
usersToFetch
.map { userId ->
val profileJson = profileService.getProfile(userId)
User.fromJson(userId, profileJson)
}
.map { user -> UserEntityFactory.create(user) }
.let { userEntities ->
monarchy.doWithRealm {
it.insertOrUpdate(userEntities)
}
}
} Also has the advantage to do on single Realm transaction instead of N transactions with your code. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally prefer it split. The advantage is you can get the whole context of the action from the first method, and only if you're concerned about the details of the implementation do you need to read through the bottom methods. I agree with making it a single Realm transaction though. I'll push changes to make this happen There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your latest implementation is better, thanks. Maybe just skip the transaction if the list is empty, which will be the case nearly all the time, or in case of error when fetching the profile. |
||
|
||
private suspend fun fetchUsers(usersToFetch: MutableList<String>) = usersToFetch.map { | ||
val profileJson = profileService.getProfile(it) | ||
|
||
MatrixItem.UserItem( | ||
id = it, | ||
displayName = profileJson[ProfileService.DISPLAY_NAME_KEY] as? String, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a method to reuse these json keys as it's used in several places |
||
avatarUrl = profileJson[ProfileService.AVATAR_URL_KEY] as? String | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,7 +206,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
insertType: EventInsertType, | ||
syncLocalTimestampMillis: Long, | ||
aggregator: SyncResponsePostTreatmentAggregator): RoomEntity { | ||
Timber.v("Handle join sync for room $roomId") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment is useful when debugging sync request. Can you restore it please? |
||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC | ||
|
||
val ephemeralResult = (roomSync.ephemeral as? LazyRoomSyncEphemeral.Parsed) | ||
?._roomSyncEphemeral | ||
|
@@ -241,7 +241,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
} | ||
// Give info to crypto module | ||
cryptoService.onStateEvent(roomId, event) | ||
roomMemberEventHandler.handle(realm, roomId, event, aggregator) | ||
if (isInitialSync) { | ||
roomMemberEventHandler.handleInitialSync(realm, roomId, userId, event, aggregator) | ||
} else { | ||
roomMemberEventHandler.handleIncrementalSync(roomId, event, aggregator) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code, and the similar occurence, will be much simpler with an extra parameter (see my other remark) |
||
} | ||
} | ||
if (roomSync.timeline?.events?.isNotEmpty() == true) { | ||
|
@@ -282,7 +286,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
roomSync: InvitedRoomSync, | ||
insertType: EventInsertType, | ||
syncLocalTimestampMillis: Long): RoomEntity { | ||
Timber.v("Handle invited sync for room $roomId") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I miss that at the previous review. Same remark: |
||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC | ||
val roomEntity = RoomEntity.getOrCreate(realm, roomId) | ||
roomEntity.membership = Membership.INVITE | ||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { | ||
|
@@ -296,7 +300,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
eventId = eventEntity.eventId | ||
root = eventEntity | ||
} | ||
roomMemberEventHandler.handle(realm, roomId, event) | ||
if (isInitialSync) { | ||
roomMemberEventHandler.handleInitialSync(realm, roomId, userId, event) | ||
} else { | ||
roomMemberEventHandler.handleIncrementalSync(roomId, event) | ||
} | ||
} | ||
} | ||
val inviterEvent = roomSync.inviteState?.events?.lastOrNull { | ||
|
@@ -312,6 +320,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
roomSync: RoomSync, | ||
insertType: EventInsertType, | ||
syncLocalTimestampMillis: Long): RoomEntity { | ||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC | ||
val roomEntity = RoomEntity.getOrCreate(realm, roomId) | ||
for (event in roomSync.state?.events.orEmpty()) { | ||
if (event.eventId == null || event.stateKey == null || event.type == null) { | ||
|
@@ -323,7 +332,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
eventId = event.eventId | ||
root = eventEntity | ||
} | ||
roomMemberEventHandler.handle(realm, roomId, event) | ||
if (isInitialSync) { | ||
roomMemberEventHandler.handleInitialSync(realm, roomId, userId, event) | ||
} else { | ||
roomMemberEventHandler.handleIncrementalSync(roomId, event) | ||
} | ||
} | ||
for (event in roomSync.timeline?.events.orEmpty()) { | ||
if (event.eventId == null || event.senderId == null || event.type == null) { | ||
|
@@ -337,7 +350,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
root = eventEntity | ||
} | ||
if (event.type == EventType.STATE_ROOM_MEMBER) { | ||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event) | ||
if (isInitialSync) { | ||
roomMemberEventHandler.handleInitialSync(realm, roomEntity.roomId, userId, event) | ||
} else { | ||
roomMemberEventHandler.handleIncrementalSync(roomEntity.roomId, event) | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -381,11 +398,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
continue | ||
} | ||
|
||
eventIds.add(event.eventId) | ||
liveEventService.get().dispatchLiveEventReceived(event, roomId, insertType == EventInsertType.INITIAL_SYNC) | ||
|
||
val isInitialSync = insertType == EventInsertType.INITIAL_SYNC | ||
|
||
eventIds.add(event.eventId) | ||
liveEventService.get().dispatchLiveEventReceived(event, roomId, isInitialSync) | ||
|
||
if (event.isEncrypted() && !isInitialSync) { | ||
runBlocking { | ||
decryptIfNeeded(event, roomId) | ||
|
@@ -405,7 +422,11 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle | |
} | ||
if (event.type == EventType.STATE_ROOM_MEMBER) { | ||
roomMemberContentsByUser[event.stateKey] = event.getFixedRoomMemberContent() | ||
roomMemberEventHandler.handle(realm, roomEntity.roomId, event, aggregator) | ||
if (isInitialSync) { | ||
roomMemberEventHandler.handleInitialSync(realm, roomEntity.roomId, userId, event, aggregator) | ||
} else { | ||
roomMemberEventHandler.handleIncrementalSync(roomEntity.roomId, event, aggregator) | ||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already injected on constructor (myUserId)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👁️👄👁️