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!("fedimint-recurringdv2", "--bind-api", bind_address.clone()),
29 )
30 .await?;
31
32 let recurringdv2 = Self {
33 process,
34 addr: bind_address,
35 api_url,
36 };
37
38 poll("waiting for recurringdv2 to be ready", || async {
39 match get(format!("http://{}", recurringdv2.addr)).await {
40 Ok(response) if response.status().is_success() => Ok(()),
41 _ => {
42 sleep(tokio::time::Duration::from_millis(100)).await;
43 Err(ControlFlow::Continue(anyhow::anyhow!(
44 "recurringdv2 not ready yet"
45 )))
46 }
47 }
48 })
49 .await?;
50
51 info!("Recurringdv2 started at {}", recurringdv2.addr);
52 Ok(recurringdv2)
53 }
54
55 pub async fn terminate(self) -> Result<()> {
56 self.process.terminate().await
57 }
58
59 pub fn api_url(&self) -> SafeUrl {
60 self.api_url.clone()
61 }
62}