New mesh_node.rs providing a production-ready node: - MeshNodeBuilder for fluent configuration - MeshConfig integration for all settings - MeshMetrics tracking for all operations - Rate limiting on incoming messages - Backpressure controller - Graceful shutdown via ShutdownCoordinator - Optional FappRouter based on capabilities - MeshRouter for envelope routing - TransportManager for multi-transport support Key APIs: - MeshNodeBuilder::new().fapp_relay().build() - node.process_incoming() with rate limiting + metrics - node.gc() for store/routing table cleanup - node.shutdown() for graceful termination 222 tests passing (203 lib + 3 fapp_flow + 16 multi_node)
87 lines
2.8 KiB
Rust
87 lines
2.8 KiB
Rust
//! FAPP Service Demo
|
|
//!
|
|
//! Demonstrates therapist announcement and patient query flow.
|
|
|
|
use meshservice::{
|
|
capabilities,
|
|
identity::ServiceIdentity,
|
|
router::ServiceRouter,
|
|
services::fapp::{create_announce, create_query, FappService, Modality, SlotAnnounce, SlotQuery, Specialism},
|
|
};
|
|
|
|
fn main() {
|
|
println!("=== FAPP Service Demo ===\n");
|
|
|
|
// Create identities
|
|
let therapist = ServiceIdentity::generate();
|
|
let patient = ServiceIdentity::generate();
|
|
let relay = ServiceIdentity::generate();
|
|
|
|
println!("Therapist address: {:?}", hex(&therapist.address()));
|
|
println!("Patient address: {:?}", hex(&patient.address()));
|
|
println!("Relay address: {:?}\n", hex(&relay.address()));
|
|
|
|
// Create router with FAPP service
|
|
let mut router = ServiceRouter::new(capabilities::RELAY);
|
|
router.register(Box::new(FappService::relay()));
|
|
|
|
// Therapist creates announcement
|
|
let announce = SlotAnnounce::new(
|
|
&[Specialism::CognitiveBehavioral, Specialism::TraumaFocused],
|
|
Modality::VideoCall,
|
|
"104", // Berlin Kreuzberg
|
|
)
|
|
.with_slots(3)
|
|
.with_profile("https://therapists.de/dr-schmidt")
|
|
.with_name("Dr. Anna Schmidt");
|
|
|
|
println!("Therapist announces:");
|
|
println!(" Specialisms: CBT, Trauma");
|
|
println!(" Modality: Video");
|
|
println!(" Location: 104xx");
|
|
println!(" Slots: 3");
|
|
println!(" Profile: https://therapists.de/dr-schmidt\n");
|
|
|
|
let msg = create_announce(&therapist, &announce, 1).unwrap();
|
|
let action = router.handle(msg.clone(), Some(therapist.public_key())).unwrap();
|
|
println!("Router action: {:?}", action);
|
|
println!("Stored messages: {}\n", router.store().len());
|
|
|
|
// Patient creates query
|
|
let query = SlotQuery::new(Specialism::CognitiveBehavioral, "104")
|
|
.with_modality(Modality::VideoCall)
|
|
.with_max_wait(30);
|
|
|
|
println!("Patient queries:");
|
|
println!(" Looking for: CBT");
|
|
println!(" Location: 104xx");
|
|
println!(" Modality: Video");
|
|
println!(" Max wait: 30 days\n");
|
|
|
|
let query_msg = create_query(&patient, &query).unwrap();
|
|
|
|
// Find matches
|
|
let matches = router.query(&query_msg);
|
|
println!("Found {} matching therapist(s):", matches.len());
|
|
|
|
for (i, m) in matches.iter().enumerate() {
|
|
if let Ok(data) = meshservice::services::fapp::SlotAnnounce::from_bytes(&m.message.payload) {
|
|
println!(" {}. {} in {}xx ({} slots)",
|
|
i + 1,
|
|
data.display_name.as_deref().unwrap_or("Unknown"),
|
|
data.postal_prefix,
|
|
data.available_slots
|
|
);
|
|
if let Some(profile) = &data.profile_url {
|
|
println!(" Verify: {}", profile);
|
|
}
|
|
}
|
|
}
|
|
|
|
println!("\n=== Demo Complete ===");
|
|
}
|
|
|
|
fn hex(bytes: &[u8]) -> String {
|
|
bytes.iter().map(|b| format!("{b:02x}")).collect()
|
|
}
|