1#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum ForwardNode {
6 Tcp(u16),
8 LocalFilesystem(String),
10 LocalReserved(String),
12 LocalAbstract(String),
14 Dev(String),
16 Jdwp(u32),
18 Ark {
20 pid: u32,
21 tid: u32,
22 debugger: String,
23 },
24}
25
26impl ForwardNode {
27 pub fn parse(s: &str) -> crate::error::Result<Self> {
38 if let Some(port_str) = s.strip_prefix("tcp:") {
39 let port = port_str.parse::<u16>().map_err(|_| {
40 crate::error::HdcError::Protocol(format!("Invalid TCP port: {}", port_str))
41 })?;
42 Ok(Self::Tcp(port))
43 } else if let Some(name) = s.strip_prefix("localfilesystem:") {
44 Ok(Self::LocalFilesystem(name.to_string()))
45 } else if let Some(name) = s.strip_prefix("localreserved:") {
46 Ok(Self::LocalReserved(name.to_string()))
47 } else if let Some(name) = s.strip_prefix("localabstract:") {
48 Ok(Self::LocalAbstract(name.to_string()))
49 } else if let Some(name) = s.strip_prefix("dev:") {
50 Ok(Self::Dev(name.to_string()))
51 } else if let Some(pid_str) = s.strip_prefix("jdwp:") {
52 let pid = pid_str.parse::<u32>().map_err(|_| {
53 crate::error::HdcError::Protocol(format!("Invalid JDWP pid: {}", pid_str))
54 })?;
55 Ok(Self::Jdwp(pid))
56 } else if let Some(ark_str) = s.strip_prefix("ark:") {
57 let parts: Vec<&str> = ark_str.split('@').collect();
58 if parts.len() != 3 {
59 return Err(crate::error::HdcError::Protocol(format!(
60 "Invalid ark format: expected pid@tid@debugger, got {}",
61 ark_str
62 )));
63 }
64 let pid = parts[0].parse::<u32>().map_err(|_| {
65 crate::error::HdcError::Protocol(format!("Invalid pid in ark: {}", parts[0]))
66 })?;
67 let tid = parts[1].parse::<u32>().map_err(|_| {
68 crate::error::HdcError::Protocol(format!("Invalid tid in ark: {}", parts[1]))
69 })?;
70 Ok(Self::Ark {
71 pid,
72 tid,
73 debugger: parts[2].to_string(),
74 })
75 } else {
76 Err(crate::error::HdcError::Protocol(format!(
77 "Invalid forward node format: {}",
78 s
79 )))
80 }
81 }
82
83 pub fn as_protocol_string(&self) -> String {
85 match self {
86 Self::Tcp(port) => format!("tcp:{}", port),
87 Self::LocalFilesystem(name) => format!("localfilesystem:{}", name),
88 Self::LocalReserved(name) => format!("localreserved:{}", name),
89 Self::LocalAbstract(name) => format!("localabstract:{}", name),
90 Self::Dev(name) => format!("dev:{}", name),
91 Self::Jdwp(pid) => format!("jdwp:{}", pid),
92 Self::Ark { pid, tid, debugger } => format!("ark:{}@{}@{}", pid, tid, debugger),
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct ForwardTask {
100 pub local_node: ForwardNode,
101 pub remote_node: ForwardNode,
102 pub is_forward: bool, }
104
105impl ForwardTask {
106 pub fn forward(local: ForwardNode, remote: ForwardNode) -> Self {
108 Self {
109 local_node: local,
110 remote_node: remote,
111 is_forward: true,
112 }
113 }
114
115 pub fn reverse(remote: ForwardNode, local: ForwardNode) -> Self {
117 Self {
118 local_node: local,
119 remote_node: remote,
120 is_forward: false,
121 }
122 }
123
124 pub fn to_command_string(&self) -> String {
126 if self.is_forward {
127 format!(
128 "fport {} {}",
129 self.local_node.as_protocol_string(),
130 self.remote_node.as_protocol_string()
131 )
132 } else {
133 format!(
134 "rport {} {}",
135 self.remote_node.as_protocol_string(),
136 self.local_node.as_protocol_string()
137 )
138 }
139 }
140
141 pub fn task_string(&self) -> String {
143 format!(
144 "{} {}",
145 self.local_node.as_protocol_string(),
146 self.remote_node.as_protocol_string()
147 )
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_parse_tcp() {
157 let node = ForwardNode::parse("tcp:8080").unwrap();
158 assert_eq!(node, ForwardNode::Tcp(8080));
159 assert_eq!(node.as_protocol_string(), "tcp:8080");
160 }
161
162 #[test]
163 fn test_parse_jdwp() {
164 let node = ForwardNode::parse("jdwp:1234").unwrap();
165 assert_eq!(node, ForwardNode::Jdwp(1234));
166 assert_eq!(node.as_protocol_string(), "jdwp:1234");
167 }
168
169 #[test]
170 fn test_parse_ark() {
171 let node = ForwardNode::parse("ark:100@200@Debugger").unwrap();
172 let expected = ForwardNode::Ark {
173 pid: 100,
174 tid: 200,
175 debugger: "Debugger".to_string(),
176 };
177 assert_eq!(node, expected);
178 assert_eq!(node.as_protocol_string(), "ark:100@200@Debugger");
179 }
180
181 #[test]
182 fn test_forward_task() {
183 let task = ForwardTask::forward(ForwardNode::Tcp(8080), ForwardNode::Tcp(8081));
184 assert_eq!(task.to_command_string(), "fport tcp:8080 tcp:8081");
185 assert_eq!(task.task_string(), "tcp:8080 tcp:8081");
186 }
187}