aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-04 18:14:25 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-04 18:14:25 -0500
commitb0a1a43f0f40e00b89747b42bd2d95b67c88087b (patch)
treeafa030ad33800b2c55d01ddb53aa7f00dbb9bc81
parent3040c683c4a0f50b97cf968da847859a8ef45151 (diff)
downloadttyrec-bin-b0a1a43f0f40e00b89747b42bd2d95b67c88087b.tar.gz
ttyrec-bin-b0a1a43f0f40e00b89747b42bd2d95b67c88087b.zip
refactor
-rw-r--r--src/bin/ttyplay/main.rs187
1 files changed, 142 insertions, 45 deletions
diff --git a/src/bin/ttyplay/main.rs b/src/bin/ttyplay/main.rs
index 296fdc0..de6dc26 100644
--- a/src/bin/ttyplay/main.rs
+++ b/src/bin/ttyplay/main.rs
@@ -13,11 +13,135 @@ struct Frame {
delay: std::time::Duration,
}
+struct FrameData {
+ frames: Vec<Frame>,
+ done_reading: bool,
+ new_frame_w: async_std::channel::Sender<Option<usize>>,
+ new_frame_r: async_std::channel::Receiver<Option<usize>>,
+}
+
+impl FrameData {
+ fn new() -> Self {
+ let (new_frame_w, new_frame_r) = async_std::channel::unbounded();
+ Self {
+ frames: vec![],
+ done_reading: false,
+ new_frame_w,
+ new_frame_r,
+ }
+ }
+
+ fn get(&self, i: usize) -> Option<&Frame> {
+ self.frames.get(i)
+ }
+
+ async fn add_frame(&mut self, frame: Frame) {
+ self.frames.push(frame);
+ self.new_frame_w
+ .send(Some(self.frames.len()))
+ .await
+ .unwrap()
+ }
+
+ async fn done_reading(&mut self) {
+ self.done_reading = true;
+ self.new_frame_w.send(None).await.unwrap();
+ }
+
+ fn wait_for_frame(
+ &self,
+ i: usize,
+ ) -> std::pin::Pin<
+ Box<dyn std::future::Future<Output = bool> + 'static + Send>,
+ > {
+ if i < self.frames.len() {
+ return Box::pin(std::future::ready(true));
+ }
+ let new_frame_r = self.new_frame_r.clone();
+ Box::pin(async move {
+ while let Some(new_len) = new_frame_r.recv().await.unwrap() {
+ if i < new_len {
+ return true;
+ }
+ }
+ false
+ })
+ }
+}
+
+enum Event {
+ Render { screen: vt100::Screen },
+ Quit,
+}
+
+enum TimerAction {
+ Pause,
+ NewFrameRead,
+}
+
+fn spawn_frame_reader_task(
+ frames: async_std::sync::Arc<async_std::sync::Mutex<FrameData>>,
+ size: (u16, u16),
+ fh: async_std::fs::File,
+) {
+ async_std::task::spawn(async move {
+ let mut reader = ttyrec::Reader::new(fh);
+ let mut parser = vt100::Parser::new(size.0, size.1, 0);
+ while let Ok(frame) = reader.read_frame().await {
+ let delay = if let Some(time) = reader.offset() {
+ frame.time - time
+ } else {
+ std::time::Duration::from_secs(0)
+ };
+ parser.process(&frame.data);
+ frames
+ .lock_arc()
+ .await
+ .add_frame(Frame {
+ screen: parser.screen().clone(),
+ delay,
+ })
+ .await;
+ }
+ frames.lock_arc().await.done_reading().await;
+ });
+}
+
+fn spawn_timer_task(
+ frames: async_std::sync::Arc<async_std::sync::Mutex<FrameData>>,
+ timer_r: async_std::channel::Receiver<TimerAction>,
+ event_w: async_std::channel::Sender<Event>,
+) {
+ async_std::task::spawn(async move {
+ let mut idx = 0;
+ let start_time = std::time::Instant::now();
+ loop {
+ let wait = frames.lock_arc().await.wait_for_frame(idx);
+ if !wait.await {
+ break;
+ }
+ let frame = frames.lock_arc().await.get(idx).unwrap().clone();
+ async_std::task::sleep(
+ (start_time + frame.delay)
+ .saturating_duration_since(std::time::Instant::now()),
+ )
+ .await;
+ event_w
+ .send(Event::Render {
+ screen: frame.screen,
+ })
+ .await
+ .unwrap();
+ idx += 1;
+ }
+ event_w.send(Event::Quit).await.unwrap();
+ });
+}
+
async fn async_main(opt: Opt) -> anyhow::Result<()> {
let Opt { file } = opt;
let fh = async_std::fs::File::open(file).await?;
- let mut reader = ttyrec::Reader::new(fh);
let size = terminal_size::terminal_size().map_or(
(24, 80),
|(terminal_size::Width(w), terminal_size::Height(h))| (h, w),
@@ -28,53 +152,26 @@ async fn async_main(opt: Opt) -> anyhow::Result<()> {
let _input_guard = input.take_raw_guard();
let _output_guard = output.take_screen_guard();
- let frames =
- async_std::sync::Arc::new(async_std::sync::Mutex::new(vec![]));
- let (frame_count_w, frame_count_r) = async_std::channel::unbounded();
-
- {
- let frames = frames.clone();
- async_std::task::spawn(async move {
- let mut parser = vt100::Parser::new(size.0, size.1, 0);
- while let Ok(frame) = reader.read_frame().await {
- let delay = if let Some(time) = reader.offset() {
- frame.time - time
- } else {
- std::time::Duration::from_secs(0)
- };
- parser.process(&frame.data);
- let mut frames = frames.lock_arc().await;
- frames.push(Frame {
- screen: parser.screen().clone(),
- delay,
- });
- frame_count_w.send(Some(frames.len())).await.unwrap();
- }
- frame_count_w.send(None).await.unwrap();
- });
- }
+ let frames = async_std::sync::Arc::new(async_std::sync::Mutex::new(
+ FrameData::new(),
+ ));
+ let (event_w, event_r) = async_std::channel::unbounded();
+ let (timer_w, timer_r) = async_std::channel::unbounded();
+
+ spawn_frame_reader_task(frames.clone(), size, fh);
+ spawn_timer_task(frames.clone(), timer_r, event_w.clone());
- let start_time = std::time::Instant::now();
- let mut idx = 0;
- let mut prev_frame: Option<Frame> = None;
loop {
- frame_count_r.recv().await?;
- let frame = if let Some(frame) = frames.lock_arc().await.get(idx) {
- frame.clone()
- } else {
- break;
- };
- if let Some(prev_frame) = prev_frame {
- let dur = (start_time + frame.delay)
- .saturating_duration_since(std::time::Instant::now());
- async_std::task::sleep(dur).await;
- output.write(&frame.screen.contents_diff(&prev_frame.screen));
- } else {
- output.write(&frame.screen.contents_formatted());
+ let event = event_r.recv().await?;
+ match event {
+ Event::Render { screen } => {
+ output.clear();
+ output.move_to(0, 0);
+ output.write(&screen.contents_formatted());
+ output.refresh().await?;
+ }
+ Event::Quit => break,
}
- output.refresh().await?;
- idx += 1;
- prev_frame = Some(frame);
}
Ok(())