Incorporate state store rewrite
Also add prototype message history backfill. Backfilled encrypted messages can't be handled before some api changes.
This commit is contained in:
parent
45c4b62150
commit
2a9dbb90d3
|
@ -23,7 +23,7 @@ tracing-subscriber = { version = "0.2", features = ["parking_lot"] }
|
||||||
|
|
||||||
[dependencies.matrix-sdk]
|
[dependencies.matrix-sdk]
|
||||||
git = "https://github.com/matrix-org/matrix-rust-sdk"
|
git = "https://github.com/matrix-org/matrix-rust-sdk"
|
||||||
rev = "d9e5a17"
|
rev = "74998c8"
|
||||||
default_features = false
|
default_features = false
|
||||||
features = ["encryption", "sqlite_cryptostore", "messages", "rustls-tls", "unstable-synapse-quirks"]
|
features = ["encryption", "sqlite_cryptostore", "messages", "rustls-tls", "unstable-synapse-quirks"]
|
||||||
|
|
||||||
|
|
|
@ -214,10 +214,6 @@ where
|
||||||
sender.send(Event::Token(response.next_batch)).ok();
|
sender.send(Event::Token(response.next_batch)).ok();
|
||||||
for (id, room) in response.rooms.join {
|
for (id, room) in response.rooms.join {
|
||||||
for event in room.timeline.events {
|
for event in room.timeline.events {
|
||||||
let event = match event.deserialize() {
|
|
||||||
Ok(event) => event,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
let id = id.clone();
|
let id = id.clone();
|
||||||
let event = match event {
|
let event = match event {
|
||||||
AnySyncRoomEvent::Message(e) => {
|
AnySyncRoomEvent::Message(e) => {
|
||||||
|
@ -237,10 +233,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for event in response.to_device.events {
|
for event in response.to_device.events {
|
||||||
let event = match event.deserialize() {
|
|
||||||
Ok(event) => event,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
sender.send(Event::ToDevice(event)).ok();
|
sender.send(Event::ToDevice(event)).ok();
|
||||||
}
|
}
|
||||||
LoopCtrl::Continue
|
LoopCtrl::Continue
|
||||||
|
|
157
src/ui.rs
157
src/ui.rs
|
@ -9,10 +9,13 @@ use iced::{
|
||||||
Subscription, Text, TextInput,
|
Subscription, Text, TextInput,
|
||||||
};
|
};
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
|
api::r0::message::get_message_events::{
|
||||||
|
Request as MessageRequest, Response as MessageResponse,
|
||||||
|
},
|
||||||
events::{
|
events::{
|
||||||
key::verification::cancel::CancelCode as VerificationCancelCode,
|
key::verification::cancel::CancelCode as VerificationCancelCode,
|
||||||
room::message::MessageEventContent, AnyMessageEvent, AnyMessageEventContent,
|
room::message::MessageEventContent, AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent,
|
||||||
AnyPossiblyRedactedSyncMessageEvent, AnyRoomEvent, AnyStateEvent, AnyToDeviceEvent,
|
AnyStateEvent, AnyToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{EventId, RoomAliasId, RoomId, UserId},
|
identifiers::{EventId, RoomAliasId, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
@ -85,7 +88,7 @@ impl MessageBuffer {
|
||||||
/// Sorts the messages by send time
|
/// Sorts the messages by send time
|
||||||
fn sort(&mut self) {
|
fn sort(&mut self) {
|
||||||
self.messages
|
self.messages
|
||||||
.sort_unstable_by(|a, b| a.origin_server_ts().cmp(&b.origin_server_ts()))
|
.sort_unstable_by_key(|msg| msg.origin_server_ts())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the send time of the most recently sent message
|
/// Gets the send time of the most recently sent message
|
||||||
|
@ -209,6 +212,7 @@ impl MainView {
|
||||||
.scrollbar_width(5);
|
.scrollbar_width(5);
|
||||||
|
|
||||||
// Group by DM and group conversation
|
// Group by DM and group conversation
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
let (mut dm_rooms, mut group_rooms): (
|
let (mut dm_rooms, mut group_rooms): (
|
||||||
Vec<(&RoomId, &RoomEntry)>,
|
Vec<(&RoomId, &RoomEntry)>,
|
||||||
Vec<(&RoomId, &RoomEntry)>,
|
Vec<(&RoomId, &RoomEntry)>,
|
||||||
|
@ -219,14 +223,16 @@ impl MainView {
|
||||||
// Sort
|
// Sort
|
||||||
for list in [&mut dm_rooms, &mut group_rooms].iter_mut() {
|
for list in [&mut dm_rooms, &mut group_rooms].iter_mut() {
|
||||||
match self.sorting {
|
match self.sorting {
|
||||||
RoomSorting::Alphabetic => list.sort_unstable_by(|(_, a), (_, b)| {
|
RoomSorting::Alphabetic => {
|
||||||
a.name.to_uppercase().cmp(&b.name.to_uppercase())
|
list.sort_unstable_by_key(|(_, room)| room.name.to_uppercase())
|
||||||
}),
|
}
|
||||||
|
// TODO: fix this
|
||||||
RoomSorting::Recent => list.sort_unstable_by(|(_, a), (_, b)| {
|
RoomSorting::Recent => list.sort_unstable_by(|(_, a), (_, b)| {
|
||||||
a.messages.updated.cmp(&b.messages.updated).reverse()
|
a.messages.updated.cmp(&b.messages.updated).reverse()
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Make sure button handler list has appropriate length
|
||||||
self.dm_buttons
|
self.dm_buttons
|
||||||
.resize_with(dm_rooms.len(), Default::default);
|
.resize_with(dm_rooms.len(), Default::default);
|
||||||
self.group_buttons
|
self.group_buttons
|
||||||
|
@ -241,7 +247,7 @@ impl MainView {
|
||||||
let (id, room) = dm_rooms[idx];
|
let (id, room) = dm_rooms[idx];
|
||||||
Button::new(button, Text::new(&room.name))
|
Button::new(button, Text::new(&room.name))
|
||||||
.width(300.into())
|
.width(300.into())
|
||||||
.on_press(Message::SelectRoom(id.clone().clone()))
|
.on_press(Message::SelectRoom(id.to_owned()))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let room_buttons: Vec<Button<_>> = self
|
let room_buttons: Vec<Button<_>> = self
|
||||||
|
@ -252,7 +258,7 @@ impl MainView {
|
||||||
let (id, room) = group_rooms[idx];
|
let (id, room) = group_rooms[idx];
|
||||||
Button::new(button, Text::new(&room.name))
|
Button::new(button, Text::new(&room.name))
|
||||||
.width(300.into())
|
.width(300.into())
|
||||||
.on_press(Message::SelectRoom(id.clone()))
|
.on_press(Message::SelectRoom(id.to_owned()))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
// Add buttons to container
|
// Add buttons to container
|
||||||
|
@ -279,23 +285,30 @@ impl MainView {
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
if let Some(room) = selected_room {
|
if let Some(room) = selected_room {
|
||||||
|
let title = if let Some(ref direct) = room.direct {
|
||||||
|
format!("{} ({})", &room.name, direct)
|
||||||
|
} else if let Some(ref alias) = room.alias {
|
||||||
|
format!("{} ({})", &room.name, alias)
|
||||||
|
} else {
|
||||||
|
room.name.clone()
|
||||||
|
};
|
||||||
message_col = message_col
|
message_col = message_col
|
||||||
.push(Text::new(&room.name).size(25))
|
.push(Text::new(title).size(25))
|
||||||
.push(Rule::horizontal(2));
|
.push(Rule::horizontal(2));
|
||||||
let mut scroll = Scrollable::new(&mut self.message_scroll)
|
let mut scroll = Scrollable::new(&mut self.message_scroll)
|
||||||
.scrollbar_width(2)
|
.scrollbar_width(2)
|
||||||
.height(Length::Fill);
|
.height(Length::Fill);
|
||||||
for event in room.messages.messages.iter() {
|
for event in room.messages.messages.iter() {
|
||||||
|
#[allow(clippy::single_match)]
|
||||||
match event {
|
match event {
|
||||||
AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(message)) => {
|
AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(message)) => {
|
||||||
let sender = {
|
let sender = {
|
||||||
let joined = self.client.joined_rooms();
|
match self.client.get_joined_room(&message.room_id) {
|
||||||
let rooms_lock = block_on(async { joined.read().await });
|
|
||||||
match rooms_lock.get(&message.room_id) {
|
|
||||||
Some(backend) => {
|
Some(backend) => {
|
||||||
let room_lock = block_on(async { backend.read().await });
|
match block_on(async {
|
||||||
match room_lock.joined_members.get(&message.sender) {
|
backend.get_member(&message.sender).await
|
||||||
Some(member) => member.disambiguated_name(),
|
}) {
|
||||||
|
Some(member) => member.name().to_owned(),
|
||||||
None => message.sender.to_string(),
|
None => message.sender.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +361,9 @@ impl MainView {
|
||||||
.push(Text::new(format_systime(message.origin_server_ts)));
|
.push(Text::new(format_systime(message.origin_server_ts)));
|
||||||
scroll = scroll.push(row);
|
scroll = scroll.push(row);
|
||||||
}
|
}
|
||||||
|
AnyRoomEvent::Message(AnyMessageEvent::RoomEncrypted(_encrypted)) => {
|
||||||
|
scroll = scroll.push(Text::new("Encrypted event").color([0.3, 0.3, 0.3]))
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,6 +461,7 @@ impl MainView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Retrix {
|
pub enum Retrix {
|
||||||
Prompt(PromptView),
|
Prompt(PromptView),
|
||||||
|
@ -471,6 +488,8 @@ pub enum Message {
|
||||||
ResetRoom(RoomId, RoomEntry),
|
ResetRoom(RoomId, RoomEntry),
|
||||||
/// Get backfill for given room
|
/// Get backfill for given room
|
||||||
BackFill(RoomId),
|
BackFill(RoomId),
|
||||||
|
/// Received backfille
|
||||||
|
BackFilled(RoomId, MessageResponse),
|
||||||
/// View messages from this room
|
/// View messages from this room
|
||||||
SelectRoom(RoomId),
|
SelectRoom(RoomId),
|
||||||
/// Set error message
|
/// Set error message
|
||||||
|
@ -608,27 +627,28 @@ impl Application for Retrix {
|
||||||
},
|
},
|
||||||
Retrix::AwaitLogin => match message {
|
Retrix::AwaitLogin => match message {
|
||||||
Message::LoginFailed(e) => {
|
Message::LoginFailed(e) => {
|
||||||
let mut view = PromptView::default();
|
let view = PromptView {
|
||||||
view.error = Some(e);
|
error: Some(e),
|
||||||
|
..PromptView::default()
|
||||||
|
};
|
||||||
*self = Retrix::Prompt(view);
|
*self = Retrix::Prompt(view);
|
||||||
}
|
}
|
||||||
Message::LoggedIn(client, session) => {
|
Message::LoggedIn(client, session) => {
|
||||||
*self = Retrix::LoggedIn(MainView::new(client.clone(), session));
|
*self = Retrix::LoggedIn(MainView::new(client.clone(), session));
|
||||||
let joined = client.joined_rooms();
|
|
||||||
let read = block_on(async { joined.read().await });
|
|
||||||
let mut commands: Vec<Command<Message>> = Vec::new();
|
let mut commands: Vec<Command<Message>> = Vec::new();
|
||||||
for (id, room) in read.iter() {
|
for room in client.joined_rooms().into_iter() {
|
||||||
let id = id.clone();
|
|
||||||
let room = room.clone();
|
|
||||||
let client = client.clone();
|
|
||||||
let command = async move {
|
let command = async move {
|
||||||
let room = room.read().await;
|
let room = room.clone();
|
||||||
let mut entry = RoomEntry::default();
|
let entry = RoomEntry {
|
||||||
|
direct: room.direct_target(),
|
||||||
|
name: block_on(async { room.calculate_name().await }),
|
||||||
|
topic: room.topic().unwrap_or_default(),
|
||||||
|
..RoomEntry::default()
|
||||||
|
};
|
||||||
|
|
||||||
entry.direct = room.direct_target.clone();
|
|
||||||
// Display name calculation for DMs is bronk so we're doing it
|
// Display name calculation for DMs is bronk so we're doing it
|
||||||
// ourselves
|
// ourselves
|
||||||
match entry.direct {
|
/*match entry.direct {
|
||||||
Some(ref direct) => {
|
Some(ref direct) => {
|
||||||
let request = matrix_sdk::api::r0::profile::get_display_name::Request::new(direct);
|
let request = matrix_sdk::api::r0::profile::get_display_name::Request::new(direct);
|
||||||
if let Ok(response) = client.send(request).await {
|
if let Ok(response) = client.send(request).await {
|
||||||
|
@ -638,8 +658,8 @@ impl Application for Retrix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => entry.name = room.display_name(),
|
None => entry.name = room.display_name(),
|
||||||
}
|
}*/
|
||||||
let messages = room
|
/*let messages = room
|
||||||
.messages
|
.messages
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -654,9 +674,10 @@ impl Application for Retrix {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
entry.messages.messages = messages;
|
entry.messages.messages = messages;*/
|
||||||
Message::ResetRoom(id, entry)
|
Message::ResetRoom(room.room_id().to_owned(), entry)
|
||||||
}.into();
|
}
|
||||||
|
.into();
|
||||||
commands.push(command)
|
commands.push(command)
|
||||||
}
|
}
|
||||||
return Command::batch(commands);
|
return Command::batch(commands);
|
||||||
|
@ -670,12 +691,36 @@ impl Application for Retrix {
|
||||||
Message::ResetRoom(id, room) => {
|
Message::ResetRoom(id, room) => {
|
||||||
view.rooms.insert(id, room).and(Some(())).unwrap_or(())
|
view.rooms.insert(id, room).and(Some(())).unwrap_or(())
|
||||||
}
|
}
|
||||||
Message::SelectRoom(r) => view.selected = Some(r),
|
Message::SelectRoom(r) => {
|
||||||
|
view.selected = Some(r.clone());
|
||||||
|
return async move { Message::BackFill(r) }.into();
|
||||||
|
}
|
||||||
Message::Sync(event) => match event {
|
Message::Sync(event) => match event {
|
||||||
matrix::Event::Room(event) => match event {
|
matrix::Event::Room(event) => match event {
|
||||||
AnyRoomEvent::Message(event) => {
|
AnyRoomEvent::Message(event) => {
|
||||||
let room = view.rooms.entry(event.room_id().clone()).or_default();
|
let room = view.rooms.entry(event.room_id().clone()).or_default();
|
||||||
room.messages.push(AnyRoomEvent::Message(event));
|
room.messages.push(AnyRoomEvent::Message(event.clone()));
|
||||||
|
// Set read marker if message is in selected room
|
||||||
|
if view.selected.as_ref() == Some(event.room_id()) {
|
||||||
|
let client = view.client.clone();
|
||||||
|
return Command::perform(
|
||||||
|
async move {
|
||||||
|
client
|
||||||
|
.read_marker(
|
||||||
|
event.room_id(),
|
||||||
|
event.event_id(),
|
||||||
|
Some(event.event_id()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.err()
|
||||||
|
},
|
||||||
|
|result| match result {
|
||||||
|
Some(err) => Message::ErrorMessage(err.to_string()),
|
||||||
|
// TODO: Make this an actual no-op
|
||||||
|
None => Message::Login,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AnyRoomEvent::State(event) => match event {
|
AnyRoomEvent::State(event) => match event {
|
||||||
AnyStateEvent::RoomCanonicalAlias(ref alias) => {
|
AnyStateEvent::RoomCanonicalAlias(ref alias) => {
|
||||||
|
@ -706,7 +751,7 @@ impl Application for Retrix {
|
||||||
let client = view.client.clone();
|
let client = view.client.clone();
|
||||||
return Command::perform(
|
return Command::perform(
|
||||||
async move {
|
async move {
|
||||||
tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
//tokio::time::delay_for(std::time::Duration::from_secs(2)).await;
|
||||||
client.get_verification(&start.content.transaction_id).await
|
client.get_verification(&start.content.transaction_id).await
|
||||||
},
|
},
|
||||||
Message::SetVerification,
|
Message::SetVerification,
|
||||||
|
@ -722,6 +767,48 @@ impl Application for Retrix {
|
||||||
view.sync_token = token;
|
view.sync_token = token;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Message::BackFill(id) => {
|
||||||
|
let room = view.rooms.get(&id).unwrap();
|
||||||
|
let client = view.client.clone();
|
||||||
|
let token = match room.messages.end.clone() {
|
||||||
|
Some(end) => end,
|
||||||
|
None => client
|
||||||
|
.get_joined_room(&id)
|
||||||
|
.unwrap()
|
||||||
|
.last_prev_batch()
|
||||||
|
.unwrap_or_else(|| view.sync_token.clone()),
|
||||||
|
};
|
||||||
|
return async move {
|
||||||
|
let request = MessageRequest::backward(&id, &token);
|
||||||
|
match client.room_messages(request).await {
|
||||||
|
Ok(response) => Message::BackFilled(id, response),
|
||||||
|
Err(e) => Message::ErrorMessage(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
Message::BackFilled(id, response) => {
|
||||||
|
let room = view.rooms.get_mut(&id).unwrap();
|
||||||
|
let events: Vec<AnyRoomEvent> = response
|
||||||
|
.chunk
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| e.deserialize().ok())
|
||||||
|
.chain(
|
||||||
|
response
|
||||||
|
.state
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| e.deserialize().ok().map(AnyRoomEvent::State)),
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Some(start) = response.start {
|
||||||
|
room.messages.start = Some(start);
|
||||||
|
}
|
||||||
|
if let Some(end) = response.end {
|
||||||
|
room.messages.end = Some(end);
|
||||||
|
}
|
||||||
|
room.messages.append(events);
|
||||||
|
}
|
||||||
Message::SetVerification(v) => view.sas = v,
|
Message::SetVerification(v) => view.sas = v,
|
||||||
Message::VerificationAccept => {
|
Message::VerificationAccept => {
|
||||||
let sas = match &view.sas {
|
let sas = match &view.sas {
|
||||||
|
|
Loading…
Reference in a new issue