feat: integrate DWN protocols with content and federation flows

- SCHEMA-03: content.add now writes DWN file-catalog/v1 message alongside
  the existing catalog entry. File metadata queryable via dwn.query-messages.
- SCHEMA-04: federation.join now writes DWN federation/v1 membership message.
  Federation relationships queryable via DWN protocol filter.

Both integrations are non-fatal on DWN errors (existing flows unaffected).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-14 03:50:44 +00:00
parent 6da58943a7
commit fdb890e78a
3 changed files with 62 additions and 3 deletions

View File

@@ -1,8 +1,11 @@
use super::RpcHandler;
use crate::content_server::{self, AccessControl, Availability, ContentItem};
use crate::network::dwn_store::DwnStore;
use anyhow::{Context, Result};
use tracing::debug;
const FILE_CATALOG_PROTOCOL: &str = "https://archipelago.dev/protocols/file-catalog/v1";
impl RpcHandler {
/// List content I'm sharing.
pub(super) async fn handle_content_list_mine(
@@ -49,6 +52,36 @@ impl RpcHandler {
}
content_server::add_item(&self.config.data_dir, item.clone()).await?;
// Also store as DWN message for interoperable file catalog
if let Ok(store) = DwnStore::new(&self.config.data_dir).await {
let did = crate::identity::did_key_from_pubkey_hex(
&self.state_manager.get_snapshot().await.0.server_info.pubkey,
)
.unwrap_or_default();
let dwn_data = serde_json::json!({
"id": item.id,
"title": item.filename,
"description": item.description,
"content_type": item.mime_type,
"size_bytes": item.size_bytes,
"access": format!("{:?}", item.access).to_lowercase(),
"created_at": item.added_at,
});
if let Err(e) = store
.write_message(
&did,
Some(FILE_CATALOG_PROTOCOL),
Some("https://archipelago.dev/schemas/file-entry/v1"),
Some("application/json"),
Some(dwn_data),
)
.await
{
debug!("DWN file catalog write (non-fatal): {}", e);
}
}
Ok(serde_json::json!({ "item": item }))
}

View File

@@ -1,8 +1,11 @@
use super::RpcHandler;
use crate::federation::{self, FederatedNode, TrustLevel};
use crate::identity;
use crate::network::dwn_store::DwnStore;
use anyhow::Result;
use tracing::info;
use tracing::{debug, info};
const FEDERATION_PROTOCOL: &str = "https://archipelago.dev/protocols/federation/v1";
/// Validate a DID parameter: must start with "did:", max 256 chars, no path traversal.
fn validate_did(did: &str) -> Result<()> {
@@ -70,6 +73,29 @@ impl RpcHandler {
.await?;
info!(peer_did = %node.did, "Joined federation with peer");
// Store federation membership as DWN message
if let Ok(store) = DwnStore::new(&self.config.data_dir).await {
let dwn_data = serde_json::json!({
"node_did": node.did,
"trust_level": node.trust_level.to_string(),
"joined_at": chrono::Utc::now().to_rfc3339(),
"apps": [],
});
if let Err(e) = store
.write_message(
&local_did,
Some(FEDERATION_PROTOCOL),
Some("https://archipelago.dev/schemas/federation-membership/v1"),
Some("application/json"),
Some(dwn_data),
)
.await
{
debug!("DWN federation membership write (non-fatal): {}", e);
}
}
Ok(serde_json::json!({
"joined": true,
"node": {