Skip to content

Commit 27c936f

Browse files
committed
Payjoin-cli should cache ohttp-keys for re-use
This pr adds the functionality of ohttp-keys catching to payjoin-cli , ohttp-keys should not be fetched each time and a cached key should be use. Keys expire in 6 months .
1 parent 8efe975 commit 27c936f

1 file changed

Lines changed: 67 additions & 4 deletions

File tree

payjoin-cli/src/app/v2/ohttp.rs

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
use std::fs;
2+
use std::path::PathBuf;
13
use std::sync::{Arc, Mutex};
4+
use std::time::{Duration, SystemTime};
25

36
use anyhow::{anyhow, Result};
7+
use serde::{Deserialize, Serialize};
48

59
use super::Config;
610

11+
// 6 months
12+
const CACHE_DURATION: Duration = Duration::from_secs(6 * 30 * 24 * 60 * 60);
13+
714
#[derive(Debug, Clone)]
815
pub struct RelayManager {
916
selected_relay: Option<payjoin::Url>,
@@ -38,12 +45,24 @@ pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
3845
ohttp_keys,
3946
relay_url: config.v2()?.ohttp_relays[0].clone(),
4047
});
41-
} else {
42-
println!("Bootstrapping private network transport over Oblivious HTTP");
43-
let fetched_keys = fetch_ohttp_keys(config, directory, relay_manager).await?;
48+
}
4449

45-
Ok(fetched_keys)
50+
if let Some(cached_keys) = read_cached_ohttp_keys() {
51+
if !is_expired(&cached_keys) {
52+
println!("Using cached OHTTP keys");
53+
return Ok(ValidatedOhttpKeys {
54+
ohttp_keys: cached_keys.keys,
55+
relay_url: cached_keys.relay_url,
56+
});
57+
}
4658
}
59+
println!("Bootstrapping private network transport over Oblivious HTTP");
60+
let fetched_keys = fetch_ohttp_keys(config, directory, relay_manager).await?;
61+
62+
// save the keys to cache
63+
cache_ohttp_keys(&fetched_keys.ohttp_keys, &fetched_keys.relay_url)?;
64+
65+
Ok(fetched_keys)
4766
}
4867

4968
async fn fetch_ohttp_keys(
@@ -112,3 +131,47 @@ async fn fetch_ohttp_keys(
112131
}
113132
}
114133
}
134+
135+
#[derive(Serialize, Deserialize, Debug)]
136+
struct CachedOhttpKeys {
137+
keys: payjoin::OhttpKeys,
138+
relay_url: payjoin::Url,
139+
fetched_at: u64,
140+
}
141+
142+
fn get_cache_file() -> PathBuf {
143+
let dir = dirs::cache_dir().unwrap();
144+
println!("Getting cache file {:?}", dir);
145+
dirs::cache_dir().unwrap().join("payjoin-cli").join("ohttp-keys.json")
146+
}
147+
148+
fn read_cached_ohttp_keys() -> Option<CachedOhttpKeys> {
149+
let cache_file = get_cache_file();
150+
if !cache_file.exists() {
151+
return None;
152+
}
153+
let data = fs::read_to_string(cache_file).ok().unwrap();
154+
serde_json::from_str(&data).ok()
155+
}
156+
157+
fn cache_ohttp_keys(ohttp_keys: &payjoin::OhttpKeys, relay_url: &payjoin::Url) -> Result<()> {
158+
let cached = CachedOhttpKeys {
159+
keys: ohttp_keys.clone(),
160+
relay_url: relay_url.clone(),
161+
fetched_at: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(),
162+
};
163+
164+
let serialized = serde_json::to_string(&cached)?;
165+
let path = get_cache_file();
166+
fs::create_dir_all(path.parent().unwrap())?;
167+
fs::write(path, serialized)?;
168+
Ok(())
169+
}
170+
171+
fn is_expired(cached_keys: &CachedOhttpKeys) -> bool {
172+
let now = SystemTime::now()
173+
.duration_since(SystemTime::UNIX_EPOCH)
174+
.unwrap_or(Duration::ZERO)
175+
.as_secs();
176+
now.saturating_sub(cached_keys.fetched_at) > CACHE_DURATION.as_secs()
177+
}

0 commit comments

Comments
 (0)