better peer selection
This commit is contained in:
parent
2ff3e3971d
commit
358b96a744
5 changed files with 77 additions and 27 deletions
|
@ -6,20 +6,29 @@ use futures::{FutureExt, StreamExt};
|
|||
use joecalsend::{JoecalService, ReceiveDialog, ReceiveRequest, TransferEvent, error::Result};
|
||||
use julid::Julid;
|
||||
use log::{LevelFilter, debug, error, warn};
|
||||
use ratatui::{Frame, widgets::TableState};
|
||||
use ratatui::{
|
||||
Frame,
|
||||
widgets::{ListState, TableState},
|
||||
};
|
||||
use ratatui_explorer::FileExplorer;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
|
||||
pub mod widgets;
|
||||
|
||||
pub type Peers = BTreeMap<SocketAddr, (String, String)>;
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Peer {
|
||||
pub alias: String,
|
||||
pub fingerprint: String,
|
||||
pub addr: SocketAddr,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub service: JoecalService,
|
||||
pub screen: Vec<CurrentScreen>,
|
||||
pub events: EventStream,
|
||||
// addr -> (alias, fingerprint)
|
||||
pub peers: Peers,
|
||||
pub peers: Vec<Peer>,
|
||||
pub peer_state: ListState,
|
||||
pub receive_requests: BTreeMap<Julid, ReceiveRequest>,
|
||||
receiving_state: TableState,
|
||||
// for getting messages back from the web server or web client about things we've done; the
|
||||
|
@ -55,6 +64,7 @@ impl App {
|
|||
content: None,
|
||||
events: Default::default(),
|
||||
peers: Default::default(),
|
||||
peer_state: Default::default(),
|
||||
receive_requests: Default::default(),
|
||||
receiving_state: Default::default(),
|
||||
}
|
||||
|
@ -124,6 +134,8 @@ impl App {
|
|||
KeyCode::Char('q') => self.exit(),
|
||||
KeyCode::Tab => *s = SendingScreen::Files,
|
||||
KeyCode::Enter => self.send_content().await,
|
||||
KeyCode::Up => self.peer_state.select_previous(),
|
||||
KeyCode::Down => self.peer_state.select_next(),
|
||||
_ => {}
|
||||
},
|
||||
SendingScreen::Text => {}
|
||||
|
@ -234,11 +246,16 @@ impl App {
|
|||
error!("could not list directory {file:?}: {e}");
|
||||
}
|
||||
|
||||
if let Some((_, (_, peer))) = self.peers.first_key_value()
|
||||
if let Some(idx) = self.peer_state.selected()
|
||||
&& let Some(peer) = self.peers.get(idx)
|
||||
&& file.is_file()
|
||||
{
|
||||
debug!("sending {file:?}");
|
||||
if let Err(e) = self.service.send_file(peer.to_owned(), file.clone()).await {
|
||||
if let Err(e) = self
|
||||
.service
|
||||
.send_file(&peer.fingerprint, file.clone())
|
||||
.await
|
||||
{
|
||||
error!("got error sending content: {e:?}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,14 @@ use ratatui::{
|
|||
style::{Color, Style, Stylize},
|
||||
symbols::border,
|
||||
text::{Line, Text, ToLine},
|
||||
widgets::{Block, Borders, List, ListItem, Padding, Paragraph, Row, Table, TableState, Widget},
|
||||
widgets::{
|
||||
Block, Borders, List, ListItem, ListState, Padding, Paragraph, Row, Table, TableState,
|
||||
Widget,
|
||||
},
|
||||
};
|
||||
use tui_logger::{TuiLoggerLevelOutput, TuiLoggerWidget, TuiWidgetState};
|
||||
|
||||
use super::{App, CurrentScreen, Peers, SendingScreen};
|
||||
use super::{App, CurrentScreen, Peer, SendingScreen};
|
||||
|
||||
static MAIN_MENU: LazyLock<Line> = LazyLock::new(|| {
|
||||
Line::from(vec![
|
||||
|
@ -126,7 +129,12 @@ impl Widget for &mut App {
|
|||
outer_frame(*current_screen, &MAIN_MENU, area, buf);
|
||||
logger(header_right.inner(header_margin), buf);
|
||||
let peers = PeersWidget { peers: &self.peers };
|
||||
peers.render(footer_right.inner(footer_margin), buf);
|
||||
ratatui::widgets::StatefulWidget::render(
|
||||
peers,
|
||||
footer_right.inner(footer_margin),
|
||||
buf,
|
||||
&mut self.peer_state,
|
||||
);
|
||||
NetworkInfoWidget.render(footer_left.inner(footer_margin), buf);
|
||||
receive_requests(
|
||||
&rx_reqs,
|
||||
|
@ -168,7 +176,12 @@ impl Widget for &mut App {
|
|||
.render(header_left.inner(header_margin), buf);
|
||||
logger(header_right.inner(header_margin), buf);
|
||||
|
||||
peers.render(bottom.inner(subscreen_margin), buf);
|
||||
ratatui::widgets::StatefulWidget::render(
|
||||
peers,
|
||||
bottom.inner(subscreen_margin),
|
||||
buf,
|
||||
&mut self.peer_state,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
outer_frame(*current_screen, &MAIN_MENU, area, buf);
|
||||
|
@ -261,19 +274,32 @@ fn receive_requests(
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PeersWidget<'p> {
|
||||
pub peers: &'p Peers,
|
||||
pub peers: &'p [Peer],
|
||||
}
|
||||
|
||||
impl<'p> Widget for PeersWidget<'p> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer)
|
||||
impl<'p> ratatui::widgets::StatefulWidget for PeersWidget<'p> {
|
||||
type State = ListState;
|
||||
|
||||
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let mut items = Vec::with_capacity(self.peers.len());
|
||||
for (k, v) in self.peers.iter() {
|
||||
let item = format!("{:?}: {} ({})", k, v.0, v.1);
|
||||
let s = Line::from(item.yellow());
|
||||
if self.peers.is_empty() {
|
||||
state.select(None);
|
||||
}
|
||||
if state.selected().is_none() {
|
||||
state.select(Some(0));
|
||||
}
|
||||
|
||||
let mut items = Vec::with_capacity(self.peers.len());
|
||||
for Peer {
|
||||
addr,
|
||||
alias,
|
||||
fingerprint,
|
||||
} in self.peers.iter()
|
||||
{
|
||||
let item = format!("{:?}: {} ({})", addr, alias, fingerprint);
|
||||
let s = Line::from(item.yellow());
|
||||
let item = ListItem::new(s);
|
||||
items.push(item);
|
||||
}
|
||||
|
@ -282,8 +308,10 @@ impl<'p> Widget for PeersWidget<'p> {
|
|||
.title(title)
|
||||
.borders(Borders::all())
|
||||
.padding(Padding::uniform(1));
|
||||
let list = List::new(items).block(block);
|
||||
list.render(area, buf);
|
||||
let list = List::new(items)
|
||||
.block(block)
|
||||
.highlight_style(Style::new().bg(Color::Rgb(99, 99, 99)));
|
||||
ratatui::widgets::StatefulWidget::render(list, area, buf, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ impl JoecalService {
|
|||
socket.join_multicast_v4(MULTICAST_IP, Ipv4Addr::from_bits(0))?;
|
||||
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
// localsend certs are self-signed
|
||||
.danger_accept_invalid_certs(true)
|
||||
.build()?;
|
||||
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -5,7 +5,7 @@ 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};
|
||||
use app::{App, CurrentScreen, Peer};
|
||||
|
||||
fn main() -> error::Result<()> {
|
||||
let device = Device::default();
|
||||
|
@ -58,18 +58,22 @@ async fn start_and_run(
|
|||
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 peer = Peer {
|
||||
alias,
|
||||
fingerprint: fingerprint.to_owned(),
|
||||
addr: addr.to_owned(),
|
||||
};
|
||||
app.peers.push(peer);
|
||||
});
|
||||
|
||||
let mut stale_uploads = Vec::with_capacity(app.receive_requests.len());
|
||||
let mut stale_rx_requests = Vec::with_capacity(app.receive_requests.len());
|
||||
let now = chrono::Utc::now().timestamp_millis() as u64;
|
||||
for (id, request) in app.receive_requests.iter() {
|
||||
if request.tx.is_closed() || (now - id.timestamp()) > 60_000 {
|
||||
stale_uploads.push(*id);
|
||||
stale_rx_requests.push(*id);
|
||||
}
|
||||
}
|
||||
for id in stale_uploads {
|
||||
for id in stale_rx_requests {
|
||||
app.receive_requests.remove(&id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,10 +55,10 @@ pub struct PrepareUploadRequest {
|
|||
impl JoecalService {
|
||||
pub async fn prepare_upload(
|
||||
&self,
|
||||
peer: String,
|
||||
peer: &str,
|
||||
files: BTreeMap<String, FileMetadata>,
|
||||
) -> Result<PrepareUploadResponse> {
|
||||
let Some((addr, device)) = self.peers.lock().await.get(&peer).cloned() else {
|
||||
let Some((addr, device)) = self.peers.lock().await.get(peer).cloned() else {
|
||||
return Err(LocalSendError::PeerNotFound);
|
||||
};
|
||||
|
||||
|
@ -135,7 +135,7 @@ impl JoecalService {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_file(&self, peer: String, file_path: PathBuf) -> Result<()> {
|
||||
pub async fn send_file(&self, peer: &str, file_path: PathBuf) -> Result<()> {
|
||||
// Generate file metadata
|
||||
let file_metadata = FileMetadata::from_path(&file_path)?;
|
||||
|
||||
|
|
Loading…
Reference in a new issue