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

payjoin / rust-payjoin / 15454126991

04 Jun 2025 10:33PM UTC coverage: 85.192% (+0.1%) from 85.055%
15454126991

Pull #726

github

web-flow
Merge ba87a4169 into 1063687eb
Pull Request #726: Merge parallel feature flag local certificate logic in cli ohttp

32 of 33 new or added lines in 2 files covered. (96.97%)

12 existing lines in 1 file now uncovered.

6823 of 8009 relevant lines covered (85.19%)

579.55 hits per line

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

80.65
/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<payjoin::Url>,
10
    failed_relays: Vec<payjoin::Url>,
11
}
12

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

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

18
    pub fn get_selected_relay(&self) -> Option<payjoin::Url> { self.selected_relay.clone() }
6✔
19

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

22
    pub fn get_failed_relays(&self) -> Vec<payjoin::Url> { self.failed_relays.clone() }
4✔
23
}
24

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

30
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
4✔
31
    config: &Config,
4✔
32
    directory: Option<payjoin::Url>,
4✔
33
    relay_state: Arc<Mutex<RelayManager>>,
4✔
34
) -> Result<ValidatedOhttpKeys> {
4✔
35
    let config_keys = config.v2()?.ohttp_keys.clone();
4✔
36
    let mut fetched_keys = fetch_ohttp_keys(config, directory, relay_state).await?;
4✔
37

38
    if let Some(keys) = config_keys {
4✔
39
        fetched_keys.ohttp_keys = keys;
1✔
40
    }
3✔
41

42
    Ok(fetched_keys)
4✔
43
}
4✔
44

45
async fn fetch_ohttp_keys(
4✔
46
    config: &Config,
4✔
47
    directory: Option<payjoin::Url>,
4✔
48
    relay_manager: Arc<Mutex<RelayManager>>,
4✔
49
) -> Result<ValidatedOhttpKeys> {
4✔
50
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
51
    let payjoin_directory = directory.unwrap_or(config.v2()?.pj_directory.clone());
4✔
52
    let relays = config.v2()?.ohttp_relays.clone();
4✔
53

54
    loop {
4✔
55
        let failed_relays =
4✔
56
            relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
4✔
57

4✔
58
        let remaining_relays: Vec<_> =
4✔
59
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
4✔
60

4✔
61
        if remaining_relays.is_empty() {
4✔
UNCOV
62
            return Err(anyhow!("No valid relays available"));
×
63
        }
4✔
64

65
        let selected_relay =
4✔
66
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
4✔
67
                Some(relay) => relay.clone(),
4✔
UNCOV
68
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
69
            };
70

71
        relay_manager
4✔
72
            .lock()
4✔
73
            .expect("Lock should not be poisoned")
4✔
74
            .set_selected_relay(selected_relay.clone());
4✔
75

76
        let ohttp_keys = {
4✔
77
            #[cfg(feature = "_danger-local-https")]
78
            {
79
                let cert_der = crate::app::read_local_cert()?;
4✔
80
                payjoin::io::fetch_ohttp_keys_with_cert(
4✔
81
                    selected_relay.clone(),
4✔
82
                    payjoin_directory.clone(),
4✔
83
                    cert_der,
4✔
84
                )
4✔
85
                .await
4✔
86
            }
87
            #[cfg(not(feature = "_danger-local-https"))]
88
            {
89
                payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone())
90
                    .await
91
            }
92
        };
93

UNCOV
94
        match ohttp_keys {
×
95
            Ok(keys) =>
4✔
96
                return Ok(ValidatedOhttpKeys { ohttp_keys: keys, relay_url: selected_relay }),
4✔
UNCOV
97
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
NEW
UNCOV
98
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
99
            }
UNCOV
100
            Err(e) => {
×
UNCOV
101
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
UNCOV
102
                relay_manager
×
UNCOV
103
                    .lock()
×
UNCOV
104
                    .expect("Lock should not be poisoned")
×
UNCOV
105
                    .add_failed_relay(selected_relay);
×
106
            }
107
        }
108
    }
109
}
4✔
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