got the streamed content data model correct
This commit is contained in:
parent
2b96b28db6
commit
c2160b2218
5 changed files with 123 additions and 89 deletions
|
@ -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
38
src/desktop.rs
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
99
src/lib.rs
99
src/lib.rs
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -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
52
src/util.rs
Normal 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()
|
||||||
|
}
|
Loading…
Reference in a new issue