1use std::io::{BufRead, BufReader, Write};
7use std::net::TcpStream;
8use std::time::Duration;
9
10use anyhow::Result;
11use serde_json::json;
12use tracing::debug;
13
14use super::protocol::{BridgeRequest, BridgeResponse};
15
16pub struct BridgeClient {
18 port: u16,
19}
20
21impl BridgeClient {
22 pub fn new(port: u16) -> Self {
24 Self { port }
25 }
26
27 #[allow(dead_code)]
29 pub fn port(&self) -> u16 {
30 self.port
31 }
32
33 pub fn send_command(
35 &self,
36 command: &str,
37 args: Option<serde_json::Value>,
38 ) -> Result<serde_json::Value> {
39 let addr: std::net::SocketAddr = format!("127.0.0.1:{}", self.port)
40 .parse()
41 .map_err(|e| anyhow::anyhow!("Invalid address: {}", e))?;
42 let mut stream =
43 TcpStream::connect_timeout(&addr, Duration::from_secs(10)).map_err(|e| {
44 anyhow::anyhow!("Failed to connect to bridge on port {}: {}", self.port, e)
45 })?;
46 stream.set_read_timeout(Some(Duration::from_secs(300))).ok();
47 stream.set_write_timeout(Some(Duration::from_secs(30))).ok();
48
49 let request = BridgeRequest {
50 command: command.to_string(),
51 args,
52 };
53
54 let request_json = serde_json::to_string(&request)?;
55 debug!("Sending: {}", request_json);
56
57 writeln!(stream, "{}", request_json)?;
58 stream.flush()?;
59
60 let mut reader = BufReader::new(&stream);
61 let mut response_line = String::new();
62 reader.read_line(&mut response_line)?;
63
64 debug!("Received: {}", response_line.trim());
65
66 let response: BridgeResponse = serde_json::from_str(&response_line)?;
67
68 match response.status.as_str() {
69 "success" => Ok(response.data.unwrap_or(json!({}))),
70 "error" => {
71 let msg = response
72 .message
73 .unwrap_or_else(|| "Unknown error".to_string());
74 anyhow::bail!("{}", msg)
75 }
76 "shutdown" => Ok(json!({"status": "shutdown"})),
77 _ => Ok(response.data.unwrap_or(json!({}))),
78 }
79 }
80
81 pub fn ping(&self) -> Result<bool> {
83 match self.send_command("ping", None) {
84 Ok(_) => Ok(true),
85 Err(_) => Ok(false),
86 }
87 }
88
89 pub fn shutdown(&self) -> Result<()> {
91 self.send_command("shutdown", None)?;
92 Ok(())
93 }
94
95 #[allow(dead_code)]
97 pub fn status(&self) -> Result<serde_json::Value> {
98 self.send_command("status", None)
99 }
100
101 pub fn bridge_info(&self) -> Result<serde_json::Value> {
103 self.send_command("bridge_info", None)
104 }
105
106 pub fn list_functions(
108 &self,
109 limit: Option<usize>,
110 filter: Option<String>,
111 ) -> Result<serde_json::Value> {
112 self.send_command(
113 "list_functions",
114 Some(json!({"limit": limit, "filter": filter})),
115 )
116 }
117
118 pub fn decompile(&self, address: String) -> Result<serde_json::Value> {
120 self.send_command("decompile", Some(json!({"address": address})))
121 }
122
123 pub fn list_strings(&self, limit: Option<usize>, filter: Option<String>) -> Result<serde_json::Value> {
125 self.send_command("list_strings", Some(json!({"limit": limit, "filter": filter})))
126 }
127
128 pub fn list_imports(&self) -> Result<serde_json::Value> {
130 self.send_command("list_imports", None)
131 }
132
133 pub fn list_exports(&self) -> Result<serde_json::Value> {
135 self.send_command("list_exports", None)
136 }
137
138 pub fn memory_map(&self) -> Result<serde_json::Value> {
140 self.send_command("memory_map", None)
141 }
142
143 pub fn program_info(&self) -> Result<serde_json::Value> {
145 self.send_command("program_info", None)
146 }
147
148 pub fn xrefs_to(&self, address: String) -> Result<serde_json::Value> {
150 self.send_command("xrefs_to", Some(json!({"address": address})))
151 }
152
153 pub fn xrefs_from(&self, address: String) -> Result<serde_json::Value> {
155 self.send_command("xrefs_from", Some(json!({"address": address})))
156 }
157
158 pub fn import_binary(
160 &self,
161 binary_path: &str,
162 program: Option<&str>,
163 ) -> Result<serde_json::Value> {
164 self.send_command(
165 "import",
166 Some(json!({"binary_path": binary_path, "program": program})),
167 )
168 }
169
170 pub fn analyze(&self) -> Result<serde_json::Value> {
172 self.send_command("analyze", None)
173 }
174
175 pub fn list_programs(&self) -> Result<serde_json::Value> {
177 self.send_command("list_programs", None)
178 }
179
180 pub fn open_program(&self, program: &str) -> Result<serde_json::Value> {
182 self.send_command("open_program", Some(json!({"program": program})))
183 }
184
185 pub fn symbol_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
188 self.send_command("symbol_list", Some(json!({"limit": limit, "filter": filter})))
189 }
190
191 pub fn symbol_get(&self, name: &str) -> Result<serde_json::Value> {
192 self.send_command("symbol_get", Some(json!({"name": name})))
193 }
194
195 pub fn symbol_create(&self, address: &str, name: &str) -> Result<serde_json::Value> {
196 self.send_command(
197 "symbol_create",
198 Some(json!({"address": address, "name": name})),
199 )
200 }
201
202 pub fn symbol_delete(&self, name: &str) -> Result<serde_json::Value> {
203 self.send_command("symbol_delete", Some(json!({"name": name})))
204 }
205
206 pub fn symbol_rename(&self, old_name: &str, new_name: &str) -> Result<serde_json::Value> {
207 self.send_command(
208 "symbol_rename",
209 Some(json!({"old_name": old_name, "new_name": new_name})),
210 )
211 }
212
213 pub fn type_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
214 self.send_command("type_list", Some(json!({"limit": limit, "filter": filter})))
215 }
216
217 pub fn type_get(&self, name: &str) -> Result<serde_json::Value> {
218 self.send_command("type_get", Some(json!({"name": name})))
219 }
220
221 pub fn type_create(&self, definition: &str) -> Result<serde_json::Value> {
222 self.send_command("type_create", Some(json!({"definition": definition})))
223 }
224
225 pub fn type_apply(&self, address: &str, type_name: &str) -> Result<serde_json::Value> {
226 self.send_command(
227 "type_apply",
228 Some(json!({"address": address, "type_name": type_name})),
229 )
230 }
231
232 pub fn comment_list(&self, limit: Option<usize>, filter: Option<&str>) -> Result<serde_json::Value> {
233 self.send_command("comment_list", Some(json!({"limit": limit, "filter": filter})))
234 }
235
236 pub fn comment_get(&self, address: &str) -> Result<serde_json::Value> {
237 self.send_command("comment_get", Some(json!({"address": address})))
238 }
239
240 pub fn comment_set(
241 &self,
242 address: &str,
243 text: &str,
244 comment_type: Option<&str>,
245 ) -> Result<serde_json::Value> {
246 self.send_command(
247 "comment_set",
248 Some(json!({
249 "address": address,
250 "text": text,
251 "type": comment_type,
252 })),
253 )
254 }
255
256 pub fn comment_delete(&self, address: &str) -> Result<serde_json::Value> {
257 self.send_command("comment_delete", Some(json!({"address": address})))
258 }
259
260 pub fn graph_calls(&self, limit: Option<usize>) -> Result<serde_json::Value> {
261 self.send_command("graph_calls", Some(json!({"limit": limit})))
262 }
263
264 pub fn graph_callers(&self, function: &str, depth: Option<usize>) -> Result<serde_json::Value> {
265 self.send_command(
266 "graph_callers",
267 Some(json!({"function": function, "depth": depth})),
268 )
269 }
270
271 pub fn graph_callees(&self, function: &str, depth: Option<usize>) -> Result<serde_json::Value> {
272 self.send_command(
273 "graph_callees",
274 Some(json!({"function": function, "depth": depth})),
275 )
276 }
277
278 pub fn graph_export(&self, format: &str) -> Result<serde_json::Value> {
279 self.send_command("graph_export", Some(json!({"format": format})))
280 }
281
282 pub fn find_string(&self, pattern: &str) -> Result<serde_json::Value> {
283 self.send_command("find_string", Some(json!({"pattern": pattern})))
284 }
285
286 pub fn find_bytes(&self, hex: &str) -> Result<serde_json::Value> {
287 self.send_command("find_bytes", Some(json!({"hex": hex})))
288 }
289
290 pub fn find_function(&self, pattern: &str) -> Result<serde_json::Value> {
291 self.send_command("find_function", Some(json!({"pattern": pattern})))
292 }
293
294 pub fn find_calls(&self, function: &str) -> Result<serde_json::Value> {
295 self.send_command("find_calls", Some(json!({"function": function})))
296 }
297
298 pub fn find_crypto(&self) -> Result<serde_json::Value> {
299 self.send_command("find_crypto", None)
300 }
301
302 pub fn find_interesting(&self) -> Result<serde_json::Value> {
303 self.send_command("find_interesting", None)
304 }
305
306 pub fn diff_programs(&self, program1: &str, program2: &str) -> Result<serde_json::Value> {
307 self.send_command(
308 "diff_programs",
309 Some(json!({"program1": program1, "program2": program2})),
310 )
311 }
312
313 pub fn diff_functions(&self, func1: &str, func2: &str) -> Result<serde_json::Value> {
314 self.send_command(
315 "diff_functions",
316 Some(json!({"func1": func1, "func2": func2})),
317 )
318 }
319
320 pub fn patch_bytes(&self, address: &str, hex: &str) -> Result<serde_json::Value> {
321 self.send_command("patch_bytes", Some(json!({"address": address, "hex": hex})))
322 }
323
324 pub fn patch_nop(&self, address: &str) -> Result<serde_json::Value> {
325 self.send_command("patch_nop", Some(json!({"address": address})))
326 }
327
328 pub fn patch_export(&self, output: &str) -> Result<serde_json::Value> {
329 self.send_command("patch_export", Some(json!({"output": output})))
330 }
331
332 pub fn disasm(
333 &self,
334 address: &str,
335 num_instructions: Option<usize>,
336 ) -> Result<serde_json::Value> {
337 self.send_command(
338 "disasm",
339 Some(json!({"address": address, "count": num_instructions})),
340 )
341 }
342
343 pub fn stats(&self) -> Result<serde_json::Value> {
344 self.send_command("stats", None)
345 }
346
347 pub fn script_run(&self, script_path: &str, args: &[String]) -> Result<serde_json::Value> {
348 self.send_command(
349 "script_run",
350 Some(json!({"path": script_path, "args": args})),
351 )
352 }
353
354 pub fn script_python(&self, code: &str) -> Result<serde_json::Value> {
355 self.send_command("script_python", Some(json!({"code": code})))
356 }
357
358 pub fn script_java(&self, code: &str) -> Result<serde_json::Value> {
359 self.send_command("script_java", Some(json!({"code": code})))
360 }
361
362 pub fn script_list(&self) -> Result<serde_json::Value> {
363 self.send_command("script_list", None)
364 }
365
366 pub fn program_close(&self) -> Result<serde_json::Value> {
367 self.send_command("close_program", None)
368 }
369
370 pub fn program_delete(&self, program: &str) -> Result<serde_json::Value> {
371 self.send_command("delete_program", Some(json!({"program": program})))
372 }
373
374 pub fn program_export(&self, format: &str, output: Option<&str>) -> Result<serde_json::Value> {
375 self.send_command(
376 "export_program",
377 Some(json!({"format": format, "output": output})),
378 )
379 }
380}