feat(messaging,dwn,mesh): route peer messaging + DWN sync + blob fetch via FIPS first
Migrates the remaining Tor-direct peer call sites to PeerRequest so FIPS is the default when the peer is federated and running the daemon: - node_message::send_to_peer / check_peer_reachable: gain a fips_npub parameter. Error messages updated to reference both transports. - Callers (api/rpc/network.rs, api/rpc/peers.rs, server health loop): look up fips_npub from federation storage by onion and pass it. - mesh::send_typed_wire_via_federation: the spawned background POST for the /archipelago/mesh-typed endpoint now uses PeerRequest with federation-resolved fips_npub. Signature domain unchanged. - api/rpc/mesh/typed_messages.rs fetch_blob_from_peer: blob URL rebuilt as (base_url, path_with_query) so PeerRequest can append the query string after swapping the host. Cap/exp/peer parameters are still signed over the content ref itself, so transport choice is invisible to the signature. - network/dwn_sync.rs sync_with_peers: per-peer fips_npub lookup before sync_single_peer; health/pull/push each dial through PeerRequest, so any DWN peer known to federation gets FIPS. Left Tor-only on purpose: - api/rpc/identity/handlers.rs handle_identity_resolve_peer_onion — resolving TO a DID, no anchor yet. - content.browse / preview calls to non-federated peers fall through to Tor naturally inside PeerRequest (no fips_npub → skip FIPS branch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -104,16 +104,6 @@ pub async fn sync_with_peers(data_dir: &Path, peer_onions: &[String]) -> Result<
|
||||
state.status = SyncStatus::Syncing;
|
||||
save_sync_state(data_dir, &state).await?;
|
||||
|
||||
let socks_proxy = reqwest::Proxy::all(crate::constants::TOR_SOCKS_PROXY)
|
||||
.context("Failed to create SOCKS proxy")?;
|
||||
|
||||
let client = reqwest::Client::builder()
|
||||
.proxy(socks_proxy)
|
||||
.connect_timeout(std::time::Duration::from_secs(15))
|
||||
.timeout(std::time::Duration::from_secs(30))
|
||||
.build()
|
||||
.context("Failed to build Tor HTTP client")?;
|
||||
|
||||
let store = DwnStore::new(data_dir).await?;
|
||||
let mut synced_count = 0u64;
|
||||
|
||||
@@ -142,7 +132,15 @@ pub async fn sync_with_peers(data_dir: &Path, peer_onions: &[String]) -> Result<
|
||||
// Overall sync timeout: 90 seconds
|
||||
let sync_future = async {
|
||||
for onion in &unique_onions {
|
||||
match sync_single_peer(&client, &store, onion, &local_messages, &state.last_sync).await
|
||||
let fips_npub = crate::federation::fips_npub_for_onion(data_dir, onion).await;
|
||||
match sync_single_peer(
|
||||
fips_npub.as_deref(),
|
||||
&store,
|
||||
onion,
|
||||
&local_messages,
|
||||
&state.last_sync,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(count) => {
|
||||
debug!(peer = %onion, messages = count, "Peer sync complete");
|
||||
@@ -173,29 +171,28 @@ pub async fn sync_with_peers(data_dir: &Path, peer_onions: &[String]) -> Result<
|
||||
}
|
||||
|
||||
/// Sync with a single peer: pull their messages and push ours.
|
||||
/// Each HTTP call picks FIPS when a npub is known, otherwise Tor.
|
||||
async fn sync_single_peer(
|
||||
client: &reqwest::Client,
|
||||
fips_npub: Option<&str>,
|
||||
store: &crate::network::dwn_store::DwnStore,
|
||||
onion: &str,
|
||||
local_messages: &[crate::network::dwn_store::DwnMessage],
|
||||
last_sync: &Option<String>,
|
||||
) -> Result<u64> {
|
||||
let base_url = format!("http://{}", onion);
|
||||
use crate::fips::dial::PeerRequest;
|
||||
let mut imported = 0u64;
|
||||
|
||||
// Step 1: Check peer health
|
||||
let health_url = format!("{}/dwn/health", base_url);
|
||||
let res = client
|
||||
.get(&health_url)
|
||||
.send()
|
||||
let (health_resp, _) = PeerRequest::new(fips_npub, onion, "/dwn/health")
|
||||
.timeout(std::time::Duration::from_secs(30))
|
||||
.send_get()
|
||||
.await
|
||||
.context("Peer DWN unreachable")?;
|
||||
if !res.status().is_success() {
|
||||
if !health_resp.status().is_success() {
|
||||
return Err(anyhow::anyhow!("Peer DWN not healthy"));
|
||||
}
|
||||
|
||||
// Step 2: Pull — query peer for messages since our last sync
|
||||
let dwn_url = format!("{}/dwn", base_url);
|
||||
let mut query_filter = serde_json::json!({});
|
||||
if let Some(ref since) = last_sync {
|
||||
query_filter = serde_json::json!({ "dateSort": "createdAscending", "dateFrom": since });
|
||||
@@ -210,10 +207,9 @@ async fn sync_single_peer(
|
||||
}]
|
||||
});
|
||||
|
||||
let pull_res = client
|
||||
.post(&dwn_url)
|
||||
.json(&pull_body)
|
||||
.send()
|
||||
let (pull_res, _) = PeerRequest::new(fips_npub, onion, "/dwn")
|
||||
.timeout(std::time::Duration::from_secs(30))
|
||||
.send_json(&pull_body)
|
||||
.await
|
||||
.context("Failed to query peer DWN")?;
|
||||
|
||||
@@ -267,10 +263,14 @@ async fn sync_single_peer(
|
||||
|
||||
let push_body = serde_json::json!({ "messages": messages });
|
||||
|
||||
// Best-effort push — don't fail the whole sync if a batch fails
|
||||
match client.post(&dwn_url).json(&push_body).send().await {
|
||||
Ok(_) => {
|
||||
debug!(count = chunk.len(), "Pushed message batch to peer");
|
||||
// Best-effort push — don't fail the whole sync if a batch fails.
|
||||
match PeerRequest::new(fips_npub, onion, "/dwn")
|
||||
.timeout(std::time::Duration::from_secs(30))
|
||||
.send_json(&push_body)
|
||||
.await
|
||||
{
|
||||
Ok((_, t)) => {
|
||||
debug!(count = chunk.len(), transport = %t, "Pushed message batch to peer");
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(error = %e, "Failed to push message batch to peer");
|
||||
|
||||
Reference in New Issue
Block a user