bsv_wallet_toolbox_rs/monitor/
config.rs1use std::sync::Arc;
4use std::time::Duration;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct TransactionStatusUpdate {
12 pub txid: String,
14 pub status: String,
16 pub merkle_root: Option<String>,
18 pub merkle_path: Option<String>,
20 pub block_height: Option<u32>,
22 pub block_hash: Option<String>,
24}
25
26#[derive(Clone)]
28pub struct MonitorOptions {
29 pub tasks: TasksConfig,
31 pub fail_abandoned_timeout: Duration,
33 pub on_tx_broadcasted: Option<Arc<dyn Fn(TransactionStatusUpdate) + Send + Sync>>,
35 pub on_tx_proven: Option<Arc<dyn Fn(TransactionStatusUpdate) + Send + Sync>>,
37}
38
39impl std::fmt::Debug for MonitorOptions {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("MonitorOptions")
42 .field("tasks", &self.tasks)
43 .field("fail_abandoned_timeout", &self.fail_abandoned_timeout)
44 .field(
45 "on_tx_broadcasted",
46 &self.on_tx_broadcasted.as_ref().map(|_| "Some(<callback>)"),
47 )
48 .field(
49 "on_tx_proven",
50 &self.on_tx_proven.as_ref().map(|_| "Some(<callback>)"),
51 )
52 .finish()
53 }
54}
55
56impl Default for MonitorOptions {
57 fn default() -> Self {
58 Self {
59 tasks: TasksConfig::default(),
60 fail_abandoned_timeout: Duration::from_secs(5 * 60), on_tx_broadcasted: None,
62 on_tx_proven: None,
63 }
64 }
65}
66
67#[derive(Debug, Clone)]
69pub struct TasksConfig {
70 pub check_for_proofs: TaskConfig,
72 pub send_waiting: TaskConfig,
74 pub fail_abandoned: TaskConfig,
76 pub unfail: TaskConfig,
78 pub clock: TaskConfig,
80 pub new_header: TaskConfig,
82 pub reorg: TaskConfig,
84 pub check_no_sends: TaskConfig,
86 pub review_status: TaskConfig,
88 pub purge: TaskConfig,
90 pub compact_beef: TaskConfig,
92 pub monitor_call_history: TaskConfig,
94 pub sync_when_idle: TaskConfig,
96}
97
98impl Default for TasksConfig {
99 fn default() -> Self {
100 Self {
101 check_for_proofs: TaskConfig {
102 enabled: true,
103 interval: Duration::from_secs(60), start_immediately: false,
105 },
106 send_waiting: TaskConfig {
107 enabled: true,
108 interval: Duration::from_secs(5 * 60), start_immediately: true,
110 },
111 fail_abandoned: TaskConfig {
112 enabled: true,
113 interval: Duration::from_secs(5 * 60), start_immediately: false,
115 },
116 unfail: TaskConfig {
117 enabled: true,
118 interval: Duration::from_secs(10 * 60), start_immediately: false,
120 },
121 clock: TaskConfig {
122 enabled: true,
123 interval: Duration::from_secs(1), start_immediately: true,
125 },
126 new_header: TaskConfig {
127 enabled: true,
128 interval: Duration::from_secs(60), start_immediately: false,
130 },
131 reorg: TaskConfig {
132 enabled: true,
133 interval: Duration::from_secs(60), start_immediately: false,
135 },
136 check_no_sends: TaskConfig {
137 enabled: true,
138 interval: Duration::from_secs(86400), start_immediately: false,
140 },
141 review_status: TaskConfig {
142 enabled: true,
143 interval: Duration::from_secs(900), start_immediately: false,
145 },
146 purge: TaskConfig {
147 enabled: true,
148 interval: Duration::from_secs(3600), start_immediately: false,
150 },
151 compact_beef: TaskConfig {
152 enabled: true,
153 interval: Duration::from_secs(15 * 60), start_immediately: false,
155 },
156 monitor_call_history: TaskConfig {
157 enabled: true,
158 interval: Duration::from_secs(720), start_immediately: false,
160 },
161 sync_when_idle: TaskConfig {
162 enabled: true,
163 interval: Duration::from_secs(60), start_immediately: false,
165 },
166 }
167 }
168}
169
170#[derive(Debug, Clone)]
172pub struct TaskConfig {
173 pub enabled: bool,
175 pub interval: Duration,
177 pub start_immediately: bool,
179}
180
181impl TaskConfig {
182 pub fn new(interval: Duration) -> Self {
184 Self {
185 enabled: true,
186 interval,
187 start_immediately: false,
188 }
189 }
190
191 pub fn disabled() -> Self {
193 Self {
194 enabled: false,
195 interval: Duration::from_secs(60),
196 start_immediately: false,
197 }
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_default_options() {
207 let opts = MonitorOptions::default();
208 assert!(opts.tasks.check_for_proofs.enabled);
209 assert!(opts.tasks.send_waiting.enabled);
210 assert!(opts.tasks.fail_abandoned.enabled);
211 assert!(opts.tasks.unfail.enabled);
212 assert!(opts.tasks.clock.enabled);
213 assert!(opts.tasks.new_header.enabled);
214 assert!(opts.tasks.reorg.enabled);
215 assert!(opts.tasks.check_no_sends.enabled);
216 assert!(opts.tasks.review_status.enabled);
217 assert!(opts.tasks.purge.enabled);
218 assert!(opts.tasks.monitor_call_history.enabled);
219 assert!(opts.tasks.sync_when_idle.enabled);
220 assert_eq!(opts.fail_abandoned_timeout, Duration::from_secs(5 * 60));
221 assert!(opts.on_tx_broadcasted.is_none());
222 assert!(opts.on_tx_proven.is_none());
223 }
224
225 #[test]
226 fn test_default_task_intervals() {
227 let opts = MonitorOptions::default();
228 assert_eq!(opts.tasks.clock.interval, Duration::from_secs(1));
229 assert!(opts.tasks.clock.start_immediately);
230 assert_eq!(opts.tasks.new_header.interval, Duration::from_secs(60));
231 assert!(!opts.tasks.new_header.start_immediately);
232 assert_eq!(opts.tasks.reorg.interval, Duration::from_secs(60));
233 assert_eq!(
234 opts.tasks.check_no_sends.interval,
235 Duration::from_secs(86400)
236 );
237 assert_eq!(opts.tasks.review_status.interval, Duration::from_secs(900));
238 assert_eq!(opts.tasks.purge.interval, Duration::from_secs(3600));
239 assert_eq!(
240 opts.tasks.monitor_call_history.interval,
241 Duration::from_secs(720)
242 );
243 assert_eq!(opts.tasks.sync_when_idle.interval, Duration::from_secs(60));
244 }
245
246 #[test]
247 fn test_task_config_new() {
248 let config = TaskConfig::new(Duration::from_secs(30));
249 assert!(config.enabled);
250 assert_eq!(config.interval, Duration::from_secs(30));
251 assert!(!config.start_immediately);
252 }
253
254 #[test]
255 fn test_task_config_disabled() {
256 let config = TaskConfig::disabled();
257 assert!(!config.enabled);
258 }
259
260 #[test]
261 fn test_transaction_status_update() {
262 let update = TransactionStatusUpdate {
263 txid: "abc123".to_string(),
264 status: "completed".to_string(),
265 merkle_root: Some("root".to_string()),
266 merkle_path: Some("path".to_string()),
267 block_height: Some(800000),
268 block_hash: Some("hash".to_string()),
269 };
270 assert_eq!(update.txid, "abc123");
271 assert_eq!(update.status, "completed");
272 assert_eq!(update.block_height, Some(800000));
273 }
274
275 #[test]
276 fn test_monitor_options_with_callbacks() {
277 let opts = MonitorOptions {
278 on_tx_broadcasted: Some(Arc::new(|_update| {
279 })),
281 on_tx_proven: Some(Arc::new(|_update| {
282 })),
284 ..MonitorOptions::default()
285 };
286 assert!(opts.on_tx_broadcasted.is_some());
287 assert!(opts.on_tx_proven.is_some());
288 }
289}