mirror of
https://github.com/kristoferssolo/traxor.git
synced 2025-12-30 21:31:46 +00:00
Compare commits
2 Commits
46486a3409
...
161362fc1f
| Author | SHA1 | Date | |
|---|---|---|---|
| 161362fc1f | |||
| f997d19ab1 |
5
.github/workflows/rust.yml
vendored
5
.github/workflows/rust.yml
vendored
@ -16,9 +16,8 @@ jobs:
|
||||
- name: Check formatting
|
||||
run: cargo fmt -- --check
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
run: cargo build --release
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
run: cargo test
|
||||
- name: Run clippy
|
||||
run: cargo clippy -- -D warnings
|
||||
|
||||
|
||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -432,6 +432,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "filecaster"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97921cbd5451445637b91a0237b3c9316fa550ea7ff166a40be7ce5afad335"
|
||||
dependencies = [
|
||||
"filecaster-derive",
|
||||
"merge",
|
||||
@ -441,6 +443,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "filecaster-derive"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f5c7bc432f529eac3ec2d60812e05c1eae39fde9d7434fe59e64c03c27da882"
|
||||
dependencies = [
|
||||
"merge",
|
||||
"proc-macro-error2",
|
||||
|
||||
@ -6,9 +6,7 @@ license = "GPLv3"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
filecaster = { version = "0.2", features = [
|
||||
"merge",
|
||||
], path = "../filecaster/filecaster/" }
|
||||
filecaster = { version = "0.2", features = ["derive", "merge"] }
|
||||
color-eyre = "0.6"
|
||||
crossterm = "0.29"
|
||||
derive_more = { version = "2.0", features = ["display"] }
|
||||
|
||||
@ -43,4 +43,3 @@ mod tests {
|
||||
assert_eq!(file_size.to_string(), "1.00 GB");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,4 +43,3 @@ mod tests {
|
||||
assert_eq!(net_speed.to_string(), "1.00 GB/s");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -157,4 +157,4 @@ mod tests {
|
||||
let display = UnitDisplay::new(&unit, &["B", "KB", "MB"]);
|
||||
assert_eq!(display.to_string(), "512 B");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@ use std::{
|
||||
};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
const DEFAULT_CONFIG_STR: &str = include_str!("../../config/default.toml");
|
||||
|
||||
#[derive(Debug, Clone, FromFile)]
|
||||
pub struct Config {
|
||||
pub keybinds: KeybindsConfig,
|
||||
@ -25,12 +27,23 @@ pub struct 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
|
||||
///
|
||||
/// 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")]
|
||||
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 = [
|
||||
("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 ratatui::{Terminal, backend::CrosstermBackend};
|
||||
use std::io;
|
||||
use tracing::{debug, trace};
|
||||
use std::{io, sync::Arc};
|
||||
use tokio::{
|
||||
sync::Mutex,
|
||||
time::{self, Duration},
|
||||
};
|
||||
use tracing::{trace, warn};
|
||||
use traxor::{
|
||||
app::App,
|
||||
config::Config,
|
||||
@ -15,38 +19,54 @@ use traxor::{
|
||||
async fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
debug!("Loading configuration...");
|
||||
let config = Config::load()?;
|
||||
debug!("Configuration loaded.");
|
||||
|
||||
// Setup the logger.
|
||||
setup_logger(&config)?;
|
||||
|
||||
// Create an application.
|
||||
let mut app = App::new(config)?;
|
||||
// Wrap App in Arc<Mutex<>> so we can share it between UI and updater
|
||||
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 terminal = Terminal::new(backend)?;
|
||||
let events = EventHandler::new(250); // Update time in ms
|
||||
let mut tui = Tui::new(terminal, events);
|
||||
tui.init()?;
|
||||
|
||||
// Start the main loop.
|
||||
while app.running {
|
||||
// Render the user interface.
|
||||
tui.draw(&mut app)?;
|
||||
// Handle events.
|
||||
match tui.events.next()? {
|
||||
Event::Tick => {
|
||||
trace!(target: "app", "Event::Tick");
|
||||
app.tick().await?;
|
||||
// Main loop
|
||||
loop {
|
||||
{
|
||||
let app_guard = app.lock().await;
|
||||
if !app_guard.running {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut app_guard = app.lock().await;
|
||||
tui.draw(&mut app_guard)?;
|
||||
}
|
||||
|
||||
match tui.events.next()? {
|
||||
Event::Tick => {}
|
||||
Event::Key(key_event) => {
|
||||
trace!(target: "app", "Event::Key: {:?}", key_event);
|
||||
if let Some(action) = get_action(key_event, &mut app).await? {
|
||||
trace!(target: "app", "Action: {:?}", action);
|
||||
update(&mut app, action).await?;
|
||||
let mut app_guard = app.lock().await;
|
||||
if let Some(action) = get_action(key_event, &mut app_guard).await? {
|
||||
update(&mut app_guard, action).await?;
|
||||
}
|
||||
}
|
||||
Event::Mouse(mouse_event) => {
|
||||
@ -58,7 +78,6 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// Exit the user interface.
|
||||
tui.exit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -67,10 +67,10 @@ fn make_row<'a>(
|
||||
highlight: Style,
|
||||
) -> Row<'a> {
|
||||
let cells = fields.iter().map(|&field| {
|
||||
if let Some(id) = torrent.id {
|
||||
if selected.contains(&id) {
|
||||
return field.value(torrent).set_style(highlight);
|
||||
}
|
||||
if let Some(id) = torrent.id
|
||||
&& selected.contains(&id)
|
||||
{
|
||||
return field.value(torrent).set_style(highlight);
|
||||
}
|
||||
field.value(torrent).into()
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use ratatui::backend::TestBackend;
|
||||
use ratatui::Terminal;
|
||||
use ratatui::backend::TestBackend;
|
||||
use traxor::event::EventHandler;
|
||||
use traxor::tui::Tui;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user