got the streamed content data model correct

This commit is contained in:
Joe Ardent 2023-08-07 09:33:35 -07:00
parent 2b96b28db6
commit c2160b2218
5 changed files with 123 additions and 89 deletions

View file

@ -1,6 +1,3 @@
use godiva::{Message, MessageData};
fn main() { fn main() {
dbg!(std::mem::size_of::<MessageData>()); //
dbg!(std::mem::size_of::<Message>());
} }

38
src/desktop.rs Normal file
View file

@ -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);
});
}
}

View file

@ -3,16 +3,13 @@ use std::{
time::{Duration, Instant}, 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}; 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<u8>)>; pub type Receiver = std::sync::mpsc::Receiver<(usize, Vec<u8>)>;
pub type Sender = std::sync::mpsc::SyncSender<(usize, Vec<u8>)>; pub type Sender = std::sync::mpsc::SyncSender<(usize, Vec<u8>)>;
@ -24,13 +21,26 @@ pub struct Flasher {
pub content: Content, pub content: Content,
pub sleep: Duration, pub sleep: Duration,
pub last: Instant, pub last: Instant,
pub idx: usize,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum Content { pub enum Content {
Static(&'static [u8]), 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<usize>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StreamStatus {
Paused,
Streaming,
} }
#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
@ -40,72 +50,3 @@ pub struct TxConfig {
pub mtu: u16, pub mtu: u16,
pub description: String, pub description: String,
} }
pub fn stream_bytes(bytes: Vec<u8>, 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::<Vec<_>>();
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<u8> {
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);
});
}
}

View file

@ -4,7 +4,7 @@ use std::{
}; };
use clap::Parser; use clap::Parser;
use cuttle::{stream_bytes, Content, Flasher}; use cuttle::{stream_bytes, Content, Flasher, StreamStatus, StreamedContent};
use eframe::egui; use eframe::egui;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -45,7 +45,7 @@ fn main() -> Result<(), eframe::Error> {
"text message".to_string() "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 = 1000.0 / cli.fps as f64;
let sleep = Duration::from_millis(sleep as u64); let sleep = Duration::from_millis(sleep as u64);
@ -55,7 +55,6 @@ fn main() -> Result<(), eframe::Error> {
content, content,
sleep, sleep,
last, last,
idx: 0,
}; };
let options = eframe::NativeOptions { let options = eframe::NativeOptions {
@ -79,12 +78,19 @@ fn get_content(cli: &Cli, desc: &str) -> Content {
cli.text().join(" ").bytes().collect() 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(); let bytes = bytes.leak();
Content::Static(bytes) Content::Static(bytes)
} else { } else {
let (tx, rx) = std::sync::mpsc::sync_channel(2); let (tx, rx) = std::sync::mpsc::sync_channel(2);
stream_bytes(bytes, tx, desc.to_string()); let txconfig = stream_bytes(bytes, tx, desc.to_string()).leak();
Content::Streaming(rx)
let stream = StreamedContent {
txconfig,
rx,
status: StreamStatus::Paused,
last_packet: None,
};
Content::Streamed(stream)
} }
} }

52
src/util.rs Normal file
View file

@ -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<u8>, tx: Sender, desc: String) -> Vec<u8> {
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::<Vec<_>>();
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<u8> {
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()
}