use super::{code::*, io::*, read::*};
use std::{
io::{self, Write},
path::*,
};
const MAX_PAYLOAD_CHUNK_SIZE: usize = 4096;
const MAX_PAYLOAD_CHUNK_SIZE_U64: u64 = MAX_PAYLOAD_CHUNK_SIZE as u64;
#[derive(Clone, Debug, Default)]
pub struct Command {
control: Vec<(char, Code)>,
}
impl Command {
pub fn add<CodeT>(&mut self, key: char, code: CodeT)
where
CodeT: Into<Code>,
{
self.control.push((key, code.into()));
}
pub fn with<CodeT>(mut self, key: char, code: CodeT) -> Self
where
CodeT: Into<Code>,
{
self.add(key, code);
self
}
pub fn execute(&self) -> io::Result<()> {
let mut writer = io::stdout();
writer.write_start()?;
self.write_control(&mut writer)?;
writer.write_end()
}
pub fn execute_with_payload(&self, payload: &[u8]) -> io::Result<()> {
if payload.len() > MAX_PAYLOAD_CHUNK_SIZE {
self.execute_with_payload_from(payload)
} else {
let mut writer = io::stdout();
writer.write_start()?;
self.write_control(&mut writer)?;
write!(writer, ";")?;
writer = writer.write_base64(payload)?;
writer.write_end()
}
}
pub fn execute_with_payload_from<ReadT>(&self, mut payload: ReadT) -> io::Result<()>
where
ReadT: io::Read,
{
let mut writer = io::stdout();
writer.write_start()?;
if !self.control.is_empty() {
self.write_control(&mut writer)?;
write!(writer, ",")?;
}
write!(writer, "m=1;")?;
let mut chunk = Vec::with_capacity(MAX_PAYLOAD_CHUNK_SIZE);
loop {
chunk.clear();
payload = payload.read_chunk(MAX_PAYLOAD_CHUNK_SIZE_U64, &mut chunk)?;
if chunk.is_empty() {
writer.write_end()?;
writer.write_start()?;
write!(writer, "m=0;")?;
return writer.write_end();
}
writer = writer.write_base64(&chunk)?;
writer.write_end()?;
writer.write_start()?;
write!(writer, "m=1;")?;
}
}
pub fn execute_with_path_payload<PathT>(&self, path: PathT) -> io::Result<()>
where
PathT: AsRef<Path>,
{
self.execute_with_payload(absolute(path)?.as_os_str().as_encoded_bytes())
}
fn write_control<WriteT>(&self, mut writer: WriteT) -> io::Result<()>
where
WriteT: io::Write,
{
let mut iterator = self.control.iter().peekable();
while let Some((key, code)) = iterator.next() {
write!(writer, "{}=", *key)?;
code.write(&mut writer)?;
if iterator.peek().is_some() {
write!(writer, ",")?;
}
}
Ok(())
}
}