Skip to content

Commit 17bb6d6

Browse files
amituclaude
andcommitted
feat: implement beautiful nested protocol.command API
🎯 Revolutionary nested protocol architecture: Beautiful Nested API: fastn_p2p::serve_all() .protocol("mail.fastn.com", |p| p .handle_requests("inbox.get-mails", get_mails_handler) .handle_requests("send.send-mail", send_mail_handler) .handle_requests("settings.add-forwarding", forwarding_handler) ) .protocol("filetransfer.fastn.com", |p| p .handle_streams("transfer.large-file", large_file_handler) ) Benefits: - Clean protocol grouping (no flat tuples) - Professional dotted notation - Command hierarchy: inbox.get-mails, settings.add-forwarding - Type separation: requests vs streams - Builder pattern with closures This enables complex protocols with multiple commands in a clean API! 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1b9376f commit 17bb6d6

2 files changed

Lines changed: 48 additions & 29 deletions

File tree

examples/src/request_response.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ async fn run_server(_identity: String) -> Result<(), Box<dyn std::error::Error>>
5555
println!("🎧 Starting multi-identity Echo protocol server");
5656
println!("📡 Will discover and serve all configured identities and protocols from FASTN_HOME");
5757

58-
// Use modern serve_all() builder with protocol.command API
58+
// Use modern serve_all() builder with nested protocol API
5959
fastn_p2p::serve_all()
60-
.handle_requests("echo.fastn.com", "basic-echo", fastn_p2p::echo_request_handler)
60+
.protocol("echo.fastn.com", |p| p
61+
.handle_requests("basic-echo", fastn_p2p::echo_request_handler)
62+
)
6163
.serve()
6264
.await?;
6365

fastn-p2p/src/server/serve_all.rs

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,42 +28,60 @@ pub type StreamCallback = fn(
2828
serde_json::Value, // initial_data
2929
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>> + Send>>;
3030

31+
/// Protocol command handlers for a specific protocol
32+
pub struct ProtocolBuilder {
33+
protocol_name: String,
34+
request_callbacks: HashMap<String, RequestCallback>, // Key: command name
35+
stream_callbacks: HashMap<String, StreamCallback>, // Key: command name
36+
}
37+
38+
impl ProtocolBuilder {
39+
/// Add a request/response command handler
40+
pub fn handle_requests(mut self, command: &str, callback: RequestCallback) -> Self {
41+
self.request_callbacks.insert(command.to_string(), callback);
42+
self
43+
}
44+
45+
/// Add a streaming command handler
46+
pub fn handle_streams(mut self, command: &str, callback: StreamCallback) -> Self {
47+
self.stream_callbacks.insert(command.to_string(), callback);
48+
self
49+
}
50+
}
51+
3152
/// Multi-identity server builder that discovers and serves all configured protocols
3253
pub struct ServeAllBuilder {
3354
fastn_home: PathBuf,
34-
request_callbacks: HashMap<String, RequestCallback>, // Key: "protocol.command"
35-
stream_callbacks: HashMap<String, StreamCallback>, // Key: "protocol.command"
55+
protocols: HashMap<String, ProtocolBuilder>, // Key: protocol name
3656
}
3757

3858
impl ServeAllBuilder {
39-
/// Register a request/response callback for a protocol command
40-
///
41-
/// # Arguments
42-
/// * `protocol` - Protocol name (e.g., "mail.fastn.com", "echo.fastn.com")
43-
/// * `command` - Command name (e.g., "get-mails", "send-mail", "basic-echo")
44-
/// * `callback` - Handler function
59+
/// Register handlers for a protocol with nested command structure
4560
///
4661
/// # Example
4762
/// ```rust,no_run
4863
/// fastn_p2p::serve_all()
49-
/// .handle_requests("mail.fastn.com", "get-mails", get_mails_handler)
50-
/// .handle_requests("mail.fastn.com", "send-mail", send_mail_handler)
64+
/// .protocol("mail.fastn.com", |p| p
65+
/// .handle_requests("get-mails", get_mails_handler)
66+
/// .handle_requests("send-mail", send_mail_handler)
67+
/// .handle_requests("settings.add-forwarding", forwarding_handler)
68+
/// )
69+
/// .protocol("filetransfer.fastn.com", |p| p
70+
/// .handle_streams("transfer.large-file", large_file_handler)
71+
/// )
5172
/// ```
52-
pub fn handle_requests(mut self, protocol: &str, command: &str, callback: RequestCallback) -> Self {
53-
let key = format!("{}.{}", protocol, command);
54-
self.request_callbacks.insert(key, callback);
55-
self
56-
}
57-
58-
/// Register a streaming callback for a protocol command
59-
///
60-
/// # Arguments
61-
/// * `protocol` - Protocol name (e.g., "filetransfer.fastn.com")
62-
/// * `command` - Command name (e.g., "large-file", "media-stream")
63-
/// * `callback` - Handler function
64-
pub fn handle_streams(mut self, protocol: &str, command: &str, callback: StreamCallback) -> Self {
65-
let key = format!("{}.{}", protocol, command);
66-
self.stream_callbacks.insert(key, callback);
73+
pub fn protocol<F>(mut self, protocol_name: &str, builder_fn: F) -> Self
74+
where
75+
F: FnOnce(ProtocolBuilder) -> ProtocolBuilder,
76+
{
77+
let protocol_builder = ProtocolBuilder {
78+
protocol_name: protocol_name.to_string(),
79+
request_callbacks: HashMap::new(),
80+
stream_callbacks: HashMap::new(),
81+
};
82+
83+
let configured_protocol = builder_fn(protocol_builder);
84+
self.protocols.insert(protocol_name.to_string(), configured_protocol);
6785
self
6886
}
6987

@@ -142,8 +160,7 @@ pub fn serve_all() -> ServeAllBuilder {
142160

143161
ServeAllBuilder {
144162
fastn_home,
145-
request_callbacks: HashMap::new(),
146-
stream_callbacks: HashMap::new(),
163+
protocols: HashMap::new(),
147164
}
148165
}
149166

0 commit comments

Comments
 (0)