use std::collections::BTreeMap;
pub const DEFAULT_COMMAND_OUTPUT_LIMIT: usize = 8 * 1024 * 1024;
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum ChannelKind {
Session,
DirectTcpIp,
ForwardedTcpIp,
DirectStreamLocal,
ForwardedStreamLocal,
Subsystem(String),
}
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CommandExit {
Status(u32),
Signal(String),
Missing,
}
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CommandLimits {
stdout: usize,
stderr: usize,
}
impl CommandLimits {
pub fn new(stdout: usize, stderr: usize) -> Self {
Self { stdout, stderr }
}
pub fn stdout(&self) -> usize {
self.stdout
}
pub fn stderr(&self) -> usize {
self.stderr
}
pub fn with_stdout(mut self, stdout: usize) -> Self {
self.stdout = stdout;
self
}
pub fn with_stderr(mut self, stderr: usize) -> Self {
self.stderr = stderr;
self
}
}
impl Default for CommandLimits {
fn default() -> Self {
Self {
stdout: DEFAULT_COMMAND_OUTPUT_LIMIT,
stderr: DEFAULT_COMMAND_OUTPUT_LIMIT,
}
}
}
impl CommandExit {
pub fn status(status: u32) -> Self {
Self::Status(status)
}
pub fn signal(signal: impl Into<String>) -> Self {
Self::Signal(signal.into())
}
pub fn missing() -> Self {
Self::Missing
}
pub fn code(&self) -> Option<u32> {
match self {
Self::Status(status) => Some(*status),
Self::Signal(_) | Self::Missing => None,
}
}
pub fn signal_name(&self) -> Option<&str> {
match self {
Self::Signal(signal) => Some(signal),
Self::Status(_) | Self::Missing => None,
}
}
pub fn success(&self) -> bool {
matches!(self, Self::Status(0))
}
}
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pty {
term: String,
width_columns: u32,
height_rows: u32,
width_pixels: u32,
height_pixels: u32,
modes: BTreeMap<TerminalMode, u32>,
}
impl Pty {
pub fn new(term: impl Into<String>, width_columns: u32, height_rows: u32) -> Self {
Self {
term: term.into(),
width_columns,
height_rows,
width_pixels: 0,
height_pixels: 0,
modes: BTreeMap::new(),
}
}
pub fn term(&self) -> &str {
&self.term
}
pub fn width_columns(&self) -> u32 {
self.width_columns
}
pub fn height_rows(&self) -> u32 {
self.height_rows
}
pub fn width_pixels(&self) -> u32 {
self.width_pixels
}
pub fn height_pixels(&self) -> u32 {
self.height_pixels
}
pub fn with_pixels(mut self, width_pixels: u32, height_pixels: u32) -> Self {
self.width_pixels = width_pixels;
self.height_pixels = height_pixels;
self
}
pub fn with_mode(mut self, mode: TerminalMode, value: u32) -> Self {
self.modes.insert(mode, value);
self
}
pub fn modes(&self) -> &BTreeMap<TerminalMode, u32> {
&self.modes
}
}
impl Default for Pty {
fn default() -> Self {
Self::new("xterm-256color", 80, 24)
}
}
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum TerminalMode {
Interrupt,
Quit,
Erase,
Kill,
EndOfFile,
InputSpeed,
OutputSpeed,
Echo,
EchoErase,
EchoKill,
EchoNl,
CanonicalInput,
SigCheck,
CrToNlInput,
NlToCrInput,
IgnoreCrInput,
PostProcessOutput,
NlToCrNlOutput,
CrToNlOutput,
NoCrOnNl,
Custom(u8),
}
#[cfg(test)]
mod tests {
use crate::{CommandLimits, DEFAULT_COMMAND_OUTPUT_LIMIT};
#[test]
fn command_limits_default_to_eight_mib_per_stream() {
let limits = CommandLimits::default();
assert_eq!(limits.stdout(), DEFAULT_COMMAND_OUTPUT_LIMIT);
assert_eq!(limits.stderr(), DEFAULT_COMMAND_OUTPUT_LIMIT);
}
#[test]
fn command_limits_are_configurable() {
let limits = CommandLimits::default().with_stdout(1024).with_stderr(2048);
assert_eq!(limits.stdout(), 1024);
assert_eq!(limits.stderr(), 2048);
}
}