atagen

macltok

public
Star0
Watch0
960ac07210797dcdf9149ef8465c1ccd46dafbda
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: src/normalise/room.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use futures_util::{StreamExt, stream};
31ce2453c82fatagen2026-09-24 13:07 UTC2
use matrix_sdk::{
31ce2453c82fatagen2026-09-24 13:07 UTC3
    Client, Room, RoomState,
31ce2453c82fatagen2026-09-24 13:07 UTC4
    deserialized_responses::SyncOrStrippedState,
31ce2453c82fatagen2026-09-24 13:07 UTC5
    latest_events::LatestEventValue,
31ce2453c82fatagen2026-09-24 13:07 UTC6
    ruma::events::{
31ce2453c82fatagen2026-09-24 13:07 UTC7
        AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncStateEvent,
31ce2453c82fatagen2026-09-24 13:07 UTC8
        space::child::SpaceChildEventContent,
31ce2453c82fatagen2026-09-24 13:07 UTC9
    },
31ce2453c82fatagen2026-09-24 13:07 UTC10
};
31ce2453c82fatagen2026-09-24 13:07 UTC11
use matrix_sdk_ui::spaces::{SpaceRoom, SpaceService};
31ce2453c82fatagen2026-09-24 13:07 UTC12
use ruma::OwnedRoomId;
96fdf90aacd6atagen2026-09-08 08:24 UTC13
31ce2453c82fatagen2026-09-24 13:07 UTC14
use crate::{
31ce2453c82fatagen2026-09-24 13:07 UTC15
    LatestEvent, RoomHero, RoomMembership, RoomNotificationMode, RoomSummary, SendState, SpaceChild,
31ce2453c82fatagen2026-09-24 13:07 UTC16
};
96fdf90aacd6atagen2026-09-08 08:24 UTC17
31ce2453c82fatagen2026-09-24 13:07 UTC18
pub(crate) async fn room_summaries(client: &Client, spaces: &SpaceService) -> Vec<RoomSummary> {
96fdf90aacd6atagen2026-09-08 08:24 UTC19
    let mut summaries = stream::iter(client.rooms())
31ce2453c82fatagen2026-09-24 13:07 UTC20
        .map(|room| async move { room_summary(&room, spaces).await })
96fdf90aacd6atagen2026-09-08 08:24 UTC21
        .buffer_unordered(16)
96fdf90aacd6atagen2026-09-08 08:24 UTC22
        .collect::<Vec<_>>()
96fdf90aacd6atagen2026-09-08 08:24 UTC23
        .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC24
    summaries.sort_by(|left, right| {
96fdf90aacd6atagen2026-09-08 08:24 UTC25
        right
96fdf90aacd6atagen2026-09-08 08:24 UTC26
            .latest_event_timestamp_ms
96fdf90aacd6atagen2026-09-08 08:24 UTC27
            .cmp(&left.latest_event_timestamp_ms)
96fdf90aacd6atagen2026-09-08 08:24 UTC28
            .then_with(|| left.name.to_lowercase().cmp(&right.name.to_lowercase()))
96fdf90aacd6atagen2026-09-08 08:24 UTC29
            .then_with(|| left.room_id.cmp(&right.room_id))
96fdf90aacd6atagen2026-09-08 08:24 UTC30
    });
96fdf90aacd6atagen2026-09-08 08:24 UTC31
    summaries
96fdf90aacd6atagen2026-09-08 08:24 UTC32
}
96fdf90aacd6atagen2026-09-08 08:24 UTC33
31ce2453c82fatagen2026-09-24 13:07 UTC34
async fn room_summary(room: &Room, spaces: &SpaceService) -> RoomSummary {
96fdf90aacd6atagen2026-09-08 08:24 UTC35
    let name = room
96fdf90aacd6atagen2026-09-08 08:24 UTC36
        .display_name()
96fdf90aacd6atagen2026-09-08 08:24 UTC37
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC38
        .map(|name| name.to_string())
96fdf90aacd6atagen2026-09-08 08:24 UTC39
        .unwrap_or_else(|_| room.room_id().to_string());
96fdf90aacd6atagen2026-09-08 08:24 UTC40
    let custom_notification_mode = room.user_defined_notification_mode().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC41
    let effective_notification_mode = match custom_notification_mode {
96fdf90aacd6atagen2026-09-08 08:24 UTC42
        Some(mode) => Some(mode),
96fdf90aacd6atagen2026-09-08 08:24 UTC43
        None => room.notification_mode().await,
96fdf90aacd6atagen2026-09-08 08:24 UTC44
    };
31ce2453c82fatagen2026-09-24 13:07 UTC45
    let inviter = match room.state() {
31ce2453c82fatagen2026-09-24 13:07 UTC46
        RoomState::Invited => room
31ce2453c82fatagen2026-09-24 13:07 UTC47
            .invite_details()
31ce2453c82fatagen2026-09-24 13:07 UTC48
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC49
            .ok()
31ce2453c82fatagen2026-09-24 13:07 UTC50
            .map(|invite| invite.inviter_id),
31ce2453c82fatagen2026-09-24 13:07 UTC51
        _ => None,
31ce2453c82fatagen2026-09-24 13:07 UTC52
    };
31ce2453c82fatagen2026-09-24 13:07 UTC53
    let children = if room.is_space() {
31ce2453c82fatagen2026-09-24 13:07 UTC54
        space_children(room).await
31ce2453c82fatagen2026-09-24 13:07 UTC55
    } else {
31ce2453c82fatagen2026-09-24 13:07 UTC56
        Vec::new()
31ce2453c82fatagen2026-09-24 13:07 UTC57
    };
96fdf90aacd6atagen2026-09-08 08:24 UTC58
    RoomSummary {
96fdf90aacd6atagen2026-09-08 08:24 UTC59
        room_id: room.room_id().to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC60
        name,
31ce2453c82fatagen2026-09-24 13:07 UTC61
        membership: membership(room.state()),
96fdf90aacd6atagen2026-09-08 08:24 UTC62
        unread_messages: room.num_unread_messages(),
96fdf90aacd6atagen2026-09-08 08:24 UTC63
        unread_mentions: room.num_unread_mentions(),
96fdf90aacd6atagen2026-09-08 08:24 UTC64
        encrypted: room.encryption_state().is_encrypted(),
96fdf90aacd6atagen2026-09-08 08:24 UTC65
        space: room.is_space(),
96fdf90aacd6atagen2026-09-08 08:24 UTC66
        direct: room.is_direct().await.unwrap_or(false),
96fdf90aacd6atagen2026-09-08 08:24 UTC67
        favourite: room.is_favourite(),
96fdf90aacd6atagen2026-09-08 08:24 UTC68
        low_priority: room.is_low_priority(),
96fdf90aacd6atagen2026-09-08 08:24 UTC69
        avatar: room.avatar_url(),
96fdf90aacd6atagen2026-09-08 08:24 UTC70
        latest_event_timestamp_ms: room
96fdf90aacd6atagen2026-09-08 08:24 UTC71
            .latest_event_timestamp()
96fdf90aacd6atagen2026-09-08 08:24 UTC72
            .map(|value| value.get().into()),
31ce2453c82fatagen2026-09-24 13:07 UTC73
        latest_event: latest_event(room),
96fdf90aacd6atagen2026-09-08 08:24 UTC74
        notification_mode: effective_notification_mode.map(notification_mode),
96fdf90aacd6atagen2026-09-08 08:24 UTC75
        notification_mode_custom: custom_notification_mode.is_some(),
31ce2453c82fatagen2026-09-24 13:07 UTC76
        topic: room.topic(),
31ce2453c82fatagen2026-09-24 13:07 UTC77
        canonical_alias: room.canonical_alias(),
31ce2453c82fatagen2026-09-24 13:07 UTC78
        joined_members: room.joined_members_count(),
31ce2453c82fatagen2026-09-24 13:07 UTC79
        invited_members: room.invited_members_count(),
31ce2453c82fatagen2026-09-24 13:07 UTC80
        heroes: room
31ce2453c82fatagen2026-09-24 13:07 UTC81
            .heroes()
31ce2453c82fatagen2026-09-24 13:07 UTC82
            .into_iter()
31ce2453c82fatagen2026-09-24 13:07 UTC83
            .map(|hero| RoomHero {
31ce2453c82fatagen2026-09-24 13:07 UTC84
                user_id: hero.user_id,
31ce2453c82fatagen2026-09-24 13:07 UTC85
                display_name: hero.display_name,
31ce2453c82fatagen2026-09-24 13:07 UTC86
                avatar: hero.avatar_url,
31ce2453c82fatagen2026-09-24 13:07 UTC87
            })
31ce2453c82fatagen2026-09-24 13:07 UTC88
            .collect(),
31ce2453c82fatagen2026-09-24 13:07 UTC89
        successor: room.successor_room().map(|successor| successor.room_id),
31ce2453c82fatagen2026-09-24 13:07 UTC90
        inviter,
31ce2453c82fatagen2026-09-24 13:07 UTC91
        parent_spaces: spaces
31ce2453c82fatagen2026-09-24 13:07 UTC92
            .joined_parents_of_child(room.room_id())
31ce2453c82fatagen2026-09-24 13:07 UTC93
            .await
31ce2453c82fatagen2026-09-24 13:07 UTC94
            .into_iter()
31ce2453c82fatagen2026-09-24 13:07 UTC95
            .map(|parent| parent.room_id)
31ce2453c82fatagen2026-09-24 13:07 UTC96
            .collect(),
31ce2453c82fatagen2026-09-24 13:07 UTC97
        children,
31ce2453c82fatagen2026-09-24 13:07 UTC98
    }
31ce2453c82fatagen2026-09-24 13:07 UTC99
}
31ce2453c82fatagen2026-09-24 13:07 UTC100
31ce2453c82fatagen2026-09-24 13:07 UTC101
const fn membership(state: RoomState) -> RoomMembership {
31ce2453c82fatagen2026-09-24 13:07 UTC102
    match state {
31ce2453c82fatagen2026-09-24 13:07 UTC103
        RoomState::Joined => RoomMembership::Joined,
31ce2453c82fatagen2026-09-24 13:07 UTC104
        RoomState::Invited => RoomMembership::Invited,
31ce2453c82fatagen2026-09-24 13:07 UTC105
        RoomState::Left => RoomMembership::Left,
31ce2453c82fatagen2026-09-24 13:07 UTC106
        RoomState::Knocked => RoomMembership::Knocked,
31ce2453c82fatagen2026-09-24 13:07 UTC107
        RoomState::Banned => RoomMembership::Banned,
31ce2453c82fatagen2026-09-24 13:07 UTC108
    }
31ce2453c82fatagen2026-09-24 13:07 UTC109
}
31ce2453c82fatagen2026-09-24 13:07 UTC110
31ce2453c82fatagen2026-09-24 13:07 UTC111
/// what the space itself lists, straight from local state. redacted children don't count
31ce2453c82fatagen2026-09-24 13:07 UTC112
async fn space_children(room: &Room) -> Vec<OwnedRoomId> {
31ce2453c82fatagen2026-09-24 13:07 UTC113
    let Ok(events) = room
31ce2453c82fatagen2026-09-24 13:07 UTC114
        .get_state_events_static::<SpaceChildEventContent>()
31ce2453c82fatagen2026-09-24 13:07 UTC115
        .await
31ce2453c82fatagen2026-09-24 13:07 UTC116
    else {
31ce2453c82fatagen2026-09-24 13:07 UTC117
        return Vec::new();
31ce2453c82fatagen2026-09-24 13:07 UTC118
    };
31ce2453c82fatagen2026-09-24 13:07 UTC119
    events
31ce2453c82fatagen2026-09-24 13:07 UTC120
        .into_iter()
31ce2453c82fatagen2026-09-24 13:07 UTC121
        .filter_map(|event| match event.deserialize().ok()? {
31ce2453c82fatagen2026-09-24 13:07 UTC122
            SyncOrStrippedState::Sync(SyncStateEvent::Original(event)) => Some(event.state_key),
31ce2453c82fatagen2026-09-24 13:07 UTC123
            SyncOrStrippedState::Stripped(event) => Some(event.state_key),
31ce2453c82fatagen2026-09-24 13:07 UTC124
            SyncOrStrippedState::Sync(SyncStateEvent::Redacted(_)) => None,
31ce2453c82fatagen2026-09-24 13:07 UTC125
        })
31ce2453c82fatagen2026-09-24 13:07 UTC126
        .collect()
31ce2453c82fatagen2026-09-24 13:07 UTC127
}
31ce2453c82fatagen2026-09-24 13:07 UTC128
31ce2453c82fatagen2026-09-24 13:07 UTC129
fn latest_event(room: &Room) -> Option<LatestEvent> {
31ce2453c82fatagen2026-09-24 13:07 UTC130
    let (sender, body, timestamp, send_state) = match room.latest_event() {
31ce2453c82fatagen2026-09-24 13:07 UTC131
        LatestEventValue::None => return None,
31ce2453c82fatagen2026-09-24 13:07 UTC132
        LatestEventValue::Remote(event) => {
31ce2453c82fatagen2026-09-24 13:07 UTC133
            let body = match event.raw().deserialize() {
31ce2453c82fatagen2026-09-24 13:07 UTC134
                Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
31ce2453c82fatagen2026-09-24 13:07 UTC135
                    message,
31ce2453c82fatagen2026-09-24 13:07 UTC136
                ))) => message
31ce2453c82fatagen2026-09-24 13:07 UTC137
                    .as_original()
31ce2453c82fatagen2026-09-24 13:07 UTC138
                    .map(|message| message.content.body().to_owned()),
31ce2453c82fatagen2026-09-24 13:07 UTC139
                _ => None,
31ce2453c82fatagen2026-09-24 13:07 UTC140
            };
