events are processed in wrong order, cannot chat anymore
When somebody kicks me from a room, but invites me shortly after without my client making a sync in between (because the chat app was closed), the leave and invite event is processed in the wrong order.
The result of /sync looks fine, the origin_server_ts of the invite is later than the one of the leave-Event. But when listening to client.on('event', ...), the invite Event comes first and the leave-Event second. This leads to a wrong state in the (persistent) store. Because of this, the app thinks the user is not in the room anymore and won't receive any new messages. The new state is "invite", but the user cannot accept the invittation, since it is not displayed.
Here is the result of /sync
/sync result
{
"next_batch": "s127655_2818331_4835_288127_209897_85_169_14999_0",
"presence": {
"events": [
{
"type": "m.presence",
"sender": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"content": {
"presence": "online",
"last_active_ago": 17,
"currently_active": true
}
}
]
},
"device_lists": {
"left": [
"@ctbot:chat.krz.tools"
]
},
"device_one_time_keys_count": {
"signed_curve25519": 0
},
"org.matrix.msc2732.device_unused_fallback_key_types": [],
"device_unused_fallback_key_types": [],
"rooms": {
"invite": {
"!sQgeWUrcqXvxvzkUqw:chat.krz.tools": {
"invite_state": {
"events": [
{
"type": "m.room.avatar",
"state_key": "",
"content": {
"url": ""
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.canonical_alias",
"state_key": "",
"content": {
"alias": "#ctg_4b1a00f5-7753-469f-bf95-6bb3b7c1414d:chat.krz.tools"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.create",
"state_key": "",
"content": {
"room_version": "9",
"creator": "@ctbot:chat.krz.tools"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.join_rules",
"state_key": "",
"content": {
"join_rule": "invite"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.name",
"state_key": "",
"content": {
"name": "Chattest"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.topic",
"state_key": "",
"content": {
"topic": "Gruppen-Chat einer Gruppe in testsilas.krz.tools"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.member",
"state_key": "@ctbot:chat.krz.tools",
"content": {
"membership": "join"
},
"sender": "@ctbot:chat.krz.tools"
},
{
"type": "m.room.member",
"sender": "@ctbot:chat.krz.tools",
"content": {
"membership": "invite",
"displayname": "Admin Admin"
},
"state_key": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"origin_server_ts": 1671178716243,
"unsigned": {
"replaces_state": "$LbfQGkLijKPasqYizadgfKnvLW_OKYK4izrqDLegduU",
"prev_content": {
"reason": null,
"membership": "leave"
},
"prev_sender": "@ctbot:chat.krz.tools",
"age": 41096
},
"event_id": "$elHhtOnT4Xy9mdNaHeJzVu5nVhKnRbjDEiFpN8BxBrc"
}
]
}
}
},
"leave": {
"!sQgeWUrcqXvxvzkUqw:chat.krz.tools": {
"timeline": {
"events": [
{
"type": "m.room.member",
"sender": "@ctbot:chat.krz.tools",
"content": {
"reason": null,
"membership": "leave"
},
"state_key": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"origin_server_ts": 1671178710797,
"unsigned": {
"replaces_state": "$pTOIJv3ViDwR7QyzOCLQatCwUyv5fQpNYSOaDIHXcdI",
"prev_content": {
"membership": "join",
"displayname": "Admin Admin"
},
"prev_sender": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"age": 46542
},
"event_id": "$LbfQGkLijKPasqYizadgfKnvLW_OKYK4izrqDLegduU"
}
],
"prev_batch": "s127652_2818310_4829_288126_209897_85_169_14999_0",
"limited": false
},
"state": {
"events": []
},
"account_data": {
"events": []
}
}
}
}
}
And the Events from client.on('event', ...):
Invite Event
{
"type": "m.room.member",
"sender": "@ctbot:chat.krz.tools",
"content": {
"membership": "invite",
"displayname": "Admin Admin"
},
"state_key": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"origin_server_ts": 1671178716243,
"unsigned": {
"replaces_state": "$LbfQGkLijKPasqYizadgfKnvLW_OKYK4izrqDLegduU",
"prev_content": {
"reason": null,
"membership": "leave"
},
"prev_sender": "@ctbot:chat.krz.tools",
"age": 41096
},
"event_id": "$elHhtOnT4Xy9mdNaHeJzVu5nVhKnRbjDEiFpN8BxBrc",
"room_id": "!sQgeWUrcqXvxvzkUqw:chat.krz.tools"
}
Leave Event
{
"type": "m.room.member",
"sender": "@ctbot:chat.krz.tools",
"content": {
"reason": null,
"membership": "leave",
"displayname": "Admin Admin"
},
"state_key": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"origin_server_ts": 1671178710797,
"unsigned": {
"replaces_state": "$pTOIJv3ViDwR7QyzOCLQatCwUyv5fQpNYSOaDIHXcdI",
"prev_content": {
"membership": "join",
"displayname": "Admin Admin"
},
"prev_sender": "@ct_a18c34c2-ea65-4359-956e-b4c237c96e47:chat.krz.tools",
"age": 46542
},
"event_id": "$LbfQGkLijKPasqYizadgfKnvLW_OKYK4izrqDLegduU",
"room_id": "!sQgeWUrcqXvxvzkUqw:chat.krz.tools"
}
Clients can't rely on origin_server_ts for ordering given that it may come from different servers in the distributed system with out of sync clocks. The issue here is a spec one, in no definition on how to handle a room being in both invite and leave sections of the sync response, ideally the server would only include it in the latest "correct" section.
@t3chguy thanks for the response. Is there a possibility to sync the member states for a given room? Then I could at least sync the states at the app start and have the right state again after a restart. At the moment because of persistent storage the app saves the wrong state
I'd suggest
client.stopClient();
client.store.deleteAllData();
then restart your client - this will not clear any e2ee
Is there a better way then to delete all data? If I delete all data on appstart, then I can use a memory store directly.