|
|
|
|
@ -5,17 +5,17 @@ use anyhow::anyhow;
|
|
|
|
|
use chrono::DateTime; |
|
|
|
|
use chrono::Utc; |
|
|
|
|
use either::Either; |
|
|
|
|
use log::{debug, info, warn}; |
|
|
|
|
use matrix_sdk::api::r0::sync::sync_events::Response as SyncResponse; |
|
|
|
|
use log::{debug, info}; |
|
|
|
|
use matrix_sdk::deserialized_responses::SyncResponse; |
|
|
|
|
use matrix_sdk::directory::PublicRoomsChunk; |
|
|
|
|
use matrix_sdk::events::{ |
|
|
|
|
room::member::{MemberEventContent, MembershipState}, |
|
|
|
|
AnyBasicEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncStateEvent, |
|
|
|
|
SyncStateEvent, |
|
|
|
|
AnyBasicEvent, AnyBasicEventContent, AnyMessageEventContent, AnyStrippedStateEvent, |
|
|
|
|
AnySyncEphemeralRoomEvent, AnySyncRoomEvent, AnySyncStateEvent, SyncStateEvent, |
|
|
|
|
}; |
|
|
|
|
use matrix_sdk::identifiers::{EventId, RoomAliasId, RoomId, UserId}; |
|
|
|
|
use matrix_sdk::Raw; |
|
|
|
|
use serde::{Deserialize, Serialize}; |
|
|
|
|
use serde_json::value::Value; |
|
|
|
|
use std::collections::{BTreeMap, HashMap, HashSet}; |
|
|
|
|
use std::convert::{TryFrom, TryInto}; |
|
|
|
|
use url::{ParseError as UrlError, Url}; |
|
|
|
|
@ -163,53 +163,23 @@ impl Room {
|
|
|
|
|
|
|
|
|
|
pub fn from_sync_response(response: &SyncResponse, user_id: UserId) -> Vec<Self> { |
|
|
|
|
// getting the list of direct rooms
|
|
|
|
|
let direct: HashSet<RoomId> = response.account_data.events |
|
|
|
|
let direct: HashSet<RoomId> = response |
|
|
|
|
.account_data |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.cloned() |
|
|
|
|
// Synapse sometimes sends an object with the key "[object Object]"
|
|
|
|
|
// instead of a user ID. Since we don't need the key, we use our own
|
|
|
|
|
// event type so it accepts that.
|
|
|
|
|
// There's always at most one object of this type.
|
|
|
|
|
.find_map(|ev| { |
|
|
|
|
Raw::<CustomDirectEvent>::from_json(ev.into_json()) |
|
|
|
|
.deserialize() |
|
|
|
|
.ok() |
|
|
|
|
.filter_map(|event| { |
|
|
|
|
if let AnyBasicEventContent::Direct(content) = event.content() { |
|
|
|
|
Some(content.values().flatten().cloned().collect::<Vec<RoomId>>()) |
|
|
|
|
} else { |
|
|
|
|
None |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.map_or(Default::default(), |direct_event| { |
|
|
|
|
direct_event.content.values().flatten().cloned().collect() |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
response.rooms.join.iter().for_each(|(_, room)| { |
|
|
|
|
room.state.events.iter().for_each(|ev| log::info!("stevents: {}", ev.json().get())); |
|
|
|
|
}); |
|
|
|
|
*/ |
|
|
|
|
.flatten() |
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
let joined_rooms = response.rooms.join.iter().map(|(k, room)| { |
|
|
|
|
let stevents: Vec<_> = room |
|
|
|
|
.state |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| ev.deserialize()) |
|
|
|
|
.inspect(|result_ev| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(Result::ok) |
|
|
|
|
.collect(); |
|
|
|
|
let dataevs: Vec<_> = room |
|
|
|
|
.account_data |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| ev.deserialize()) |
|
|
|
|
.inspect(|result_ev| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(Result::ok) |
|
|
|
|
.collect(); |
|
|
|
|
let stevents: Vec<_> = room.state.events.iter().collect(); |
|
|
|
|
let dataevs: Vec<_> = room.account_data.events.iter().collect(); |
|
|
|
|
let room_tag = dataevs |
|
|
|
|
.iter() |
|
|
|
|
.find_map(|event| match event { |
|
|
|
|
@ -274,28 +244,14 @@ impl Room {
|
|
|
|
|
_ => None, |
|
|
|
|
}), |
|
|
|
|
direct: direct.contains(&k), |
|
|
|
|
notifications: room |
|
|
|
|
.unread_notifications |
|
|
|
|
.notification_count |
|
|
|
|
.map(Into::into) |
|
|
|
|
.unwrap_or_default(), |
|
|
|
|
highlight: room |
|
|
|
|
.unread_notifications |
|
|
|
|
.highlight_count |
|
|
|
|
.map(Into::into) |
|
|
|
|
.unwrap_or_default(), |
|
|
|
|
notifications: room.unread_notifications.notification_count, |
|
|
|
|
highlight: room.unread_notifications.highlight_count, |
|
|
|
|
prev_batch: room.timeline.prev_batch.clone(), |
|
|
|
|
messages: room |
|
|
|
|
.timeline |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| Ok((k.clone(), ev.deserialize()?))) |
|
|
|
|
.inspect(|result_ev: &Result<_, serde_json::Error>| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(|k_ev| k_ev.ok()?.try_into().ok()) |
|
|
|
|
.filter_map(|event| (k.clone(), event.clone()).try_into().ok()) |
|
|
|
|
.collect(), |
|
|
|
|
admins: stevents |
|
|
|
|
.iter() |
|
|
|
|
@ -335,15 +291,8 @@ impl Room {
|
|
|
|
|
.ephemeral |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| ev.deserialize()) |
|
|
|
|
.inspect(|result_ev| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(Result::ok) |
|
|
|
|
.filter_map(|event| match event { |
|
|
|
|
AnySyncEphemeralRoomEvent::Receipt(ev) => Some(ev.content.0), |
|
|
|
|
AnySyncEphemeralRoomEvent::Receipt(ev) => Some(ev.content.0.clone()), |
|
|
|
|
_ => None, |
|
|
|
|
}) |
|
|
|
|
.take(1) |
|
|
|
|
@ -387,22 +336,10 @@ impl Room {
|
|
|
|
|
}) |
|
|
|
|
.for_each(|(msg, receipt)| msg.set_receipt(receipt)); |
|
|
|
|
|
|
|
|
|
if let Some(event_id) = room |
|
|
|
|
.ephemeral |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| ev.deserialize()) |
|
|
|
|
.inspect(|result_ev| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(Result::ok) |
|
|
|
|
.find_map(|event| match event { |
|
|
|
|
AnySyncEphemeralRoomEvent::FullyRead(ev) => Some(ev.content.event_id), |
|
|
|
|
_ => None, |
|
|
|
|
}) |
|
|
|
|
{ |
|
|
|
|
if let Some(event_id) = room.ephemeral.events.iter().find_map(|event| match event { |
|
|
|
|
AnySyncEphemeralRoomEvent::FullyRead(ev) => Some(ev.content.event_id.clone()), |
|
|
|
|
_ => None, |
|
|
|
|
}) { |
|
|
|
|
let event_id = Some(event_id); |
|
|
|
|
|
|
|
|
|
r.messages |
|
|
|
|
@ -416,50 +353,29 @@ impl Room {
|
|
|
|
|
r |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let left_rooms = |
|
|
|
|
response.rooms.leave.iter().map(|(k, room)| { |
|
|
|
|
// TODO: The spec doesn't explain where to get the reason
|
|
|
|
|
// for the kicking from, so matrix-sdk doesn't support
|
|
|
|
|
// that.
|
|
|
|
|
if let Some(last_event) = room.timeline.events.last().and_then(|ev| { |
|
|
|
|
match serde_json::to_value(ev.json()) { |
|
|
|
|
Ok(event) => Some(event), |
|
|
|
|
Err(err) => { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
None |
|
|
|
|
let left_rooms = response.rooms.leave.iter().map(|(k, room)| { |
|
|
|
|
// TODO: The spec doesn't explain where to get the reason
|
|
|
|
|
// for the kicking from, so matrix-sdk doesn't support
|
|
|
|
|
// that.
|
|
|
|
|
if let Some(last_event) = room.timeline.events.last() { |
|
|
|
|
if let AnySyncRoomEvent::Message(message) = last_event { |
|
|
|
|
let kicker = message.sender().clone(); |
|
|
|
|
if kicker != user_id { |
|
|
|
|
if let AnyMessageEventContent::Custom(message) = message.content() { |
|
|
|
|
if let Value::String(kick_reason) = &message.json["reason"] { |
|
|
|
|
let reason = Reason::Kicked(kick_reason.clone(), kicker); |
|
|
|
|
return Self::new(k.clone(), RoomMembership::Left(reason)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) { |
|
|
|
|
if let Some(kicker) = |
|
|
|
|
UserId::try_from(last_event["sender"].as_str().unwrap_or_default()) |
|
|
|
|
.ok() |
|
|
|
|
.filter(|leave_uid| *leave_uid != user_id) |
|
|
|
|
{ |
|
|
|
|
let kick_reason = &last_event["content"]["reason"]; |
|
|
|
|
let reason = Reason::Kicked( |
|
|
|
|
String::from(kick_reason.as_str().unwrap_or_default()), |
|
|
|
|
kicker, |
|
|
|
|
); |
|
|
|
|
return Self::new(k.clone(), RoomMembership::Left(reason)); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Self::new(k.clone(), RoomMembership::Left(Reason::None)) |
|
|
|
|
}); |
|
|
|
|
Self::new(k.clone(), RoomMembership::Left(Reason::None)) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
let invited_rooms = response.rooms.invite.iter().filter_map(|(k, room)| { |
|
|
|
|
let stevents: Vec<_> = room |
|
|
|
|
.invite_state |
|
|
|
|
.events |
|
|
|
|
.iter() |
|
|
|
|
.map(|ev| ev.deserialize()) |
|
|
|
|
.inspect(|result_ev| { |
|
|
|
|
if let Err(err) = result_ev { |
|
|
|
|
warn!("Bad event: {}", err); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.filter_map(Result::ok) |
|
|
|
|
.collect(); |
|
|
|
|
let stevents: Vec<_> = room.invite_state.events.iter().collect(); |
|
|
|
|
let inv_sender = stevents |
|
|
|
|
.iter() |
|
|
|
|
.find_map(|event| match event { |
|
|
|
|
|