Skip to content
Snippets Groups Projects
sync.rs 38.7 KiB
Newer Older
  • Learn to ignore specific revisions
  •     for user_id in left_encrypted_users {
    
            let still_share_encrypted_room = services()
    
    Timo Kösters's avatar
    Timo Kösters committed
                .user
    
                .get_shared_rooms(vec![sender_user.clone(), user_id.clone()])?
    
                .filter_map(|r| r.ok())
                .filter_map(|other_room_id| {
                    Some(
    
    Timo Kösters's avatar
    Timo Kösters committed
                        services()
                            .rooms
                            .state_accessor
                            .room_state_get(&other_room_id, &StateEventType::RoomEncryption, "")
    
                            .ok()?
                            .is_some(),
                    )
                })
    
                .all(|encrypted| !encrypted);
            // If the user doesn't share an encrypted room with the target anymore, we need to tell
            // them
    
            if still_share_encrypted_room {
    
                device_list_left.insert(user_id);
            }
        }
    
    
        // Remove all to-device events the device received *last time*
    
    Timo Kösters's avatar
    Timo Kösters committed
        services()
            .users
    
            .remove_to_device_events(&sender_user, &sender_device, since)?;
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
        let response = sync_events::v3::Response {
    
            next_batch: next_batch_string,
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
            rooms: Rooms {
    
                leave: left_rooms,
                join: joined_rooms,
                invite: invited_rooms,
    
                knock: BTreeMap::new(), // TODO
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
            presence: Presence {
    
                events: presence_updates
    
    Nyaaori's avatar
    Nyaaori committed
                    .into_values()
                    .map(|v| Raw::new(&v).expect("PresenceEvent always serializes successfully"))
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
            account_data: GlobalAccountData {
    
                events: services()
    
                    .account_data
    
                    .changes_since(None, &sender_user, since)?
    
                    .into_iter()
                    .filter_map(|(_, v)| {
                        serde_json::from_str(v.json().get())
                            .map_err(|_| Error::bad_database("Invalid account event in database."))
                            .ok()
                    })
    
    Jonas Platte's avatar
    Jonas Platte committed
                    .collect(),
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
            device_lists: DeviceLists {
    
                changed: device_list_updates.into_iter().collect(),
    
                left: device_list_left.into_iter().collect(),
    
    Timo Kösters's avatar
    Timo Kösters committed
            device_one_time_keys_count: services()
                .users
                .count_one_time_keys(&sender_user, &sender_device)?,
    
    Jonathan de Jong's avatar
    Jonathan de Jong committed
            to_device: ToDevice {
    
                events: services()
    
                    .users
                    .get_to_device_events(&sender_user, &sender_device)?,
    
    Jonas Platte's avatar
    Jonas Platte committed
            // Fallback keys are not yet supported
            device_unused_fallback_key_types: None,
    
        };
    
        // TODO: Retry the endpoint instead of returning (waiting for #118)
    
        if !body.full_state
    
            && response.rooms.is_empty()
            && response.presence.is_empty()
            && response.account_data.is_empty()
            && response.device_lists.is_empty()
            && response.to_device.is_empty()
        {
            // Hang a few seconds so requests are not spammed
            // Stop hanging if new info arrives
    
            let mut duration = body.timeout.unwrap_or_default();
    
            if duration.as_secs() > 30 {
                duration = Duration::from_secs(30);
            }
    
            let _ = tokio::time::timeout(duration, watcher).await;
    
            Ok((response, false))
        } else {
            Ok((response, since != next_batch)) // Only cache if we made progress
    
    
    fn share_encrypted_room(
    
        sender_user: &UserId,
    
        user_id: &UserId,
        ignore_room: &RoomId,
    
    ) -> Result<bool> {
    
        Ok(services()
    
    Timo Kösters's avatar
    Timo Kösters committed
            .user
    
    Jonas Platte's avatar
    Jonas Platte committed
            .get_shared_rooms(vec![sender_user.to_owned(), user_id.to_owned()])?
    
            .filter_map(|r| r.ok())
            .filter(|room_id| room_id != ignore_room)
            .filter_map(|other_room_id| {
                Some(
    
    Timo Kösters's avatar
    Timo Kösters committed
                    services()
                        .rooms
                        .state_accessor
    
    Timo Kösters's avatar
    Timo Kösters committed
                        .room_state_get(&other_room_id, &StateEventType::RoomEncryption, "")
    
                        .ok()?
                        .is_some(),
                )
            })
    
            .any(|encrypted| encrypted))