1use std::ops::ControlFlow;
2
3use anyhow::Result;
4use fedimint_core::task::sleep;
5use fedimint_core::util::SafeUrl;
6use reqwest::get;
7use tracing::info;
8
9use crate::cmd;
10use crate::util::{ProcessHandle, ProcessManager, poll};
11
12#[derive(Clone)]
13pub struct Recurringdv2 {
14 pub(crate) process: ProcessHandle,
15 pub addr: String,
16 pub api_url: SafeUrl,
17}
18
19impl Recurringdv2 {
20 pub async fn new(process_mgr: &ProcessManager) -> Result<Self> {
21 let port = process_mgr.globals.FM_PORT_RECURRINGDV2;
22 let bind_address = format!("127.0.0.1:{port}");
23 let api_url = SafeUrl::parse(&format!("http://{bind_address}/")).expect("Valid URL");
24
25 let process = process_mgr
26 .spawn_daemon(
27 "recurringdv2",
28 cmd!(
29 "fedimint-recurringdv2",
30 "--bind-api",
31 bind_address.clone(),
32 "--api-address",
33 api_url.to_string()
34 ),
35 )
36 .await?;
37
38 let recurringdv2 = Self {
39 process,
40 addr: bind_address,
41 api_url,
42 };
43
44 poll("waiting for recurringdv2 to be ready", || async {
45 match get(format!("http://{}", recurringdv2.addr)).await {
46 Ok(response) if response.status().is_success() => Ok(()),
47 _ => {
48 sleep(tokio::time::Duration::from_millis(100)).await;
49 Err(ControlFlow::Continue(anyhow::anyhow!(
50 "recurringdv2 not ready yet"
51 )))
52 }
53 }
54 })
55 .await?;
56
57 info!("Recurringdv2 started at {}", recurringdv2.addr);
58 Ok(recurringdv2)
59 }
60
61 pub async fn terminate(self) -> Result<()> {
62 self.process.terminate().await
63 }
64
65 pub fn api_url(&self) -> SafeUrl {
66 self.api_url.clone()
67 }
68}