New implementation of play command (basic version)

This commit is contained in:
Marcin Kulik
2024-01-02 16:06:43 +01:00
parent 58b3d567c3
commit 6e380cf245
4 changed files with 55 additions and 7 deletions

View File

@@ -1,5 +1,7 @@
use crate::player;
use anyhow::Result;
use clap::Args;
use std::fs;
#[derive(Debug, Args)]
pub struct Cli {
@@ -24,6 +26,8 @@ pub struct Cli {
impl Cli {
pub fn run(self) -> Result<()> {
todo!();
let file = fs::File::open(self.filename)?;
player::play(file)
}
}

View File

@@ -1,4 +1,4 @@
use serde::de::Error;
use anyhow::Result;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use std::fmt::{self, Display};
@@ -84,7 +84,7 @@ where
}
}
pub fn get_duration<S: AsRef<Path>>(path: S) -> anyhow::Result<u64> {
pub fn get_duration<S: AsRef<Path>>(path: S) -> Result<u64> {
let file = fs::File::open(path)?;
let reader = io::BufReader::new(file);
let (_header, events) = open(reader)?;
@@ -93,9 +93,7 @@ pub fn get_duration<S: AsRef<Path>>(path: S) -> anyhow::Result<u64> {
Ok(time)
}
pub fn open<R: BufRead>(
reader: R,
) -> anyhow::Result<(Header, impl Iterator<Item = anyhow::Result<Event>>)> {
pub fn open<R: BufRead>(reader: R) -> Result<(Header, impl Iterator<Item = Result<Event>>)> {
let mut lines = reader.lines();
let first_line = lines.next().ok_or(anyhow::anyhow!("empty file"))??;
let header: Header = serde_json::from_str(&first_line)?;
@@ -104,7 +102,7 @@ pub fn open<R: BufRead>(
Ok((header, events))
}
fn parse_event(line: io::Result<String>) -> Option<anyhow::Result<Event>> {
fn parse_event(line: io::Result<String>) -> Option<Result<Event>> {
match line {
Ok(line) => {
if line.is_empty() {
@@ -122,6 +120,8 @@ fn deserialize_time<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let value: serde_json::Value = Deserialize::deserialize(deserializer)?;
let string = value.to_string();
let parts: Vec<&str> = string.split('.').collect();
@@ -146,6 +146,7 @@ fn deserialize_code<'de, D>(deserializer: D) -> Result<EventCode, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
use EventCode::*;
let value: &str = Deserialize::deserialize(deserializer)?;
@@ -292,6 +293,21 @@ impl From<&super::Header> for Header {
}
}
pub fn output(
events: impl Iterator<Item = Result<Event>>,
) -> impl Iterator<Item = Result<(u64, String)>> {
events.filter_map(|e| match e {
Ok(Event {
code: EventCode::Output,
time,
data,
}) => Some(Ok((time, data))),
Ok(_) => None,
Err(e) => Some(Err(e)),
})
}
#[cfg(test)]
mod tests {
use super::{Event, EventCode, Header, Writer};

View File

@@ -2,6 +2,7 @@ mod cmd;
mod config;
mod format;
mod locale;
mod player;
mod pty;
mod recorder;
use crate::config::Config;

27
src/player.rs Normal file
View File

@@ -0,0 +1,27 @@
use crate::format::asciicast;
use anyhow::Result;
use std::io::{self, Write};
use std::thread;
use std::time::{Duration, Instant};
pub fn play(input: impl io::Read) -> Result<()> {
let reader = io::BufReader::new(input);
let (_, events) = asciicast::open(reader)?;
let output = asciicast::output(events);
let mut stdout = io::stdout();
let epoch = Instant::now();
for o in output {
let (time, data) = o?;
let diff = time as i64 - epoch.elapsed().as_micros() as i64;
if diff > 0 {
stdout.flush().unwrap();
thread::sleep(Duration::from_micros(diff as u64));
}
stdout.write(data.as_bytes())?;
}
Ok(())
}