-
Notifications
You must be signed in to change notification settings - Fork 77
Payjoin-cli should cache ohttp-keys for re-use #1035
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,9 +1,16 @@ | ||||||
| use std::fs; | ||||||
| use std::path::PathBuf; | ||||||
| use std::sync::{Arc, Mutex}; | ||||||
| use std::time::{Duration, SystemTime}; | ||||||
|
|
||||||
| use anyhow::{anyhow, Result}; | ||||||
| use serde::{Deserialize, Serialize}; | ||||||
|
|
||||||
| use super::Config; | ||||||
|
|
||||||
| // 6 months | ||||||
| const CACHE_DURATION: Duration = Duration::from_secs(6 * 30 * 24 * 60 * 60); | ||||||
|
|
||||||
| #[derive(Debug, Clone)] | ||||||
| pub struct RelayManager { | ||||||
| selected_relay: Option<url::Url>, | ||||||
|
|
@@ -38,12 +45,12 @@ pub(crate) async fn unwrap_ohttp_keys_or_else_fetch( | |||||
| ohttp_keys, | ||||||
| relay_url: config.v2()?.ohttp_relays[0].clone(), | ||||||
| }); | ||||||
| } else { | ||||||
| println!("Bootstrapping private network transport over Oblivious HTTP"); | ||||||
| let fetched_keys = fetch_ohttp_keys(config, directory, relay_manager).await?; | ||||||
|
|
||||||
| Ok(fetched_keys) | ||||||
| } | ||||||
|
|
||||||
| println!("Bootstrapping private network transport over Oblivious HTTP"); | ||||||
| let fetched_keys = fetch_ohttp_keys(config, directory, relay_manager).await?; | ||||||
|
|
||||||
| Ok(fetched_keys) | ||||||
| } | ||||||
|
|
||||||
| async fn fetch_ohttp_keys( | ||||||
|
|
@@ -77,6 +84,17 @@ async fn fetch_ohttp_keys( | |||||
| .expect("Lock should not be poisoned") | ||||||
| .set_selected_relay(selected_relay.clone()); | ||||||
|
|
||||||
| // try cache for this selected relay first | ||||||
| if let Some(cached) = read_cached_ohttp_keys(&selected_relay) { | ||||||
| println!("using Cached keys for relay: {selected_relay}"); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| if !is_expired(&cached) && cached.relay_url == selected_relay { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would |
||||||
| return Ok(ValidatedOhttpKeys { | ||||||
| ohttp_keys: cached.keys, | ||||||
| relay_url: cached.relay_url, | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| let ohttp_keys = { | ||||||
| #[cfg(feature = "_manual-tls")] | ||||||
| { | ||||||
|
|
@@ -101,8 +119,17 @@ async fn fetch_ohttp_keys( | |||||
| }; | ||||||
|
|
||||||
| match ohttp_keys { | ||||||
| Ok(keys) => | ||||||
| return Ok(ValidatedOhttpKeys { ohttp_keys: keys, relay_url: selected_relay }), | ||||||
| Ok(keys) => { | ||||||
| // Cache the keys if they are not already cached for this relay | ||||||
| if read_cached_ohttp_keys(&selected_relay).is_none() { | ||||||
| if let Err(e) = cache_ohttp_keys(&keys, &selected_relay) { | ||||||
| tracing::debug!( | ||||||
| "Failed to cache OHTTP keys for relay {selected_relay}: {e:?}" | ||||||
| ); | ||||||
| } | ||||||
| } | ||||||
| return Ok(ValidatedOhttpKeys { ohttp_keys: keys, relay_url: selected_relay }); | ||||||
| } | ||||||
| Err(payjoin::io::Error::UnexpectedStatusCode(e)) => { | ||||||
| return Err(payjoin::io::Error::UnexpectedStatusCode(e).into()); | ||||||
| } | ||||||
|
|
@@ -116,3 +143,49 @@ async fn fetch_ohttp_keys( | |||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| #[derive(Serialize, Deserialize, Debug)] | ||||||
| struct CachedOhttpKeys { | ||||||
| keys: payjoin::OhttpKeys, | ||||||
| relay_url: url::Url, | ||||||
| fetched_at: u64, | ||||||
| } | ||||||
|
|
||||||
| fn get_cache_file(relay_url: &url::Url) -> PathBuf { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are cached keys not being persisted in the database? |
||||||
| dirs::cache_dir() | ||||||
| .unwrap() | ||||||
| .join("payjoin-cli") | ||||||
| .join(relay_url.host_str().unwrap()) | ||||||
| .join("ohttp-keys.json") | ||||||
| } | ||||||
|
|
||||||
| fn read_cached_ohttp_keys(relay_url: &url::Url) -> Option<CachedOhttpKeys> { | ||||||
| let cache_file = get_cache_file(relay_url); | ||||||
| if !cache_file.exists() { | ||||||
| return None; | ||||||
| } | ||||||
| let data = fs::read_to_string(cache_file).ok().unwrap(); | ||||||
| serde_json::from_str(&data).ok() | ||||||
| } | ||||||
|
|
||||||
| fn cache_ohttp_keys(ohttp_keys: &payjoin::OhttpKeys, relay_url: &url::Url) -> Result<()> { | ||||||
| let cached = CachedOhttpKeys { | ||||||
| keys: ohttp_keys.clone(), | ||||||
| relay_url: relay_url.clone(), | ||||||
| fetched_at: SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(), | ||||||
| }; | ||||||
|
|
||||||
| let serialized = serde_json::to_string(&cached)?; | ||||||
| let path = get_cache_file(relay_url); | ||||||
| fs::create_dir_all(path.parent().unwrap())?; | ||||||
| fs::write(path, serialized)?; | ||||||
| Ok(()) | ||||||
| } | ||||||
|
|
||||||
| fn is_expired(cached_keys: &CachedOhttpKeys) -> bool { | ||||||
| let now = SystemTime::now() | ||||||
| .duration_since(SystemTime::UNIX_EPOCH) | ||||||
| .unwrap_or(Duration::ZERO) | ||||||
| .as_secs(); | ||||||
| now.saturating_sub(cached_keys.fetched_at) > CACHE_DURATION.as_secs() | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the logger instead of println?