diff --git a/src/app/mod.rs b/src/app/mod.rs index 31236b9..449c933 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -2,17 +2,11 @@ use std::{collections::BTreeMap, net::SocketAddr, time::Duration}; use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind}; use futures::{FutureExt, StreamExt}; -use joecalsend::{ - Config, JoecalService, JoecalUploadRequest, Listeners, TransferEvent, UploadDialog, - error::Result, models::Device, -}; +use joecalsend::{JoecalService, JoecalUploadRequest, TransferEvent, UploadDialog, error::Result}; use julid::Julid; -use log::{LevelFilter, debug, error, info, warn}; -use ratatui::{DefaultTerminal, Frame, widgets::TableState}; -use tokio::{ - sync::mpsc::{UnboundedReceiver, unbounded_channel}, - task::JoinSet, -}; +use log::{LevelFilter, debug, error, warn}; +use ratatui::{Frame, widgets::TableState}; +use tokio::sync::mpsc::UnboundedReceiver; pub mod widgets; @@ -40,58 +34,6 @@ pub enum CurrentScreen { Logging, } -#[tokio::main] -pub async fn start_and_run( - terminal: &mut DefaultTerminal, - config: Config, - device: Device, -) -> Result<()> { - let (event_tx, event_listener) = unbounded_channel(); - - let service = JoecalService::new(device, event_tx) - .await - .expect("Could not create JoecalService"); - - let mut app = App::new(service, event_listener); - - let mut handles = JoinSet::new(); - app.service.start(&config, &mut handles).await; - loop { - terminal.draw(|frame| app.draw(frame))?; - app.handle_events().await?; - - if let Some(&top) = app.screen.last() - && top == CurrentScreen::Stopping - { - app.service.stop().await; - break; - } - - let peers = app.service.peers.lock().await; - app.peers.clear(); - peers.iter().for_each(|(fingerprint, (addr, device))| { - let alias = device.alias.clone(); - app.peers - .insert(addr.to_owned(), (alias, fingerprint.to_owned())); - }); - - let mut stale_uploads = Vec::new(); - let now = chrono::Utc::now().timestamp_millis() as u64; - for (id, request) in app.uploads.iter() { - if request.tx.is_closed() || (now - id.timestamp()) > 60_000 { - stale_uploads.push(*id); - } - } - for id in stale_uploads { - app.uploads.remove(&id); - } - } - - shutdown(&mut handles).await; - - Ok(()) -} - impl App { pub fn new(service: JoecalService, event_listener: UnboundedReceiver) -> Self { App { @@ -105,7 +47,7 @@ impl App { } } - async fn handle_events(&mut self) -> Result<()> { + pub async fn handle_events(&mut self) -> Result<()> { tokio::select! { event = self.events.next().fuse() => { if let Some(Ok(evt)) = event { @@ -138,7 +80,7 @@ impl App { Ok(()) } - fn handle_key_event(&mut self, key_event: KeyEvent) { + pub fn handle_key_event(&mut self, key_event: KeyEvent) { match self.screen.last().unwrap() { CurrentScreen::Logging => match key_event.code { KeyCode::Esc => self.pop(), @@ -167,7 +109,7 @@ impl App { } } - fn accept(&mut self) { + pub fn accept(&mut self) { let Some(idx) = self.upload_state.selected() else { return; }; @@ -185,7 +127,7 @@ impl App { }; } - fn deny(&mut self) { + pub fn deny(&mut self) { let Some(idx) = self.upload_state.selected() else { return; }; @@ -204,15 +146,15 @@ impl App { self.uploads.remove(key); } - fn draw(&mut self, frame: &mut Frame) { + pub fn draw(&mut self, frame: &mut Frame) { frame.render_widget(self, frame.area()); } - fn exit(&mut self) { + pub fn exit(&mut self) { self.screen.push(CurrentScreen::Stopping); } - fn send(&mut self) { + pub fn send(&mut self) { let last = self.screen.last(); match last { Some(CurrentScreen::Sending) => {} @@ -220,7 +162,7 @@ impl App { } } - fn recv(&mut self) { + pub fn recv(&mut self) { let last = self.screen.last(); match last { Some(CurrentScreen::Receiving) => {} @@ -228,7 +170,7 @@ impl App { } } - fn logs(&mut self) { + pub fn logs(&mut self) { let last = self.screen.last(); match last { Some(CurrentScreen::Logging) => {} @@ -236,7 +178,7 @@ impl App { } } - fn pop(&mut self) { + pub fn pop(&mut self) { self.screen.pop(); if self.screen.last().is_none() { self.screen.push(CurrentScreen::Main); @@ -253,26 +195,3 @@ fn change_log_level(delta: isize) { log::set_max_level(level); } - -async fn shutdown(handles: &mut JoinSet) { - let mut alarm = tokio::time::interval(tokio::time::Duration::from_secs(5)); - alarm.tick().await; - loop { - tokio::select! { - join_result = handles.join_next() => { - match join_result { - Some(handle) => match handle { - Ok(h) => info!("Stopped {h:?}"), - Err(e) => error!("Got error {e:?}"), - } - None => break, - } - } - _ = alarm.tick() => { - info!("Exit timeout reached, aborting all unjoined tasks"); - handles.abort_all(); - break; - }, - } - } -} diff --git a/src/discovery.rs b/src/discovery.rs index 77d49fb..c691c2b 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -9,7 +9,6 @@ use axum::{ extract::{ConnectInfo, State}, }; use log::{debug, error, trace, warn}; -use network_interface::{Addr, NetworkInterface, NetworkInterfaceConfig, V4IfAddr}; use tokio::net::UdpSocket; use crate::{Config, JoecalService, RunningState, models::Device}; diff --git a/src/main.rs b/src/main.rs index 9e2b506..6b26db0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ -use joecalsend::{Config, error, models::Device}; -use local_ip_address::local_ip; +use joecalsend::{Config, JoecalService, Listeners, error, models::Device}; +use log::{error, info}; +use ratatui::DefaultTerminal; +use tokio::{sync::mpsc::unbounded_channel, task::JoinSet}; use tui_logger::{LevelFilter, init_logger, set_env_filter_from_env}; mod app; +use app::{App, CurrentScreen}; fn main() -> error::Result<()> { let device = Device::default(); @@ -18,8 +21,83 @@ fn main() -> error::Result<()> { let config = Config::default(); let mut terminal = ratatui::init(); - let result = app::start_and_run(&mut terminal, config, device); + let result = start_and_run(&mut terminal, config, device); ratatui::restore(); result } + +#[tokio::main] +async fn start_and_run( + terminal: &mut DefaultTerminal, + config: Config, + device: Device, +) -> error::Result<()> { + let (event_tx, event_listener) = unbounded_channel(); + + let service = JoecalService::new(device, event_tx) + .await + .expect("Could not create JoecalService"); + + let mut app = App::new(service, event_listener); + + let mut handles = JoinSet::new(); + app.service.start(&config, &mut handles).await; + loop { + terminal.draw(|frame| app.draw(frame))?; + app.handle_events().await?; + + if let Some(&top) = app.screen.last() + && top == CurrentScreen::Stopping + { + app.service.stop().await; + break; + } + + let peers = app.service.peers.lock().await; + app.peers.clear(); + peers.iter().for_each(|(fingerprint, (addr, device))| { + let alias = device.alias.clone(); + app.peers + .insert(addr.to_owned(), (alias, fingerprint.to_owned())); + }); + + let mut stale_uploads = Vec::with_capacity(app.uploads.len()); + let now = chrono::Utc::now().timestamp_millis() as u64; + for (id, request) in app.uploads.iter() { + if request.tx.is_closed() || (now - id.timestamp()) > 60_000 { + stale_uploads.push(*id); + } + } + for id in stale_uploads { + app.uploads.remove(&id); + } + } + + shutdown(&mut handles).await; + + Ok(()) +} + +async fn shutdown(handles: &mut JoinSet) { + let mut alarm = tokio::time::interval(tokio::time::Duration::from_secs(5)); + alarm.tick().await; + loop { + tokio::select! { + join_result = handles.join_next() => { + match join_result { + Some(handle) => match handle { + Ok(h) => info!("Stopped {h:?}"), + Err(e) => error!("Got error {e:?}"), + } + None => break, + } + } + _ = alarm.tick() => { + info!("Exit timeout reached, aborting all unjoined tasks"); + handles.abort_all(); + break; + }, + } + } +}