aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-11-04 11:53:11 -0500
committerJesse Luehrs <doy@tozt.net>2019-11-04 12:51:47 -0500
commitba3d78f0443ea691c8fc13709e94bc3dd6aced1b (patch)
tree7da5152496d2efc811aa0e4797ce6d1d4aeba6e4
parent736d401cf6a2b1f4d7f4261dad7c3b379f725df6 (diff)
downloadteleterm-ba3d78f0443ea691c8fc13709e94bc3dd6aced1b.tar.gz
teleterm-ba3d78f0443ea691c8fc13709e94bc3dd6aced1b.zip
allow limiting the max length of a ttyrec frame
-rw-r--r--src/cmd/play.rs34
-rw-r--r--src/config.rs30
-rw-r--r--src/error.rs3
3 files changed, 61 insertions, 6 deletions
diff --git a/src/cmd/play.rs b/src/cmd/play.rs
index 8925701..c83bb88 100644
--- a/src/cmd/play.rs
+++ b/src/cmd/play.rs
@@ -27,6 +27,7 @@ impl crate::config::Config for Config {
Box::new(PlaySession::new(
&self.ttyrec.filename,
self.play.playback_ratio,
+ self.play.max_frame_length,
))
}
}
@@ -67,22 +68,34 @@ enum FileState {
struct PlaySession {
file: FileState,
+ playback_ratio: f32,
+ max_frame_length: Option<std::time::Duration>,
+
to_write: DumbDelayQueue<Vec<u8>>,
// to_write: tokio::timer::delay_queue::DelayQueue<Vec<u8>>,
base_time: std::time::Instant,
- playback_ratio: f32,
+ last_frame_time: std::time::Duration,
+ total_time_clamped: std::time::Duration,
}
impl PlaySession {
- fn new(filename: &str, playback_ratio: f32) -> Self {
+ fn new(
+ filename: &str,
+ playback_ratio: f32,
+ max_frame_length: Option<std::time::Duration>,
+ ) -> Self {
Self {
file: FileState::Closed {
filename: filename.to_string(),
},
+ playback_ratio,
+ max_frame_length,
+
to_write: DumbDelayQueue::new(),
// to_write: tokio::timer::delay_queue::DelayQueue::new(),
base_time: std::time::Instant::now(),
- playback_ratio,
+ last_frame_time: std::time::Duration::default(),
+ total_time_clamped: std::time::Duration::default(),
}
}
}
@@ -132,12 +145,21 @@ impl PlaySession {
.poll_read()
.context(crate::error::ReadTtyrec))
{
+ let frame_time = frame.time - reader.offset().unwrap();
+ let frame_dur = (frame_time - self.last_frame_time)
+ .div_f32(self.playback_ratio);
+ self.total_time_clamped += self
+ .max_frame_length
+ .map_or(frame_dur, |max_frame_length| {
+ frame_dur.min(max_frame_length)
+ });
+
self.to_write.insert_at(
frame.data,
- self.base_time
- + (frame.time - reader.offset().unwrap())
- .div_f32(self.playback_ratio),
+ self.base_time + self.total_time_clamped,
);
+
+ self.last_frame_time = frame_time;
} else {
self.file = FileState::Eof;
}
diff --git a/src/config.rs b/src/config.rs
index 85daf27..0387fa8 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,6 +16,7 @@ const FILENAME_OPTION: &str = "filename";
const LISTEN_ADDRESS_OPTION: &str = "listen-address";
const LOGIN_PLAIN_OPTION: &str = "login-plain";
const LOGIN_RECURSE_CENTER_OPTION: &str = "login-recurse-center";
+const MAX_FRAME_LENGTH_OPTION: &str = "max-frame-length";
const PLAYBACK_RATIO_OPTION: &str = "playback-ratio";
const READ_TIMEOUT_OPTION: &str = "read-timeout-secs";
const TLS_IDENTITY_FILE_OPTION: &str = "tls-identity-file";
@@ -700,12 +701,17 @@ fn default_ttyrec_filename() -> String {
pub struct Play {
#[serde(default = "default_playback_ratio")]
pub playback_ratio: f32,
+
+ #[serde(default, deserialize_with = "max_frame_length")]
+ pub max_frame_length: Option<std::time::Duration>,
}
impl Play {
pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
let playback_ratio_help =
"Speed to play back the ttyrec at (defaults to 1.0)";
+ let max_frame_length_help =
+ "Clamp frame duration at this number of seconds";
app.arg(
clap::Arg::with_name(PLAYBACK_RATIO_OPTION)
.long(PLAYBACK_RATIO_OPTION)
@@ -713,6 +719,13 @@ impl Play {
.value_name("RATIO")
.help(playback_ratio_help),
)
+ .arg(
+ clap::Arg::with_name(MAX_FRAME_LENGTH_OPTION)
+ .long(MAX_FRAME_LENGTH_OPTION)
+ .takes_value(true)
+ .value_name("SECS")
+ .help(max_frame_length_help),
+ )
}
pub fn merge_args<'a>(
@@ -729,6 +742,11 @@ impl Play {
name: PLAYBACK_RATIO_OPTION,
})?;
}
+ self.max_frame_length = matches
+ .value_of(MAX_FRAME_LENGTH_OPTION)
+ .map(|len| len.parse().map(std::time::Duration::from_secs))
+ .transpose()
+ .context(crate::error::ParseMaxFrameLength)?;
Ok(())
}
}
@@ -737,6 +755,7 @@ impl Default for Play {
fn default() -> Self {
Self {
playback_ratio: default_playback_ratio(),
+ max_frame_length: None,
}
}
}
@@ -745,6 +764,17 @@ fn default_playback_ratio() -> f32 {
1.0
}
+fn max_frame_length<'a, D>(
+ deserializer: D,
+) -> std::result::Result<Option<std::time::Duration>, D::Error>
+where
+ D: serde::de::Deserializer<'a>,
+{
+ Ok(Some(std::time::Duration::from_secs(u64::deserialize(
+ deserializer,
+ )?)))
+}
+
pub fn oauth_configs<'a, D>(
deserializer: D,
) -> std::result::Result<
diff --git a/src/error.rs b/src/error.rs
index 3c3d663..e3c5206 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -226,6 +226,9 @@ pub enum Error {
#[snafu(display("failed to parse response json: {}", source))]
ParseJson { source: reqwest::Error },
+ #[snafu(display("failed to parse max frame length: {}", source))]
+ ParseMaxFrameLength { source: std::num::ParseIntError },
+
#[snafu(display(
"failed to parse port {} from address: {}",
string,