diff --git a/examples/messages.rs b/examples/messages.rs index 226062f..b63fa40 100644 --- a/examples/messages.rs +++ b/examples/messages.rs @@ -1,6 +1,3 @@ -use godiva::{Message, MessageData}; - fn main() { - dbg!(std::mem::size_of::()); - dbg!(std::mem::size_of::()); + // } diff --git a/src/desktop.rs b/src/desktop.rs new file mode 100644 index 0000000..491d7a6 --- /dev/null +++ b/src/desktop.rs @@ -0,0 +1,38 @@ +use eframe::egui; +use egui_extras::RetainedImage; + +use crate::{mk_qr_bytes, Content, Flasher, StreamStatus}; + +impl eframe::App for Flasher { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + ctx.request_repaint_after(self.sleep); + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading(&self.heading); + let img = match self.content { + Content::Static(bytes) => { + RetainedImage::from_image_bytes("generated qr code", &mk_qr_bytes(bytes)) + .unwrap() + } + Content::Streamed(ref streaming_content) => match streaming_content.status { + StreamStatus::Paused => RetainedImage::from_image_bytes( + "tx config for receiver initialization", + &mk_qr_bytes(streaming_content.txconfig), + ) + .unwrap(), + StreamStatus::Streaming => { + if let Ok((_counter, ref bytes)) = streaming_content.rx.try_recv() { + RetainedImage::from_image_bytes( + "generated qr code", + &mk_qr_bytes(bytes), + ) + .unwrap() + } else { + return; + } + } + }, + }; + img.show(ui); + }); + } +} diff --git a/src/lib.rs b/src/lib.rs index 6a1e590..4a8664e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,16 +3,13 @@ use std::{ time::{Duration, Instant}, }; -#[cfg(feature = "desktop")] -use eframe::egui; -#[cfg(feature = "desktop")] -use egui_extras::RetainedImage; -use fast_qr::convert::image::ImageBuilder; -use rand::seq::SliceRandom; -use raptorq::{Encoder, ObjectTransmissionInformation}; use rkyv::{Archive, Deserialize, Serialize}; -pub const STREAMING_MTU: u16 = 2326; +#[cfg(feature = "desktop")] +mod desktop; +mod util; + +pub use util::{mk_qr_bytes, stream_bytes}; pub type Receiver = std::sync::mpsc::Receiver<(usize, Vec)>; pub type Sender = std::sync::mpsc::SyncSender<(usize, Vec)>; @@ -24,13 +21,26 @@ pub struct Flasher { pub content: Content, pub sleep: Duration, pub last: Instant, - pub idx: usize, } #[derive(Debug)] pub enum Content { Static(&'static [u8]), - Streaming(Receiver), + Streamed(StreamedContent), +} + +#[derive(Debug)] +pub struct StreamedContent { + pub txconfig: &'static [u8], + pub rx: Receiver, + pub status: StreamStatus, + pub last_packet: Option, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum StreamStatus { + Paused, + Streaming, } #[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)] @@ -40,72 +50,3 @@ pub struct TxConfig { pub mtu: u16, pub description: String, } - -pub fn stream_bytes(bytes: Vec, tx: Sender, desc: String) { - std::thread::spawn(move || { - let rng = &mut rand::thread_rng(); - - let len = bytes.len() as u64; - let txconfig = TxConfig { - len, - mtu: STREAMING_MTU, - description: desc.to_string(), - }; - let txconfig = - rkyv::to_bytes::<_, 256>(&txconfig).expect("tried to serialize the txconfig"); - - let config = ObjectTransmissionInformation::with_defaults(len, STREAMING_MTU); - let encoder = Encoder::new(&bytes, config); - let mut packets = encoder - .get_encoded_packets(10) - .iter() - .map(|p| p.serialize()) - .collect::>(); - - let txcfgs = vec![txconfig.to_vec(); packets.len() / 10]; - packets.extend(txcfgs); - - packets.shuffle(rng); - - for (counter, packet) in packets.iter().cycle().enumerate() { - tx.send((counter, packet.clone())).unwrap(); - } - }); -} - -pub fn mk_img(bytes: &[u8]) -> Vec { - let qr = fast_qr::QRBuilder::new(bytes) - .ecl(fast_qr::ECL::M) - .build() - .unwrap(); - - ImageBuilder::default() - .fit_width(1100) - .to_pixmap(&qr) - .encode_png() - .unwrap() -} - -#[cfg(feature = "desktop")] -impl eframe::App for Flasher { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - ctx.request_repaint_after(self.sleep); - egui::CentralPanel::default().show(ctx, |ui| { - ui.heading(&self.heading); - let img = match self.content { - Content::Static(bytes) => { - RetainedImage::from_image_bytes("generated qr code", &mk_img(bytes)).unwrap() - } - Content::Streaming(ref rx) => { - if let Ok((_counter, ref bytes)) = rx.try_recv() { - RetainedImage::from_image_bytes("generated qr code", &mk_img(bytes)) - .unwrap() - } else { - return; - } - } - }; - img.show(ui); - }); - } -} diff --git a/src/main.rs b/src/main.rs index 9d22780..c8ea841 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use std::{ }; use clap::Parser; -use cuttle::{stream_bytes, Content, Flasher}; +use cuttle::{stream_bytes, Content, Flasher, StreamStatus, StreamedContent}; use eframe::egui; #[derive(Parser, Debug)] @@ -45,7 +45,7 @@ fn main() -> Result<(), eframe::Error> { "text message".to_string() }; - let content: Content = get_content(&cli, &description); + let content = get_content(&cli, &description); let sleep = 1000.0 / cli.fps as f64; let sleep = Duration::from_millis(sleep as u64); @@ -55,7 +55,6 @@ fn main() -> Result<(), eframe::Error> { content, sleep, last, - idx: 0, }; let options = eframe::NativeOptions { @@ -79,12 +78,19 @@ fn get_content(cli: &Cli, desc: &str) -> Content { cli.text().join(" ").bytes().collect() }; - if bytes.len() < 1700 && fast_qr::QRBuilder::new(bytes.clone()).build().is_ok() { + if bytes.len() < 2000 && fast_qr::QRBuilder::new(bytes.clone()).build().is_ok() { let bytes = bytes.leak(); Content::Static(bytes) } else { let (tx, rx) = std::sync::mpsc::sync_channel(2); - stream_bytes(bytes, tx, desc.to_string()); - Content::Streaming(rx) + let txconfig = stream_bytes(bytes, tx, desc.to_string()).leak(); + + let stream = StreamedContent { + txconfig, + rx, + status: StreamStatus::Paused, + last_packet: None, + }; + Content::Streamed(stream) } } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..7d16163 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,52 @@ +use fast_qr::convert::image::ImageBuilder; +use rand::seq::SliceRandom; +use raptorq::{Encoder, ObjectTransmissionInformation}; + +use crate::{Sender, TxConfig}; + +pub const STREAMING_MTU: u16 = 2326; + +pub fn stream_bytes(bytes: Vec, tx: Sender, desc: String) -> Vec { + let len = bytes.len() as u64; + let txconfig = TxConfig { + len, + mtu: STREAMING_MTU, + description: desc.to_string(), + }; + let txconfig = rkyv::to_bytes::<_, 256>(&txconfig) + .expect("tried to serialize the txconfig") + .to_vec(); + + std::thread::spawn(move || { + let rng = &mut rand::thread_rng(); + + let config = ObjectTransmissionInformation::with_defaults(len, STREAMING_MTU); + let encoder = Encoder::new(&bytes, config); + let mut packets = encoder + .get_encoded_packets(10) + .iter() + .map(|p| p.serialize()) + .collect::>(); + + packets.shuffle(rng); + + for (counter, packet) in packets.iter().cycle().enumerate() { + tx.send((counter, packet.clone())).unwrap(); + } + }); + txconfig +} + +/// Makes a PNG of a QR code for the given bytes, returns the bytes of the PNG. +pub fn mk_qr_bytes(bytes: &[u8]) -> Vec { + let qr = fast_qr::QRBuilder::new(bytes) + .ecl(fast_qr::ECL::M) + .build() + .unwrap(); + + ImageBuilder::default() + .fit_width(1100) + .to_pixmap(&qr) + .encode_png() + .unwrap() +}