fix: send state in /sync, element displays wrong membership changes

next
Timo Kösters 2020-12-22 20:08:20 +01:00
parent 6606e41dde
commit f12fbca3c5
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
4 changed files with 55 additions and 18 deletions

View File

@ -686,7 +686,7 @@ async fn join_room_by_id_helper(
pdu_id.extend_from_slice(&count.to_be_bytes()); pdu_id.extend_from_slice(&count.to_be_bytes());
db.rooms.append_pdu( db.rooms.append_pdu(
&PduEvent::from(&**pdu), &PduEvent::from(&**pdu),
&utils::to_canonical_object(&**pdu).expect("Pdu is valid canonical object"), utils::to_canonical_object(&**pdu).expect("Pdu is valid canonical object"),
count, count,
pdu_id.clone().into(), pdu_id.clone().into(),
&db.globals, &db.globals,

View File

@ -91,15 +91,7 @@ pub async fn sync_events_route(
// They /sync response doesn't always return all messages, so we say the output is // They /sync response doesn't always return all messages, so we say the output is
// limited unless there are events in non_timeline_pdus // limited unless there are events in non_timeline_pdus
let mut limited = false; let limited = non_timeline_pdus.next().is_some();
let mut state_pdus = Vec::new();
for (_, pdu) in non_timeline_pdus {
if pdu.state_key.is_some() {
state_pdus.push(pdu);
}
limited = true;
}
// Database queries: // Database queries:
@ -342,7 +334,7 @@ pub async fn sync_events_route(
})?; })?;
let room_events = timeline_pdus let room_events = timeline_pdus
.into_iter() .iter()
.map(|(_, pdu)| pdu.to_sync_room_event()) .map(|(_, pdu)| pdu.to_sync_room_event())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -392,7 +384,6 @@ pub async fn sync_events_route(
prev_batch, prev_batch,
events: room_events, events: room_events,
}, },
// TODO: state before timeline
state: sync_events::State { state: sync_events::State {
events: if joined_since_last_sync { events: if joined_since_last_sync {
db.rooms db.rooms
@ -401,7 +392,26 @@ pub async fn sync_events_route(
.map(|(_, pdu)| pdu.to_sync_state_event()) .map(|(_, pdu)| pdu.to_sync_state_event())
.collect() .collect()
} else { } else {
Vec::new() match since_state {
None => Vec::new(),
Some(Some(since_state)) => current_state
.iter()
.filter(|(key, value)| {
since_state.get(key).map(|e| &e.event_id) != Some(&value.event_id)
})
.filter(|(_, value)| {
!timeline_pdus.iter().any(|(_, timeline_pdu)| {
timeline_pdu.kind == value.kind
&& timeline_pdu.state_key == value.state_key
})
})
.map(|(_, pdu)| pdu.to_sync_state_event())
.collect(),
Some(None) => current_state
.iter()
.map(|(_, pdu)| pdu.to_sync_state_event())
.collect(),
}
}, },
}, },
ephemeral: sync_events::Ephemeral { events: edus }, ephemeral: sync_events::Ephemeral { events: edus },

View File

@ -15,7 +15,7 @@ use ruma::{
}, },
EventType, EventType,
}, },
serde::{to_canonical_value, CanonicalJsonObject, Raw}, serde::{to_canonical_value, CanonicalJsonObject, CanonicalJsonValue, Raw},
EventId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId, EventId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId,
}; };
use sled::IVec; use sled::IVec;
@ -444,13 +444,40 @@ impl Rooms {
pub fn append_pdu( pub fn append_pdu(
&self, &self,
pdu: &PduEvent, pdu: &PduEvent,
pdu_json: &CanonicalJsonObject, mut pdu_json: CanonicalJsonObject,
count: u64, count: u64,
pdu_id: IVec, pdu_id: IVec,
globals: &super::globals::Globals, globals: &super::globals::Globals,
account_data: &super::account_data::AccountData, account_data: &super::account_data::AccountData,
admin: &super::admin::Admin, admin: &super::admin::Admin,
) -> Result<()> { ) -> Result<()> {
// Make unsigned fields correct. This is not properly documented in the spec, but state
// events need to have previous content in the unsigned field, so clients can easily
// interpret things like membership changes
if let Some(state_key) = &pdu.state_key {
if let CanonicalJsonValue::Object(unsigned) = pdu_json
.entry("unsigned".to_owned())
.or_insert_with(|| CanonicalJsonValue::Object(Default::default()))
{
if let Some(prev_state_hash) = self.pdu_state_hash(&pdu_id).unwrap() {
if let Some(prev_state) = self
.state_get(&pdu.room_id, &prev_state_hash, &pdu.kind, &state_key)
.unwrap()
{
unsigned.insert(
"prev_content".to_owned(),
CanonicalJsonValue::Object(
utils::to_canonical_object(prev_state.1.content)
.expect("event is valid, we just created it"),
),
);
}
}
} else {
error!("Invalid unsigned type in pdu.");
}
}
self.replace_pdu_leaves(&pdu.room_id, &pdu.event_id)?; self.replace_pdu_leaves(&pdu.room_id, &pdu.event_id)?;
// Mark as read first so the sending client doesn't get a notification even if appending // Mark as read first so the sending client doesn't get a notification even if appending
@ -460,7 +487,7 @@ impl Rooms {
self.pduid_pdu.insert( self.pduid_pdu.insert(
&pdu_id, &pdu_id,
&*serde_json::to_string(pdu_json) &*serde_json::to_string(&pdu_json)
.expect("CanonicalJsonObject is always a valid String"), .expect("CanonicalJsonObject is always a valid String"),
)?; )?;
@ -905,7 +932,7 @@ impl Rooms {
self.append_pdu( self.append_pdu(
&pdu, &pdu,
&pdu_json, pdu_json,
count, count,
pdu_id.clone().into(), pdu_id.clone().into(),
globals, globals,

View File

@ -494,7 +494,7 @@ pub async fn send_transaction_message_route<'a>(
db.rooms.append_pdu( db.rooms.append_pdu(
&pdu, &pdu,
&value, value,
count, count,
pdu_id.clone().into(), pdu_id.clone().into(),
&db.globals, &db.globals,