adds preliminary sending, but seems to hang

This commit is contained in:
Joe Ardent 2025-08-03 15:06:39 -07:00
parent 6d21fa908c
commit 58fca36bd8
3 changed files with 76 additions and 53 deletions

View file

@ -67,7 +67,7 @@ impl App {
match evt { match evt {
Event::Key(key) Event::Key(key)
if key.kind == KeyEventKind::Press if key.kind == KeyEventKind::Press
=> self.handle_key_event(key, evt), => self.handle_key_event(key, evt).await,
Event::Mouse(_) => {} Event::Mouse(_) => {}
Event::Resize(_, _) => {} Event::Resize(_, _) => {}
_ => {} _ => {}
@ -93,7 +93,7 @@ impl App {
Ok(()) Ok(())
} }
pub fn handle_key_event(&mut self, key_event: KeyEvent, event: crossterm::event::Event) { pub async fn handle_key_event(&mut self, key_event: KeyEvent, event: crossterm::event::Event) {
match self.screen.last_mut().unwrap() { match self.screen.last_mut().unwrap() {
CurrentScreen::Logging => match key_event.code { CurrentScreen::Logging => match key_event.code {
KeyCode::Esc => self.pop(), KeyCode::Esc => self.pop(),
@ -116,14 +116,14 @@ impl App {
KeyCode::Esc => self.pop(), KeyCode::Esc => self.pop(),
KeyCode::Char('q') => self.exit(), KeyCode::Char('q') => self.exit(),
KeyCode::Tab => *s = SendingScreen::Peers, KeyCode::Tab => *s = SendingScreen::Peers,
KeyCode::Enter => todo!("send the selected file or enter directory"), KeyCode::Enter => self.send_content().await,
_ => self.file_picker.handle(&event).unwrap_or_default(), _ => self.file_picker.handle(&event).unwrap_or_default(),
}, },
SendingScreen::Peers => match key_event.code { SendingScreen::Peers => match key_event.code {
KeyCode::Esc => self.pop(), KeyCode::Esc => self.pop(),
KeyCode::Char('q') => self.exit(), KeyCode::Char('q') => self.exit(),
KeyCode::Tab => *s = SendingScreen::Files, KeyCode::Tab => *s = SendingScreen::Files,
KeyCode::Enter => todo!("send to the selected peer"), KeyCode::Enter => self.send_content().await,
_ => {} _ => {}
}, },
SendingScreen::Text => {} SendingScreen::Text => {}
@ -139,43 +139,6 @@ impl App {
} }
} }
pub fn accept(&mut self) {
let Some(idx) = self.receiving_state.selected() else {
return;
};
// keys are sorted, so we can use the table selection index
let keys: Vec<_> = self.receive_requests.keys().collect();
let Some(key) = keys.get(idx) else {
warn!("could not get id from selection index {idx}");
return;
};
let Some(req) = self.receive_requests.get(key) else {
return;
};
if let Err(e) = req.tx.send(ReceiveDialog::Approve) {
error!("got error sending upload confirmation: {e:?}");
};
}
pub fn deny(&mut self) {
let Some(idx) = self.receiving_state.selected() else {
return;
};
// keys are sorted, so we can use the table selection index
let keys: Vec<_> = self.receive_requests.keys().cloned().collect();
let Some(key) = keys.get(idx) else {
warn!("could not get id from selection index {idx}");
return;
};
let Some(req) = self.receive_requests.get(key).cloned() else {
return;
};
if let Err(e) = req.tx.send(ReceiveDialog::Deny) {
error!("got error sending upload confirmation: {e:?}");
};
self.receive_requests.remove(key);
}
pub fn draw(&mut self, frame: &mut Frame) { pub fn draw(&mut self, frame: &mut Frame) {
frame.render_widget(self, frame.area()); frame.render_widget(self, frame.area());
} }
@ -216,6 +179,66 @@ impl App {
self.screen.push(CurrentScreen::Main); self.screen.push(CurrentScreen::Main);
} }
} }
// accept a content receive request
fn accept(&mut self) {
let Some(idx) = self.receiving_state.selected() else {
return;
};
// keys are sorted, so we can use the table selection index
let keys: Vec<_> = self.receive_requests.keys().collect();
let Some(key) = keys.get(idx) else {
warn!("could not get id from selection index {idx}");
return;
};
let Some(req) = self.receive_requests.get(key) else {
return;
};
if let Err(e) = req.tx.send(ReceiveDialog::Approve) {
error!("got error sending upload confirmation: {e:?}");
};
}
// reject an content receive request
fn deny(&mut self) {
let Some(idx) = self.receiving_state.selected() else {
return;
};
// keys are sorted, so we can use the table selection index
let keys: Vec<_> = self.receive_requests.keys().cloned().collect();
let Some(key) = keys.get(idx) else {
warn!("could not get id from selection index {idx}");
return;
};
let Some(req) = self.receive_requests.get(key).cloned() else {
return;
};
if let Err(e) = req.tx.send(ReceiveDialog::Deny) {
error!("got error sending upload confirmation: {e:?}");
};
self.receive_requests.remove(key);
}
// send content to selected peer, or change directories in the file explorer
async fn send_content(&mut self) {
if let Some(_bytes) = self.content.iter().next().cloned() {
// self.service.send_bytes(session_id, content_id, token, body)
warn!("entering text is not yet supported");
} else {
let file = self.file_picker.current().path().clone();
if file.is_dir()
&& let Err(e) = self.file_picker.set_cwd(&file)
{
error!("could not list directory {file:?}: {e}");
} else if let Some((peer, _)) = self.service.peers.lock().await.first_key_value()
&& file.is_file()
&& let Err(e) = self.service.send_file(peer.to_owned(), file.clone()).await
{
error!("got error sending content: {e:?}");
}
}
}
} }
fn change_log_level(delta: isize) { fn change_log_level(delta: isize) {

View file

@ -5,7 +5,7 @@ pub mod models;
pub mod transfer; pub mod transfer;
use std::{ use std::{
collections::HashMap, collections::BTreeMap,
net::{Ipv4Addr, SocketAddr, SocketAddrV4}, net::{Ipv4Addr, SocketAddr, SocketAddrV4},
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
@ -54,7 +54,7 @@ pub enum TransferEvent {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ReceiveRequest { pub struct ReceiveRequest {
pub alias: String, pub alias: String,
pub files: HashMap<String, FileMetadata>, pub files: BTreeMap<String, FileMetadata>,
pub tx: UnboundedSender<ReceiveDialog>, pub tx: UnboundedSender<ReceiveDialog>,
} }
@ -62,8 +62,8 @@ pub struct ReceiveRequest {
#[derive(Clone)] #[derive(Clone)]
pub struct JoecalService { pub struct JoecalService {
pub device: Device, pub device: Device,
pub peers: Arc<Mutex<HashMap<String, (SocketAddr, Device)>>>, pub peers: Arc<Mutex<BTreeMap<String, (SocketAddr, Device)>>>,
pub sessions: Arc<Mutex<HashMap<String, Session>>>, // Session ID to Session pub sessions: Arc<Mutex<BTreeMap<String, Session>>>, // Session ID to Session
pub running_state: Arc<Mutex<RunningState>>, pub running_state: Arc<Mutex<RunningState>>,
pub socket: Arc<UdpSocket>, pub socket: Arc<UdpSocket>,
pub client: reqwest::Client, pub client: reqwest::Client,

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, net::SocketAddr, path::PathBuf}; use std::{collections::BTreeMap, net::SocketAddr, path::PathBuf};
use axum::{ use axum::{
Json, Json,
@ -21,8 +21,8 @@ use crate::{
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Session { pub struct Session {
pub session_id: String, pub session_id: String,
pub files: HashMap<String, FileMetadata>, pub files: BTreeMap<String, FileMetadata>,
pub file_tokens: HashMap<String, String>, pub file_tokens: BTreeMap<String, String>,
pub receiver: Device, pub receiver: Device,
pub sender: Device, pub sender: Device,
pub status: SessionStatus, pub status: SessionStatus,
@ -42,21 +42,21 @@ pub enum SessionStatus {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct PrepareUploadResponse { pub struct PrepareUploadResponse {
pub session_id: String, pub session_id: String,
pub files: HashMap<String, String>, pub files: BTreeMap<String, String>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct PrepareUploadRequest { pub struct PrepareUploadRequest {
pub info: Device, pub info: Device,
pub files: HashMap<String, FileMetadata>, pub files: BTreeMap<String, FileMetadata>,
} }
impl JoecalService { impl JoecalService {
pub async fn prepare_upload( pub async fn prepare_upload(
&self, &self,
peer: String, peer: String,
files: HashMap<String, FileMetadata>, files: BTreeMap<String, FileMetadata>,
) -> Result<PrepareUploadResponse> { ) -> Result<PrepareUploadResponse> {
if !self.peers.lock().await.contains_key(&peer) { if !self.peers.lock().await.contains_key(&peer) {
return Err(LocalSendError::PeerNotFound); return Err(LocalSendError::PeerNotFound);
@ -140,7 +140,7 @@ impl JoecalService {
let file_metadata = FileMetadata::from_path(&file_path)?; let file_metadata = FileMetadata::from_path(&file_path)?;
// Prepare files map // Prepare files map
let mut files = HashMap::new(); let mut files = BTreeMap::new();
files.insert(file_metadata.id.clone(), file_metadata.clone()); files.insert(file_metadata.id.clone(), file_metadata.clone());
// Prepare upload // Prepare upload
@ -227,7 +227,7 @@ pub async fn prepare_upload(
let session_id = id.as_string(); let session_id = id.as_string();
let file_tokens: HashMap<String, String> = req let file_tokens: BTreeMap<String, String> = req
.files .files
.keys() .keys()
.map(|id| (id.clone(), Julid::new().to_string())) // Replace with actual token logic .map(|id| (id.clone(), Julid::new().to_string())) // Replace with actual token logic