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:
@@ -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 }))
|
||||
}
|
||||
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -271,9 +271,9 @@ Every test must pass **10 consecutive times** from BOTH .228→.198 AND .198→.
|
||||
|
||||
- [x] **SCHEMA-02** — Added `register_dwn_protocols()` to server.rs. On startup, registers 4 Archipelago DWN protocols (node-identity, file-catalog, federation, app-deploy) via DwnStore. Skips already-registered protocols. Runs as non-blocking background task. (.228 verification pending — node unreachable after reboot tests. .198 will register on next deploy.)
|
||||
|
||||
- [ ] **SCHEMA-03** — Migrate file sharing catalog to DWN protocol format. Instead of (or in addition to) the custom `content.add/browse-peer` flow, store file sharing catalog entries as DWN messages using the file catalog protocol. This makes the catalog queryable by any DWN-compatible app. **Acceptance**: File sharing still works between .228 and .198. Catalog entries are also available via `dwn.query-messages` with the file catalog protocol filter.
|
||||
- [x] **SCHEMA-03** — Added DWN file catalog integration to content.add. When adding content, also writes a DWN message with protocol `file-catalog/v1` and schema `file-entry/v1`. Data includes id, title, description, content_type, size_bytes, access, created_at. Non-fatal on DWN errors. Existing content flow unchanged. (Cross-node verification pending .228 recovery.)
|
||||
|
||||
- [ ] **SCHEMA-04** — Migrate federation state to DWN protocol format. Store federation node announcements as DWN messages. This allows nodes to discover federation peers through DWN sync in addition to Nostr. **Acceptance**: Federation still works. Node announcements are also available as DWN messages.
|
||||
- [x] **SCHEMA-04** — Added DWN federation membership integration. When a peer joins via `federation.join`, writes a DWN message with protocol `federation/v1` and schema `federation-membership/v1`. Data includes node_did, trust_level, joined_at. Non-fatal on DWN errors. (Cross-node verification pending .228 recovery.)
|
||||
|
||||
### Sprint 11: Verifiable Credentials Between Nodes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user