From f9ea62b654790bb82a61809a5748007c76c7be2c Mon Sep 17 00:00:00 2001 From: Val Lorentz Date: Mon, 30 Oct 2023 22:11:06 +0100 Subject: [PATCH] [WIP] Fetch events from Matrix --- src/app.rs | 145 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 34 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5d20808..88c83ee 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,26 @@ +/* + * Copyright (C) 2023 Valentin Lorentz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use std::cell::RefCell; +use std::sync::atomic::{AtomicBool, Ordering}; + use color_eyre::eyre::{Result, WrapErr}; use crossterm::event::KeyEvent; +use futures::stream::FuturesUnordered; +use futures::StreamExt; use nonempty::NonEmpty; use ratatui::prelude::Rect; use serde::{Deserialize, Serialize}; @@ -21,10 +42,10 @@ pub struct App { pub tick_rate: f64, pub frame_rate: f64, pub components: Vec>, - pub should_quit: bool, + pub should_quit: AtomicBool, pub should_suspend: bool, pub mode: Mode, - pub last_tick_key_events: Vec, + pub last_tick_key_events: RefCell>, } impl App { @@ -64,13 +85,13 @@ impl App { tick_rate, frame_rate, components: vec![Box::new(home), Box::new(fps)], - should_quit: false, + should_quit: AtomicBool::new(false), should_suspend: false, clients, config, commands: RataCommands::new(), mode, - last_tick_key_events: Vec::new(), + last_tick_key_events: RefCell::new(Vec::new()), }; crate::plugins::load_all(&mut app).context("Could not load plugins")?; Ok(app) @@ -78,6 +99,7 @@ impl App { pub async fn run(&mut self) -> Result<()> { let (action_tx, mut action_rx) = mpsc::unbounded_channel(); + let (sync_responses_tx, mut sync_responses_rx) = mpsc::unbounded_channel(); let mut tui = tui::Tui::new()? .tick_rate(self.tick_rate) @@ -97,36 +119,55 @@ impl App { component.init(tui.size()?)?; } - loop { - if let Some(e) = tui.next().await { - match e { - tui::Event::Quit => action_tx.send(Action::Quit)?, - tui::Event::Tick => action_tx.send(Action::Tick)?, - tui::Event::Render => action_tx.send(Action::Render)?, - tui::Event::Resize(x, y) => action_tx.send(Action::Resize(x, y))?, - tui::Event::Key(key) => { - if let Some(keymap) = self.config.keybindings.get(&self.mode) { - if let Some(command_line) = keymap.get(&vec![key]) { - log::info!("Got command: {command_line}"); - crate::commands::run_command(command_line, &self, &action_tx)?; - } else { - // If the key was not handled as a single key action, - // then consider it for multi-key combinations. - self.last_tick_key_events.push(key); + let sync_clients = self.clients.clone(); + let mut sync_results = FuturesUnordered::new(); + for client in sync_clients.iter() { + client.add_event_handler(|ev: matrix_sdk::ruma::events::room::message::SyncRoomMessageEvent| async move { + println!("Received a message {:?}", ev); + }); + let server_name = client.user_id().expect("missing user id").server_name(); + let mut sync_settings = matrix_sdk::config::SyncSettings::default(); + if server_name == "matrix.org" { + // matrix.org is slow and frequently hits the timeout on initial sync, + // let's quadruple the default + sync_settings = sync_settings.timeout(std::time::Duration::from_secs(120)); + } + sync_results.push(client.sync_with_result_callback( + sync_settings, + |res| { + let client2 = client.clone(); + async { + let sync_response = res.expect("Failed sync"); + println!("sync response {:?}", sync_response); + sync_responses_tx.send((client2, sync_response)).expect("could not send sync response"); + if self.should_quit.load(Ordering::Acquire) { + Ok(matrix_sdk::LoopCtrl::Break) + } else { + Ok(matrix_sdk::LoopCtrl::Continue) + } + } + }, + )); + } - // Check for multi-key combinations - if let Some(command_line) = keymap.get(&self.last_tick_key_events) { - log::info!("Got command: {command_line}"); - crate::commands::run_command(command_line, &self, &action_tx)?; - } + loop { + tokio::select! { + e = tui.next() => { + if let Some(e) = e { + self.handle_tui_event(&action_tx, e.clone())?; + for component in self.components.iter_mut() { + if let Some(action) = component.handle_events(Some(e.clone()))? { + action_tx.send(action)?; } - }; - }, - _ => {}, + } + } } - for component in self.components.iter_mut() { - if let Some(action) = component.handle_events(Some(e.clone()))? { - action_tx.send(action)?; + sync_response = sync_responses_rx.recv() => { + todo!("handle {:?}", sync_response); + } + sync_result = sync_results.next() => { + if !self.should_quit.load(Ordering::Acquire) { + panic!("Sync ended unexpected: {:?}", sync_result); } } } @@ -137,9 +178,9 @@ impl App { } match action { Action::Tick => { - self.last_tick_key_events.drain(..); + self.last_tick_key_events.borrow_mut().drain(..); }, - Action::Quit => self.should_quit = true, + Action::Quit => self.should_quit.store(true, Ordering::Release), Action::Suspend => self.should_suspend = true, Action::Resume => self.should_suspend = false, Action::Resize(w, h) => { @@ -183,7 +224,7 @@ impl App { .frame_rate(self.frame_rate); // tui.mouse(true); tui.enter()?; - } else if self.should_quit { + } else if self.should_quit.load(Ordering::Acquire) { tui.stop()?; break; } @@ -191,4 +232,40 @@ impl App { tui.exit()?; Ok(()) } + + fn handle_tui_event( + &self, + action_tx: &mpsc::UnboundedSender, + e: tui::Event, + ) -> Result<()> { + match e { + tui::Event::Quit => action_tx.send(Action::Quit)?, + tui::Event::Tick => action_tx.send(Action::Tick)?, + tui::Event::Render => action_tx.send(Action::Render)?, + tui::Event::Resize(x, y) => action_tx.send(Action::Resize(x, y))?, + tui::Event::Key(key) => { + if let Some(keymap) = self.config.keybindings.get(&self.mode) { + if let Some(command_line) = keymap.get(&vec![key]) { + log::info!("Got command: {command_line}"); + crate::commands::run_command(command_line, &self, &action_tx)?; + } else { + let mut last_tick_key_events = self.last_tick_key_events.borrow_mut(); + + // If the key was not handled as a single key action, + // then consider it for multi-key combinations. + last_tick_key_events.push(key); + + // Check for multi-key combinations + if let Some(command_line) = keymap.get(&*last_tick_key_events) { + log::info!("Got command: {command_line}"); + crate::commands::run_command(command_line, &self, &action_tx)?; + } + } + }; + }, + _ => {}, + } + + Ok(()) + } }