31ce2453c82fatagen2026-09-24 13:07 UTC141
            (event.sender(), body, event.timestamp(), SendState::Sent)
31ce2453c82fatagen2026-09-24 13:07 UTC142
        }
31ce2453c82fatagen2026-09-24 13:07 UTC143
        LatestEventValue::RemoteInvite {
31ce2453c82fatagen2026-09-24 13:07 UTC144
            timestamp, inviter, ..
31ce2453c82fatagen2026-09-24 13:07 UTC145
        } => (inviter, None, Some(timestamp), SendState::Sent),
31ce2453c82fatagen2026-09-24 13:07 UTC146
        LatestEventValue::LocalIsSending(local) => local_event(room, &local, SendState::Sending),
31ce2453c82fatagen2026-09-24 13:07 UTC147
        LatestEventValue::LocalHasBeenSent { value, .. } => {
31ce2453c82fatagen2026-09-24 13:07 UTC148
            local_event(room, &value, SendState::Sent)
31ce2453c82fatagen2026-09-24 13:07 UTC149
        }
31ce2453c82fatagen2026-09-24 13:07 UTC150
        LatestEventValue::LocalCannotBeSent(local) => {
31ce2453c82fatagen2026-09-24 13:07 UTC151
            local_event(room, &local, SendState::Failed { retriable: true })
31ce2453c82fatagen2026-09-24 13:07 UTC152
        }
