This commit is contained in:
@@ -64,6 +64,31 @@ impl TerminalSessionRegistry {
|
||||
cols: u16,
|
||||
rows: u16,
|
||||
) -> Result<TerminalSessionId, TerminalSessionError> {
|
||||
self.spawn_program(shell.as_ref(), &[], cols, rows)
|
||||
}
|
||||
|
||||
pub fn spawn_ssh(
|
||||
&mut self,
|
||||
host: impl AsRef<str>,
|
||||
user: Option<&str>,
|
||||
port: u16,
|
||||
cols: u16,
|
||||
rows: u16,
|
||||
) -> Result<TerminalSessionId, TerminalSessionError> {
|
||||
let args = build_ssh_pty_args(host.as_ref(), user, port)?;
|
||||
self.spawn_program("ssh", &args, cols, rows)
|
||||
}
|
||||
|
||||
fn spawn_program(
|
||||
&mut self,
|
||||
program: &str,
|
||||
args: &[String],
|
||||
cols: u16,
|
||||
rows: u16,
|
||||
) -> Result<TerminalSessionId, TerminalSessionError> {
|
||||
if program.trim().is_empty() {
|
||||
return Err(TerminalSessionError::Io("program is required".to_string()));
|
||||
}
|
||||
let size = session_size(cols, rows)?;
|
||||
let pty_system = native_pty_system();
|
||||
let pair = pty_system
|
||||
@@ -74,7 +99,10 @@ impl TerminalSessionRegistry {
|
||||
pixel_height: 0,
|
||||
})
|
||||
.map_err(|err| TerminalSessionError::Io(err.to_string()))?;
|
||||
let command = CommandBuilder::new(shell.as_ref());
|
||||
let mut command = CommandBuilder::new(program);
|
||||
for arg in args {
|
||||
command.arg(arg);
|
||||
}
|
||||
let child = pair
|
||||
.slave
|
||||
.spawn_command(command)
|
||||
@@ -193,6 +221,31 @@ impl TerminalSessionRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_ssh_pty_args(
|
||||
host: &str,
|
||||
user: Option<&str>,
|
||||
port: u16,
|
||||
) -> Result<Vec<String>, TerminalSessionError> {
|
||||
if host.trim().is_empty() {
|
||||
return Err(TerminalSessionError::Io("ssh host is required".to_string()));
|
||||
}
|
||||
if port == 0 {
|
||||
return Err(TerminalSessionError::Io("ssh port is required".to_string()));
|
||||
}
|
||||
let destination = match user.map(str::trim).filter(|value| !value.is_empty()) {
|
||||
Some(user) => format!("{user}@{}", host.trim()),
|
||||
None => host.trim().to_string(),
|
||||
};
|
||||
Ok(vec![
|
||||
"-tt".to_string(),
|
||||
"-o".to_string(),
|
||||
"BatchMode=yes".to_string(),
|
||||
"-p".to_string(),
|
||||
port.to_string(),
|
||||
destination,
|
||||
])
|
||||
}
|
||||
|
||||
fn session_size(cols: u16, rows: u16) -> Result<TerminalSessionSize, TerminalSessionError> {
|
||||
if cols == 0 || rows == 0 {
|
||||
return Err(TerminalSessionError::InvalidSize);
|
||||
@@ -240,4 +293,29 @@ mod tests {
|
||||
|
||||
assert_eq!(err, TerminalSessionError::MissingSession(999));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssh_pty_args_enable_tty_and_batch_mode() {
|
||||
let args = build_ssh_pty_args("example.com", Some("alice"), 2222).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
"-tt",
|
||||
"-o",
|
||||
"BatchMode=yes",
|
||||
"-p",
|
||||
"2222",
|
||||
"alice@example.com"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssh_pty_args_reject_blank_host() {
|
||||
assert_eq!(
|
||||
build_ssh_pty_args(" ", None, 22).unwrap_err(),
|
||||
TerminalSessionError::Io("ssh host is required".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user