From 35b053be79445c5e6af4423b8d316d4c15c0f5ca Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Mon, 4 Aug 2025 10:52:58 -0700 Subject: [PATCH] can send text, needs a ui to enter it --- src/app/mod.rs | 16 ++++++++++------ src/models.rs | 18 ++++++++++++++++++ src/transfer.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index ca7379c..5a06ad5 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,6 +1,5 @@ use std::{collections::BTreeMap, net::SocketAddr, time::Duration}; -use axum::body::Bytes; use crossterm::event::{Event, EventStream, KeyCode, KeyEvent, KeyEventKind}; use futures::{FutureExt, StreamExt}; use joecalsend::{JoecalService, ReceiveDialog, ReceiveRequest, TransferEvent, error::Result}; @@ -35,7 +34,7 @@ pub struct App { // other end is held by the service event_listener: UnboundedReceiver, file_picker: FileExplorer, - content: Option, + text: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -61,7 +60,7 @@ impl App { event_listener, screen: vec![CurrentScreen::Main], file_picker: FileExplorer::new().expect("could not create file explorer"), - content: None, + text: Some("this is content".to_string()), events: Default::default(), peers: Default::default(), peer_state: Default::default(), @@ -235,9 +234,14 @@ impl App { async fn send_content(&mut self) { debug!("sending content"); - if let Some(_bytes) = self.content.to_owned() { - // self.service.send_bytes(session_id, content_id, token, body) - warn!("entering text is not yet supported"); + if let Some(text) = self.text.to_owned() { + if let Some(idx) = self.peer_state.selected() + && let Some(peer) = self.peers.get(idx) + { + if let Err(e) = self.service.send_text(&peer.fingerprint, &text).await { + error!("got error sending \"{text}\" to {}: {e:?}", peer.alias); + } + } } else { let file = self.file_picker.current().path().clone(); if file.is_dir() diff --git a/src/models.rs b/src/models.rs index 4b3db83..4dccbba 100644 --- a/src/models.rs +++ b/src/models.rs @@ -62,6 +62,24 @@ impl FileMetadata { metadata, }) } + + pub fn from_text(text: &str) -> Self { + let id = Julid::new().as_string(); + let size = text.as_bytes().len() as u64; + + let file_type = "text/plain".into(); + let sha256 = Some(sha256::digest(text)); + + FileMetadata { + id, + file_name: "".to_string(), + size, + file_type, + sha256, + preview: Some(text.to_string()), + metadata: None, + } + } } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/src/transfer.rs b/src/transfer.rs index 4c8fb94..dcf7c3a 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -168,6 +168,37 @@ impl JoecalService { Ok(()) } + pub async fn send_text(&self, peer: &str, text: &str) -> Result<()> { + // Generate file metadata + let file_metadata = FileMetadata::from_text(text); + + // Prepare files map + let mut files = BTreeMap::new(); + files.insert(file_metadata.id.clone(), file_metadata.clone()); + + // Prepare upload + let prepare_response = self.prepare_upload(peer, files).await?; + + // Get file token + let token = prepare_response + .files + .get(&file_metadata.id) + .ok_or(LocalSendError::InvalidToken)?; + + let bytes = Bytes::from(text.to_owned()); + + // Upload file + self.send_bytes( + prepare_response.session_id, + file_metadata.id, + token.clone(), + bytes, + ) + .await?; + + Ok(()) + } + pub async fn cancel_upload(&self, session_id: String) -> Result<()> { let sessions = self.sessions.lock().await; let session = sessions.get(&session_id).unwrap();