bsv_wallet_toolbox/monitor/tasks/
task_check_no_sends.rs1use std::sync::atomic::{AtomicU32, Ordering};
10use std::sync::Arc;
11
12use async_trait::async_trait;
13
14use crate::error::WalletError;
15use crate::monitor::helpers::now_msecs;
16use crate::monitor::task_trait::WalletMonitorTask;
17use crate::monitor::ONE_DAY;
18use crate::services::traits::WalletServices;
19use crate::status::ProvenTxReqStatus;
20use crate::storage::find_args::{FindProvenTxReqsArgs, Paged, ProvenTxReqPartial};
21use crate::storage::manager::WalletStorageManager;
22use crate::storage::traits::reader::StorageReader;
23use crate::types::Chain;
24
25pub struct TaskCheckNoSends {
27 storage: WalletStorageManager,
28 services: Arc<dyn WalletServices>,
29 chain: Chain,
30 trigger_msecs: u64,
31 last_run_msecs: u64,
32 unproven_attempts_limit: u32,
33 pub check_now: bool,
35 last_new_header_height: Arc<AtomicU32>,
37}
38
39impl TaskCheckNoSends {
40 pub fn new(
42 storage: WalletStorageManager,
43 services: Arc<dyn WalletServices>,
44 chain: Chain,
45 unproven_attempts_limit: u32,
46 last_new_header_height: Arc<AtomicU32>,
47 ) -> Self {
48 Self {
49 storage,
50 services,
51 chain,
52 trigger_msecs: ONE_DAY,
53 last_run_msecs: 0,
54 unproven_attempts_limit,
55 check_now: false,
56 last_new_header_height,
57 }
58 }
59
60 pub fn with_trigger_msecs(mut self, msecs: u64) -> Self {
62 self.trigger_msecs = msecs;
63 self
64 }
65}
66
67#[async_trait]
68impl WalletMonitorTask for TaskCheckNoSends {
69 fn name(&self) -> &str {
70 "CheckNoSends"
71 }
72
73 fn trigger(&mut self, now_msecs: u64) -> bool {
74 self.check_now
75 || (self.trigger_msecs > 0 && now_msecs > self.last_run_msecs + self.trigger_msecs)
76 }
77
78 async fn run_task(&mut self) -> Result<String, WalletError> {
79 self.last_run_msecs = now_msecs();
80 let counts_as_attempt = self.check_now;
81 self.check_now = false;
82
83 let mut log = String::new();
84
85 let raw_height = self.last_new_header_height.load(Ordering::SeqCst);
87 let max_acceptable_height = if raw_height == u32::MAX {
88 return Ok(log);
89 } else {
90 Some(raw_height)
91 };
92
93 let limit = 100i64;
94 let mut offset = 0i64;
95 loop {
96 let reqs = self
97 .storage
98 .find_proven_tx_reqs(&FindProvenTxReqsArgs {
99 partial: ProvenTxReqPartial::default(),
100 since: None,
101 paged: Some(Paged { limit, offset }),
102 statuses: Some(vec![ProvenTxReqStatus::Nosend]),
103 })
104 .await?;
105
106 if reqs.is_empty() {
107 break;
108 }
109
110 log.push_str(&format!("{} reqs with status 'nosend'\n", reqs.len()));
111
112 let r = crate::monitor::helpers::get_proofs(
114 &self.storage,
115 &*self.services,
116 &reqs,
117 &self.chain,
118 self.unproven_attempts_limit,
119 counts_as_attempt,
120 max_acceptable_height,
121 )
122 .await?;
123 log.push_str(&r.log);
124 log.push('\n');
125
126 if (reqs.len() as i64) < limit {
127 break;
128 }
129 offset += limit;
130 }
131
132 Ok(log)
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use crate::monitor::ONE_DAY;
139
140 #[test]
141 fn test_check_no_sends_defaults() {
142 assert_eq!(ONE_DAY, 86_400_000);
143 }
144
145 #[test]
146 fn test_name() {
147 assert_eq!("CheckNoSends", "CheckNoSends");
148 }
149}