adb_kit/
resource.rs

1use crate::device::ADB;
2use crate::error::{ADBError, ADBResult};
3use log::{debug, warn, info};
4use std::sync::{Arc};
5use std::time::{Duration, Instant};
6
7/// 资源管理器结构体
8///
9/// 负责跟踪和清理设备上的临时文件
10pub struct ResourceManager {
11    device_id: String,
12    temp_files: Vec<String>,
13    start_time: Instant,
14    adb: Arc<ADB>,
15}
16
17impl ResourceManager {
18    /// 创建新的资源管理器
19    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    /// 添加临时文件到跟踪列表
29    pub fn track_temp_file(&mut self, path: &str) {
30        self.temp_files.push(path.to_string());
31        debug!("添加临时文件到跟踪: {}", path);
32    }
33
34    /// 手动清理所有跟踪的临时文件
35    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        // 清空跟踪列表
49        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    /// 获取操作持续时间
62    pub fn elapsed(&self) -> Duration {
63        self.start_time.elapsed()
64    }
65}
66
67// 为 ResourceManager 实现 Drop 特性,在超出作用域时自动清理资源
68impl 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            // 尝试清理资源,但忽略错误(因为这是在 Drop 中)
78            let _ = self.cleanup();
79        }
80    }
81}
82
83// 为 ADB 添加资源管理支持
84impl ADB {
85    /// 创建资源管理器
86    pub fn create_resource_manager(&self, device_id: &str) -> ResourceManager {
87        ResourceManager::new(Arc::new(self.clone()), device_id)
88    }
89
90    /// 使用资源管理器执行操作
91    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        // 自动清理资源
99        let _ = manager.cleanup();
100
101        result
102    }
103
104    /// 优化的截图功能(使用资源管理器)
105    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            // 创建设备上的临时文件路径
112            let device_path = format!("/sdcard/screenshot_{}.png",
113                                      chrono::Local::now().format("%Y%m%d_%H%M%S"));
114
115            // 添加到资源跟踪
116            resources.track_temp_file(&device_path);
117
118            // 执行截图
119            self.shell(device_id, &format!("screencap -p {}", device_path))?;
120
121            // 下载到本地
122            self.pull(device_id, &device_path, output_path, None)?;
123
124            Ok(())
125        })
126    }
127
128    /// 优化的屏幕录制功能(使用资源管理器)
129    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            // 创建设备上的临时文件路径
138            let device_path = format!("/sdcard/recording_{}.mp4",
139                                      chrono::Local::now().format("%Y%m%d_%H%M%S"));
140
141            // 添加到资源跟踪
142            resources.track_temp_file(&device_path);
143
144            // 构建录制命令
145            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            // 执行录制(会阻塞直到录制完成)
154            self.shell(device_id, &command)?;
155
156            // 下载到本地
157            self.pull(device_id, &device_path, output_path, None)?;
158
159            Ok(())
160        })
161    }
162
163    /// 使用临时文件执行操作
164    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        // 生成唯一的临时文件名
169        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        // 执行操作
178        let result = f(&temp_filename);
179
180        // 操作完成后删除临时文件
181        let _ = self.shell(device_id, &format!("rm -f {}", temp_filename));
182
183        result
184    }
185}