31ce2453c82fatagen2026-09-24 13:07 UTC153
    };
31ce2453c82fatagen2026-09-24 13:07 UTC154
    Some(LatestEvent {
31ce2453c82fatagen2026-09-24 13:07 UTC155
        sender,
31ce2453c82fatagen2026-09-24 13:07 UTC156
        body,
31ce2453c82fatagen2026-09-24 13:07 UTC157
        timestamp_ms: timestamp.map(|timestamp| timestamp.get().into()),
31ce2453c82fatagen2026-09-24 13:07 UTC158
        send_state,
31ce2453c82fatagen2026-09-24 13:07 UTC159
    })
31ce2453c82fatagen2026-09-24 13:07 UTC160
}
31ce2453c82fatagen2026-09-24 13:07 UTC161
31ce2453c82fatagen2026-09-24 13:07 UTC162
type LatestParts = (
31ce2453c82fatagen2026-09-24 13:07 UTC163
    Option<ruma::OwnedUserId>,
31ce2453c82fatagen2026-09-24 13:07 UTC164
    Option<String>,
31ce2453c82fatagen2026-09-24 13:07 UTC165
    Option<ruma::MilliSecondsSinceUnixEpoch>,
31ce2453c82fatagen2026-09-24 13:07 UTC166
    SendState,
31ce2453c82fatagen2026-09-24 13:07 UTC167
);
31ce2453c82fatagen2026-09-24 13:07 UTC168
31ce2453c82fatagen2026-09-24 13:07 UTC169
fn local_event(
31ce2453c82fatagen2026-09-24 13:07 UTC170
    room: &Room,
31ce2453c82fatagen2026-09-24 13:07 UTC171
    local: &matrix_sdk::latest_events::LocalLatestEventValue,
31ce2453c82fatagen2026-09-24 13:07 UTC172
    send_state: SendState,
31ce2453c82fatagen2026-09-24 13:07 UTC173
) -> LatestParts {
31ce2453c82fatagen2026-09-24 13:07 UTC174
    let body = match local.content.deserialize() {
31ce2453c82fatagen2026-09-24 13:07 UTC175
        Ok(AnyMessageLikeEventContent::RoomMessage(content)) => Some(content.body().to_owned()),
31ce2453c82fatagen2026-09-24 13:07 UTC176
        _ => None,
31ce2453c82fatagen2026-09-24 13:07 UTC177
    };
31ce2453c82fatagen2026-09-24 13:07 UTC178
    (
31ce2453c82fatagen2026-09-24 13:07 UTC179
        room.own_user_id().to_owned().into(),
31ce2453c82fatagen2026-09-24 13:07 UTC180
        body,
31ce2453c82fatagen2026-09-24 13:07 UTC181
        Some(local.timestamp),
31ce2453c82fatagen2026-09-24 13:07 UTC182
        send_state,
31ce2453c82fatagen2026-09-24 13:07 UTC183
    )
31ce2453c82fatagen2026-09-24 13:07 UTC184
}
31ce2453c82fatagen2026-09-24 13:07 UTC185
31ce2453c82fatagen2026-09-24 13:07 UTC186
pub(crate) fn space_child(room: SpaceRoom) -> SpaceChild {
31ce2453c82fatagen2026-09-24 13:07 UTC187
    SpaceChild {
31ce2453c82fatagen2026-09-24 13:07 UTC188
        name: room.display_name,
31ce2453c82fatagen2026-09-24 13:07 UTC189
        room_id: room.room_id,
31ce2453c82fatagen2026-09-24 13:07 UTC190
        topic: room.topic,
31ce2453c82fatagen2026-09-24 13:07 UTC191
        avatar: room.avatar_url,
31ce2453c82fatagen2026-09-24 13:07 UTC192
        canonical_alias: room.canonical_alias,
31ce2453c82fatagen2026-09-24 13:07 UTC193
        joined_members: room.num_joined_members,
31ce2453c82fatagen2026-09-24 13:07 UTC194
        space: room.room_type == Some(ruma::room::RoomType::Space),
31ce2453c82fatagen2026-09-24 13:07 UTC195
        children_count: room.children_count,
31ce2453c82fatagen2026-09-24 13:07 UTC196
        membership: room.state.map(membership),
31ce2453c82fatagen2026-09-24 13:07 UTC197
        via: room.via,
31ce2453c82fatagen2026-09-24 13:07 UTC198
        suggested: room.suggested,
31ce2453c82fatagen2026-09-24 13:07 UTC199
        world_readable: room.world_readable,
31ce2453c82fatagen2026-09-24 13:07 UTC200
        guest_can_join: room.guest_can_join,
96fdf90aacd6atagen2026-09-08 08:24 UTC201
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC202
}
96fdf90aacd6atagen2026-09-08 08:24 UTC203
96fdf90aacd6atagen2026-09-08 08:24 UTC204
pub(crate) const fn notification_mode(
96fdf90aacd6atagen2026-09-08 08:24 UTC205
    mode: matrix_sdk::notification_settings::RoomNotificationMode,
96fdf90aacd6atagen2026-09-08 08:24 UTC206
) -> RoomNotificationMode {
96fdf90aacd6atagen2026-09-08 08:24 UTC207
    match mode {
96fdf90aacd6atagen2026-09-08 08:24 UTC208
        matrix_sdk::notification_settings::RoomNotificationMode::AllMessages => {
96fdf90aacd6atagen2026-09-08 08:24 UTC209
            RoomNotificationMode::AllMessages
96fdf90aacd6atagen2026-09-08 08:24 UTC210
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC211
        matrix_sdk::notification_settings::RoomNotificationMode::MentionsAndKeywordsOnly => {
96fdf90aacd6atagen2026-09-08 08:24 UTC212
            RoomNotificationMode::MentionsAndKeywordsOnly
96fdf90aacd6atagen2026-09-08 08:24 UTC213
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC214
        matrix_sdk::notification_settings::RoomNotificationMode::Mute => RoomNotificationMode::Mute,
96fdf90aacd6atagen2026-09-08 08:24 UTC215
    }
96fdf90aacd6atagen2026-09-08 08:24 UTC216
}