Skip to main content

par_term_ssh/
types.rs

1//! SSH host types for the SSH subsystem.
2
3use serde::{Deserialize, Serialize};
4
5/// Source of an SSH host entry
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub enum SshHostSource {
8    /// Parsed from ~/.ssh/config
9    Config,
10    /// Found in ~/.ssh/known_hosts
11    KnownHosts,
12    /// Extracted from shell history
13    History,
14    /// Discovered via mDNS/Bonjour
15    Mdns,
16}
17
18impl std::fmt::Display for SshHostSource {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            Self::Config => write!(f, "SSH Config"),
22            Self::KnownHosts => write!(f, "Known Hosts"),
23            Self::History => write!(f, "History"),
24            Self::Mdns => write!(f, "mDNS"),
25        }
26    }
27}
28
29/// A discovered SSH host with connection details
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct SshHost {
32    /// The Host alias from SSH config, or hostname from other sources
33    pub alias: String,
34    /// Resolved hostname or IP address
35    pub hostname: Option<String>,
36    /// SSH username
37    pub user: Option<String>,
38    /// SSH port (None means default 22)
39    pub port: Option<u16>,
40    /// Path to identity file
41    pub identity_file: Option<String>,
42    /// ProxyJump host
43    pub proxy_jump: Option<String>,
44    /// Where this host was discovered from
45    pub source: SshHostSource,
46}
47
48impl SshHost {
49    /// Get the display name for this host (alias or hostname)
50    pub fn display_name(&self) -> &str {
51        &self.alias
52    }
53
54    /// Get the connection target (hostname or alias)
55    pub fn connection_target(&self) -> &str {
56        self.hostname.as_deref().unwrap_or(&self.alias)
57    }
58
59    /// Build the ssh command arguments for connecting to this host
60    pub fn ssh_args(&self) -> Vec<String> {
61        let mut args = Vec::new();
62
63        if let Some(port) = self.port
64            && port != 22
65        {
66            args.push("-p".to_string());
67            args.push(port.to_string());
68        }
69
70        if let Some(ref identity) = self.identity_file {
71            args.push("-i".to_string());
72            args.push(identity.clone());
73        }
74
75        if let Some(ref proxy) = self.proxy_jump {
76            args.push("-J".to_string());
77            args.push(proxy.clone());
78        }
79
80        let target = if let Some(ref user) = self.user {
81            format!("{}@{}", user, self.connection_target())
82        } else {
83            self.connection_target().to_string()
84        };
85        args.push(target);
86
87        args
88    }
89
90    /// Build a display string showing user@host:port
91    pub fn connection_string(&self) -> String {
92        let mut s = String::new();
93        if let Some(ref user) = self.user {
94            s.push_str(user);
95            s.push('@');
96        }
97        s.push_str(self.connection_target());
98        if let Some(port) = self.port
99            && port != 22
100        {
101            s.push(':');
102            s.push_str(&port.to_string());
103        }
104        s
105    }
106}