use crate::device::ADB;
use crate::error::{ADBError, ADBResult};
use log::{debug, warn, info};
use std::sync::{Arc};
use std::time::{Duration, Instant};
pub struct ResourceManager {
device_id: String,
temp_files: Vec<String>,
start_time: Instant,
adb: Arc<ADB>,
}
impl ResourceManager {
pub fn new(adb: Arc<ADB>, device_id: &str) -> Self {
Self {
device_id: device_id.to_string(),
temp_files: Vec::new(),
start_time: Instant::now(),
adb,
}
}
pub fn track_temp_file(&mut self, path: &str) {
self.temp_files.push(path.to_string());
debug!("添加临时文件到跟踪: {}", path);
}
pub fn cleanup(&mut self) -> ADBResult<()> {
let mut errors = Vec::new();
for file in &self.temp_files {
match self.adb.shell(&self.device_id, &format!("rm -f {}", file)) {
Ok(_) => debug!("已删除临时文件: {}", file),
Err(e) => {
warn!("删除临时文件 {} 失败: {}", file, e);
errors.push(format!("文件 {}: {}", file, e));
}
}
}
self.temp_files.clear();
if errors.is_empty() {
Ok(())
} else {
Err(ADBError::FileError(format!(
"清理临时文件时发生错误: {}",
errors.join(", ")
)))
}
}
pub fn elapsed(&self) -> Duration {
self.start_time.elapsed()
}
}
impl Drop for ResourceManager {
fn drop(&mut self) {
if !self.temp_files.is_empty() {
info!(
"自动清理 {} 个设备上的临时文件 {}",
self.device_id,
self.temp_files.len()
);
let _ = self.cleanup();
}
}
}
impl ADB {
pub fn create_resource_manager(&self, device_id: &str) -> ResourceManager {
ResourceManager::new(Arc::new(self.clone()), device_id)
}
pub fn with_resources<F, T>(&self, device_id: &str, f: F) -> ADBResult<T>
where
F: FnOnce(&mut ResourceManager) -> ADBResult<T>,
{
let mut manager = self.create_resource_manager(device_id);
let result = f(&mut manager);
let _ = manager.cleanup();
result
}
pub fn take_screenshot_managed(
&self,
device_id: &str,
output_path: &str,
) -> ADBResult<()> {
self.with_resources(device_id, |resources| {
let device_path = format!("/sdcard/screenshot_{}.png",
chrono::Local::now().format("%Y%m%d_%H%M%S"));
resources.track_temp_file(&device_path);
self.shell(device_id, &format!("screencap -p {}", device_path))?;
self.pull(device_id, &device_path, output_path, None)?;
Ok(())
})
}
pub fn record_screen_managed(
&self,
device_id: &str,
output_path: &str,
duration_secs: u32,
size: Option<&str>,
) -> ADBResult<()> {
self.with_resources(device_id, |resources| {
let device_path = format!("/sdcard/recording_{}.mp4",
chrono::Local::now().format("%Y%m%d_%H%M%S"));
resources.track_temp_file(&device_path);
let mut command = format!("screenrecord --time-limit {} ", duration_secs.min(180));
if let Some(resolution) = size {
command.push_str(&format!("--size {} ", resolution));
}
command.push_str(&device_path);
self.shell(device_id, &command)?;
self.pull(device_id, &device_path, output_path, None)?;
Ok(())
})
}
pub fn with_temp_file<F, T>(&self, device_id: &str, prefix: &str, suffix: &str, f: F) -> ADBResult<T>
where
F: FnOnce(&str) -> ADBResult<T>,
{
let temp_filename = format!(
"/sdcard/{}_{}_{}{}",
prefix,
chrono::Local::now().format("%Y%m%d_%H%M%S"),
rand::random::<u32>(),
suffix
);
let result = f(&temp_filename);
let _ = self.shell(device_id, &format!("rm -f {}", temp_filename));
result
}
}