mirror of
https://github.com/kristoferssolo/traxor.git
synced 2025-10-21 20:10:35 +00:00
feat: improve event loop
This commit is contained in:
parent
46486a3409
commit
fc3db9746e
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -99,6 +99,12 @@ version = "3.19.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@ -447,7 +453,8 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde",
|
"serde",
|
||||||
"syn",
|
"thiserror 2.0.12",
|
||||||
|
"unsynn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -504,6 +511,15 @@ dependencies = [
|
|||||||
"pin-utils",
|
"pin-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -1002,6 +1018,12 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mutants"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@ -1553,6 +1575,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shadow_counted"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65da48d447333cebe1aadbdd3662f3ba56e76e67f53bc46f3dd5f67c74629d6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -2122,6 +2150,18 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsynn"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7940603a9e25cf11211cc43b81f4fcad2b8ab4df291ca855f32c40e1ac22d5bc"
|
||||||
|
dependencies = [
|
||||||
|
"fxhash",
|
||||||
|
"mutants",
|
||||||
|
"proc-macro2",
|
||||||
|
"shadow_counted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|||||||
@ -17,6 +17,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
|
const DEFAULT_CONFIG_STR: &str = include_str!("../../config/default.toml");
|
||||||
|
|
||||||
#[derive(Debug, Clone, FromFile)]
|
#[derive(Debug, Clone, FromFile)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub keybinds: KeybindsConfig,
|
pub keybinds: KeybindsConfig,
|
||||||
@ -25,12 +27,23 @@ pub struct Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
/// Load configuration with fallback to embedded defaults.
|
||||||
|
///
|
||||||
|
/// Merge order:
|
||||||
|
/// 1. Embedded defaults
|
||||||
|
/// 2. System-wide config (`/etc/xdg/traxor/config.toml`)
|
||||||
|
/// 3. User config (`~/.config/traxor/config.toml`)
|
||||||
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// TODO: add error types
|
/// Returns an error if:
|
||||||
|
/// - The embedded default config cannot be parsed (should never happen unless corrupted at build time).
|
||||||
|
/// - The system-wide or user config file cannot be read due to I/O errors.
|
||||||
|
/// - The TOML in any config file is invalid and cannot be parsed.
|
||||||
#[tracing::instrument(name = "Loading configuration")]
|
#[tracing::instrument(name = "Loading configuration")]
|
||||||
pub fn load() -> Result<Self> {
|
pub fn load() -> Result<Self> {
|
||||||
let mut cfg_file = ConfigFile::default();
|
let mut cfg_file = toml::from_str::<ConfigFile>(DEFAULT_CONFIG_STR)
|
||||||
|
.context("Failed to parse embedded default config")?;
|
||||||
|
|
||||||
let candidates = [
|
let candidates = [
|
||||||
("system-wide", PathBuf::from("/etc/xdg/traxor/config.toml")),
|
("system-wide", PathBuf::from("/etc/xdg/traxor/config.toml")),
|
||||||
|
|||||||
65
src/main.rs
65
src/main.rs
@ -1,7 +1,11 @@
|
|||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use ratatui::{Terminal, backend::CrosstermBackend};
|
use ratatui::{Terminal, backend::CrosstermBackend};
|
||||||
use std::io;
|
use std::{io, sync::Arc};
|
||||||
use tracing::{debug, trace};
|
use tokio::{
|
||||||
|
sync::Mutex,
|
||||||
|
time::{self, Duration},
|
||||||
|
};
|
||||||
|
use tracing::{trace, warn};
|
||||||
use traxor::{
|
use traxor::{
|
||||||
app::App,
|
app::App,
|
||||||
config::Config,
|
config::Config,
|
||||||
@ -15,38 +19,54 @@ use traxor::{
|
|||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|
||||||
debug!("Loading configuration...");
|
|
||||||
let config = Config::load()?;
|
let config = Config::load()?;
|
||||||
debug!("Configuration loaded.");
|
|
||||||
|
|
||||||
// Setup the logger.
|
|
||||||
setup_logger(&config)?;
|
setup_logger(&config)?;
|
||||||
|
|
||||||
// Create an application.
|
// Wrap App in Arc<Mutex<>> so we can share it between UI and updater
|
||||||
let mut app = App::new(config)?;
|
let app = Arc::new(Mutex::new(App::new(config)?));
|
||||||
|
|
||||||
// Initialize the terminal user interface.
|
// Clone for updater task
|
||||||
|
let app_clone = app.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut interval = time::interval(Duration::from_secs(2));
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
let mut app = app_clone.lock().await;
|
||||||
|
if let Err(e) = app.torrents.update().await {
|
||||||
|
warn!("Failed to update torrents: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TUI setup
|
||||||
let backend = CrosstermBackend::new(io::stderr());
|
let backend = CrosstermBackend::new(io::stderr());
|
||||||
let terminal = Terminal::new(backend)?;
|
let terminal = Terminal::new(backend)?;
|
||||||
let events = EventHandler::new(250); // Update time in ms
|
let events = EventHandler::new(250); // Update time in ms
|
||||||
let mut tui = Tui::new(terminal, events);
|
let mut tui = Tui::new(terminal, events);
|
||||||
tui.init()?;
|
tui.init()?;
|
||||||
|
|
||||||
// Start the main loop.
|
// Main loop
|
||||||
while app.running {
|
loop {
|
||||||
// Render the user interface.
|
{
|
||||||
tui.draw(&mut app)?;
|
let app_guard = app.lock().await;
|
||||||
// Handle events.
|
if !app_guard.running {
|
||||||
match tui.events.next()? {
|
break;
|
||||||
Event::Tick => {
|
|
||||||
trace!(target: "app", "Event::Tick");
|
|
||||||
app.tick().await?;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut app_guard = app.lock().await;
|
||||||
|
tui.draw(&mut app_guard)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match tui.events.next()? {
|
||||||
|
Event::Tick => {}
|
||||||
Event::Key(key_event) => {
|
Event::Key(key_event) => {
|
||||||
trace!(target: "app", "Event::Key: {:?}", key_event);
|
let mut app_guard = app.lock().await;
|
||||||
if let Some(action) = get_action(key_event, &mut app).await? {
|
if let Some(action) = get_action(key_event, &mut app_guard).await? {
|
||||||
trace!(target: "app", "Action: {:?}", action);
|
update(&mut app_guard, action).await?;
|
||||||
update(&mut app, action).await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(mouse_event) => {
|
Event::Mouse(mouse_event) => {
|
||||||
@ -58,7 +78,6 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit the user interface.
|
|
||||||
tui.exit()?;
|
tui.exit()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,10 +67,10 @@ fn make_row<'a>(
|
|||||||
highlight: Style,
|
highlight: Style,
|
||||||
) -> Row<'a> {
|
) -> Row<'a> {
|
||||||
let cells = fields.iter().map(|&field| {
|
let cells = fields.iter().map(|&field| {
|
||||||
if let Some(id) = torrent.id {
|
if let Some(id) = torrent.id
|
||||||
if selected.contains(&id) {
|
&& selected.contains(&id)
|
||||||
return field.value(torrent).set_style(highlight);
|
{
|
||||||
}
|
return field.value(torrent).set_style(highlight);
|
||||||
}
|
}
|
||||||
field.value(torrent).into()
|
field.value(torrent).into()
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user