1use crate::device::ADB;
2use crate::error::{ADBError, ADBResult};
3use log::{debug, warn, info};
4use std::sync::{Arc};
5use std::time::{Duration, Instant};
6
7pub struct ResourceManager {
11 device_id: String,
12 temp_files: Vec<String>,
13 start_time: Instant,
14 adb: Arc<ADB>,
15}
16
17impl ResourceManager {
18 pub fn new(adb: Arc<ADB>, device_id: &str) -> Self {
20 Self {
21 device_id: device_id.to_string(),
22 temp_files: Vec::new(),
23 start_time: Instant::now(),
24 adb,
25 }
26 }
27
28 pub fn track_temp_file(&mut self, path: &str) {
30 self.temp_files.push(path.to_string());
31 debug!("添加临时文件到跟踪: {}", path);
32 }
33
34 pub fn cleanup(&mut self) -> ADBResult<()> {
36 let mut errors = Vec::new();
37
38 for file in &self.temp_files {
39 match self.adb.shell(&self.device_id, &format!("rm -f {}", file)) {
40 Ok(_) => debug!("已删除临时文件: {}", file),
41 Err(e) => {
42 warn!("删除临时文件 {} 失败: {}", file, e);
43 errors.push(format!("文件 {}: {}", file, e));
44 }
45 }
46 }
47
48 self.temp_files.clear();
50
51 if errors.is_empty() {
52 Ok(())
53 } else {
54 Err(ADBError::FileError(format!(
55 "清理临时文件时发生错误: {}",
56 errors.join(", ")
57 )))
58 }
59 }
60
61 pub fn elapsed(&self) -> Duration {
63 self.start_time.elapsed()
64 }
65}
66
67impl Drop for ResourceManager {
69 fn drop(&mut self) {
70 if !self.temp_files.is_empty() {
71 info!(
72 "自动清理 {} 个设备上的临时文件 {}",
73 self.device_id,
74 self.temp_files.len()
75 );
76
77 let _ = self.cleanup();
79 }
80 }
81}
82
83impl ADB {
85 pub fn create_resource_manager(&self, device_id: &str) -> ResourceManager {
87 ResourceManager::new(Arc::new(self.clone()), device_id)
88 }
89
90 pub fn with_resources<F, T>(&self, device_id: &str, f: F) -> ADBResult<T>
92 where
93 F: FnOnce(&mut ResourceManager) -> ADBResult<T>,
94 {
95 let mut manager = self.create_resource_manager(device_id);
96 let result = f(&mut manager);
97
98 let _ = manager.cleanup();
100
101 result
102 }
103
104 pub fn take_screenshot_managed(
106 &self,
107 device_id: &str,
108 output_path: &str,
109 ) -> ADBResult<()> {
110 self.with_resources(device_id, |resources| {
111 let device_path = format!("/sdcard/screenshot_{}.png",
113 chrono::Local::now().format("%Y%m%d_%H%M%S"));
114
115 resources.track_temp_file(&device_path);
117
118 self.shell(device_id, &format!("screencap -p {}", device_path))?;
120
121 self.pull(device_id, &device_path, output_path, None)?;
123
124 Ok(())
125 })
126 }
127
128 pub fn record_screen_managed(
130 &self,
131 device_id: &str,
132 output_path: &str,
133 duration_secs: u32,
134 size: Option<&str>,
135 ) -> ADBResult<()> {
136 self.with_resources(device_id, |resources| {
137 let device_path = format!("/sdcard/recording_{}.mp4",
139 chrono::Local::now().format("%Y%m%d_%H%M%S"));
140
141 resources.track_temp_file(&device_path);
143
144 let mut command = format!("screenrecord --time-limit {} ", duration_secs.min(180));
146
147 if let Some(resolution) = size {
148 command.push_str(&format!("--size {} ", resolution));
149 }
150
151 command.push_str(&device_path);
152
153 self.shell(device_id, &command)?;
155
156 self.pull(device_id, &device_path, output_path, None)?;
158
159 Ok(())
160 })
161 }
162
163 pub fn with_temp_file<F, T>(&self, device_id: &str, prefix: &str, suffix: &str, f: F) -> ADBResult<T>
165 where
166 F: FnOnce(&str) -> ADBResult<T>,
167 {
168 let temp_filename = format!(
170 "/sdcard/{}_{}_{}{}",
171 prefix,
172 chrono::Local::now().format("%Y%m%d_%H%M%S"),
173 rand::random::<u32>(),
174 suffix
175 );
176
177 let result = f(&temp_filename);
179
180 let _ = self.shell(device_id, &format!("rm -f {}", temp_filename));
182
183 result
184 }
185}