From f9a8202b6bb2a9baba9f10d78d2f868ddb9858d3 Mon Sep 17 00:00:00 2001 From: xmppftw Date: Wed, 5 Jun 2024 01:51:43 +0200 Subject: [PATCH] send + receive message --- src/helpers/message_store.rs | 35 +++++++++++++++++++++++++++++ src/helpers/mod.rs | 1 + src/main.rs | 43 +++++++++++++++++++++++++----------- src/xmpp_client.rs | 40 +++++++++++++++++++++++++++++---- 4 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 src/helpers/message_store.rs create mode 100644 src/helpers/mod.rs diff --git a/src/helpers/message_store.rs b/src/helpers/message_store.rs new file mode 100644 index 0000000..f7be353 --- /dev/null +++ b/src/helpers/message_store.rs @@ -0,0 +1,35 @@ +use gtk::gio::ListStore; +use xmpp::BareJid; + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; + +use crate::poezio_logs::load_logs; +use crate::Message; + +pub type InnerMessageStore = HashMap; + +#[derive(Clone, Debug, Default)] +pub struct MessageStore { + /// complete message history + store: Arc>, +} + +impl<'a> MessageStore { + pub fn new() -> Self { + Self::default() + } + + pub fn with_jid(&self, jid: &BareJid) -> ListStore { + self.store + .write() + .unwrap() + .entry(jid.clone()) + .or_insert(load_logs(jid.as_str())) + .clone() + } + + pub fn insert_message(&self, jid: &BareJid, message: &Message) { + self.with_jid(jid).append(message); + } +} diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs new file mode 100644 index 0000000..effddaf --- /dev/null +++ b/src/helpers/mod.rs @@ -0,0 +1 @@ +pub mod message_store; diff --git a/src/main.rs b/src/main.rs index 55ddc02..872404e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use gtk::{gio, glib}; use std::sync::{Arc, RwLock}; mod config; +mod helpers; mod message; mod poezio_logs; mod tab; @@ -30,6 +31,7 @@ mod xdg; mod xmpp_client; use config::ConfigFile; +use helpers::message_store::MessageStore; use message::Message; use tab::Tab; @@ -46,7 +48,12 @@ fn xep_0392(input: &str) -> String { format!("#{:02x}{:02x}{:02x}", r, g, b) } -fn on_login_pressed(win: window::MainWindow, config: Arc>) { +fn on_login_pressed( + win: window::MainWindow, + config: Arc>, + messages: MessageStore, + xmpp_cmd: xmpp_client::CommandSender, +) { let jid = win.jid().text(); let password = win.password().text(); @@ -54,7 +61,7 @@ fn on_login_pressed(win: window::MainWindow, config: Arc>) { win.stack().set_visible_child(win.spinner()); let (xmpp_receiver, cmd_sender) = xmpp_client::client(&jid, &password); - // let win2 = win.clone(); + xmpp_cmd.set_sender(cmd_sender); glib::spawn_future_local(async move { while let Ok(event) = xmpp_receiver.recv().await { match event { @@ -85,6 +92,10 @@ fn on_login_pressed(win: window::MainWindow, config: Arc>) { win.tabs_store().append(&tab); } + xmpp_client::XMPPEvent::PM(jid, body, time) => { + let message = Message::new(&time, jid.as_str(), &body); + messages.insert_message(&jid, &message); + } } } }); @@ -95,6 +106,8 @@ fn main() { env_logger::init(); let config = Arc::new(RwLock::new(ConfigFile::from_xdg())); + let messages = MessageStore::new(); + let xmpp_cmd = xmpp_client::CommandSender::new(); let app = adw::Application::builder() .application_id("fr.linkmauve.XmppClient") @@ -130,8 +143,15 @@ fn main() { let win2 = win.clone(); let config2 = config.clone(); + let messages2 = messages.clone(); + let xmpp_cmd2 = xmpp_cmd.clone(); win.login().connect_clicked(move |_| { - on_login_pressed(win2.clone(), config2.clone()); + on_login_pressed( + win2.clone(), + config2.clone(), + messages2.clone(), + xmpp_cmd2.clone(), + ); }); assert!(Tab::static_type().is_valid()); @@ -198,12 +218,13 @@ fn main() { win.tabs_selection().set_model(Some(win.tabs_store())); let win2 = win.clone(); + let messages2 = messages.clone(); win.tabs_selection() .connect_selection_changed(move |tabs_selection, _, _| { let item = tabs_selection.selected_item().unwrap(); let tab: &Tab = item.downcast_ref().unwrap(); println!("Switching to {}", tab.jid()); - let store = poezio_logs::load_logs(&tab.jid()); + let store = messages2.with_jid(&jid::BareJid::new(&tab.jid()).unwrap()); let selection = win2.selection(); selection.set_model(Some(&store)); win2.messages().scroll_to( @@ -216,7 +237,7 @@ fn main() { }); let win2 = win.clone(); - //let cmd_sender2 = cmd_sender.clone(); + let xmpp_cmd2 = xmpp_cmd.clone(); win.entry().connect_activate(move |entry| { let text = entry.text(); entry.set_text(""); @@ -226,14 +247,10 @@ fn main() { .selected_item() .and_downcast() .unwrap(); - /* - cmd_sender2 - .send_blocking(xmpp_client::XMPPCommand::SendPM( - xmpp::BareJid::new(¤t_tab.jid()).unwrap(), - text.as_str().to_string(), - )) - .unwrap(); - */ + xmpp_cmd2.send(xmpp_client::XMPPCommand::SendPM( + xmpp::BareJid::new(¤t_tab.jid()).unwrap(), + text.as_str().to_string(), + )); let message = Message::now(&get_own_nick(), &text); let selection = win2.selection(); let store = selection diff --git a/src/xmpp_client.rs b/src/xmpp_client.rs index 92ba903..eaed5f9 100644 --- a/src/xmpp_client.rs +++ b/src/xmpp_client.rs @@ -1,20 +1,45 @@ use async_channel::{Receiver, Sender}; +use chrono::{DateTime, Utc}; use tokio::runtime::Runtime; use xmpp::{BareJid, ClientBuilder, ClientFeature}; use std::path::PathBuf; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock, RwLock}; #[derive(Clone, Debug)] pub enum XMPPCommand { SendPM(BareJid, String), } +#[derive(Clone, Debug)] +pub struct CommandSender(Arc>>>); + +impl CommandSender { + pub fn new() -> Self { + Self(Arc::new(RwLock::new(None))) + } + + pub fn set_sender(&self, sender: Sender) { + *self.0.write().unwrap() = Some(sender); + } + + pub fn send(&self, command: XMPPCommand) { + self.0 + .write() + .unwrap() + .as_ref() + .expect("bug: CommandSender not init") + .send_blocking(command) + .unwrap(); + } +} + #[derive(Clone, Debug)] pub enum XMPPEvent { Online, Avatar(BareJid, String), Contact(BareJid, Option), + PM(BareJid, String, DateTime), } pub fn tokio_runtime() -> &'static Runtime { @@ -70,9 +95,16 @@ pub async fn handle_xmpp_event(event: xmpp::Event) -> Option { Some(XMPPEvent::Contact(avatar_jid, None)) } } - xmpp::Event::ChatMessage(_id, _from, _body, _time) => { - // TODO: Insert message into tab history - None + xmpp::Event::ChatMessage(_id, from, body, time) => { + if from.is_bare() { + Some(XMPPEvent::PM( + from.to_bare(), + body.0.to_string(), + time.received.clone(), + )) + } else { + None + } } _ => None, }