• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payjoin / rust-payjoin / 17649311628

11 Sep 2025 03:22PM UTC coverage: 85.971% (-0.05%) from 86.019%
17649311628

Pull #1057

github

web-flow
Merge b53dc45c4 into 52cfeef1a
Pull Request #1057: Remove use of payjoin::Url and url::Url in public Api

150 of 161 new or added lines in 14 files covered. (93.17%)

8 existing lines in 3 files now uncovered.

8230 of 9573 relevant lines covered (85.97%)

488.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.69
/payjoin-cli/src/app/v2/ohttp.rs
1
use std::sync::{Arc, Mutex};
2

3
use anyhow::{anyhow, Result};
4

5
use super::Config;
6

7
#[derive(Debug, Clone)]
8
pub struct RelayManager {
9
    selected_relay: Option<String>,
10
    failed_relays: Vec<String>,
11
}
12

13
impl RelayManager {
14
    pub fn new() -> Self { RelayManager { selected_relay: None, failed_relays: Vec::new() } }
7✔
15

16
    pub fn set_selected_relay(&mut self, relay: String) { self.selected_relay = Some(relay); }
3✔
17

18
    pub fn get_selected_relay(&self) -> Option<String> { self.selected_relay.clone() }
8✔
19

NEW
20
    pub fn add_failed_relay(&mut self, relay: String) { self.failed_relays.push(relay); }
×
21

22
    pub fn get_failed_relays(&self) -> Vec<String> { self.failed_relays.clone() }
3✔
23
}
24

25
pub(crate) struct ValidatedOhttpKeys {
26
    pub(crate) ohttp_keys: payjoin::OhttpKeys,
27
    pub(crate) relay_url: String,
28
}
29

30
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
6✔
31
    config: &Config,
6✔
32
    directory: Option<String>,
6✔
33
    relay_manager: Arc<Mutex<RelayManager>>,
6✔
34
) -> Result<ValidatedOhttpKeys> {
6✔
35
    if let Some(ohttp_keys) = config.v2()?.ohttp_keys.clone() {
6✔
36
        println!("Using OHTTP Keys from config");
3✔
37
        return Ok(ValidatedOhttpKeys {
38
            ohttp_keys,
3✔
39
            relay_url: config.v2()?.ohttp_relays[0].clone(),
3✔
40
        });
41
    } else {
42
        println!("Bootstrapping private network transport over Oblivious HTTP");
3✔
43
        let fetched_keys = fetch_ohttp_keys(
3✔
44
            config,
3✔
45
            directory.unwrap_or(config.v2()?.pj_directory.clone()),
3✔
46
            relay_manager,
3✔
47
        )
48
        .await?;
3✔
49

50
        Ok(fetched_keys)
3✔
51
    }
52
}
6✔
53

54
async fn fetch_ohttp_keys(
3✔
55
    config: &Config,
3✔
56
    directory: String,
3✔
57
    relay_manager: Arc<Mutex<RelayManager>>,
3✔
58
) -> Result<ValidatedOhttpKeys> {
3✔
59
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
60
    let relays = config.v2()?.ohttp_relays.clone();
3✔
61

62
    loop {
63
        let failed_relays =
3✔
64
            relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
3✔
65

66
        let remaining_relays: Vec<_> =
3✔
67
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
3✔
68

69
        if remaining_relays.is_empty() {
3✔
70
            return Err(anyhow!("No valid relays available"));
×
71
        }
3✔
72

73
        let selected_relay =
3✔
74
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
3✔
75
                Some(relay) => relay.clone(),
3✔
76
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
77
            };
78

79
        relay_manager
3✔
80
            .lock()
3✔
81
            .expect("Lock should not be poisoned")
3✔
82
            .set_selected_relay(selected_relay.clone());
3✔
83

84
        let ohttp_keys = {
3✔
85
            #[cfg(feature = "_manual-tls")]
86
            {
87
                if let Some(cert_path) = config.root_certificate.as_ref() {
3✔
88
                    let cert_der = std::fs::read(cert_path)?;
3✔
89
                    payjoin::io::fetch_ohttp_keys_with_cert(&selected_relay, &directory, cert_der)
3✔
90
                        .await
3✔
91
                } else {
NEW
92
                    payjoin::io::fetch_ohttp_keys(&selected_relay, &directory).await
×
93
                }
94
            }
95
            #[cfg(not(feature = "_manual-tls"))]
96
            payjoin::io::fetch_ohttp_keys(&selected_relay, &directory).await
97
        };
98

99
        match ohttp_keys {
×
100
            Ok(keys) => {
3✔
101
                return Ok(ValidatedOhttpKeys { ohttp_keys: keys, relay_url: selected_relay });
3✔
102
            }
103
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
104
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
105
            }
106
            Err(e) => {
×
107
                tracing::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
108
                relay_manager
×
109
                    .lock()
×
110
                    .expect("Lock should not be poisoned")
×
111
                    .add_failed_relay(selected_relay);
×
112
            }
113
        }
114
    }
115
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc