rust_droid/action/
wait.rs

1use crate::common::point::Point;
2use crate::common::relative_rect::RelativeRect;
3use crate::{Droid, DroidError, Result, Target};
4use std::time::{Duration, Instant};
5
6pub struct WaitBuilder<'a> {
7    droid: &'a mut Droid,
8    target: Target,
9    timeout: Duration,
10    interval: Duration,
11    threshold: Option<f32>,
12    search_rect: Option<RelativeRect>,
13}
14
15impl<'a> WaitBuilder<'a> {
16    pub fn new(droid: &'a mut Droid, target: Target) -> Self {
17        let timeout = droid.config.default_timeout;
18        let interval = droid.config.default_interval;
19        Self {
20            droid,
21            target,
22            timeout,
23            interval,
24            threshold: None,
25            search_rect: None,
26        }
27    }
28
29    pub fn timeout(mut self, duration: Duration) -> Self {
30        self.timeout = duration;
31        self
32    }
33
34    pub fn interval(mut self, duration: Duration) -> Self {
35        self.interval = duration;
36        self
37    }
38
39    pub fn threshold(mut self, value: f32) -> Self {
40        self.threshold = Some(value);
41        self
42    }
43
44    pub fn search_in(mut self, rect: RelativeRect) -> Self {
45        self.search_rect = Some(rect);
46        self
47    }
48
49    pub fn execute(self) -> Result<Point> {
50        let start_time = Instant::now();
51        log::info!(
52            "Waiting for target {:?} to appear, timeout: {:?}",
53            self.target,
54            self.timeout
55        );
56
57        let threshold = self
58            .threshold
59            .unwrap_or(self.droid.config.default_confidence);
60
61        loop {
62            if start_time.elapsed() > self.timeout {
63                log::warn!("Wait operation timed out after {:?}", self.timeout);
64                return Err(DroidError::Timeout(self.timeout));
65            }
66
67            match self
68                .droid
69                .resolve_target(&self.target, threshold, self.search_rect)
70            {
71                Ok(point) => {
72                    log::info!("Target found at {:?}. Wait successful.", point);
73                    return Ok(point);
74                }
75                Err(DroidError::ImageNotFound(_)) => {
76                    log::trace!("Target not found yet, retrying after {:?}", self.interval);
77                }
78                Err(e) => {
79                    log::error!("An unrecoverable error occurred while waiting: {:?}", e);
80                    return Err(e);
81                }
82            }
83
84            std::thread::sleep(self.interval);
85        }
86    }
87}