diff --git a/README.md b/README.md index d42a4a6e..4394a552 100644 --- a/README.md +++ b/README.md @@ -133,16 +133,56 @@ let app = WireframeApp::new()? ## Connection Lifecycle -`WireframeApp` can run callbacks when a connection is opened or closed. The -state produced by `on_connection_setup` is passed to `on_connection_teardown` -when the connection ends. +Protocol callbacks are consolidated under the `WireframeProtocol` trait, +replacing the individual `on_connection_setup`/`on_connection_teardown` +closures. The trait methods are synchronous so the trait remains object safe, +but callbacks can spawn asynchronous tasks when needed. A protocol +implementation registers hooks for connection setup, frame mutation and command +completion. The associated `ProtocolError` type is used by other parts of the +API, such as request handling. ```rust - let app = WireframeApp::new() - .on_connection_setup(|| async { 42u32 }) - .on_connection_teardown(|state| async move { - println!("closing with {state}"); +pub trait WireframeProtocol: Send + Sync + 'static { + type Frame: FrameLike; + type ProtocolError; + + fn on_connection_setup( + &self, + handle: PushHandle, + ctx: &mut ConnectionContext, + ); + + fn before_send(&self, frame: &mut Self::Frame, ctx: &mut ConnectionContext); + + fn on_command_end(&self, ctx: &mut ConnectionContext); +} + +struct MySqlProtocolImpl; + +impl WireframeProtocol for MySqlProtocolImpl { + type Frame = Vec; + type ProtocolError = (); + + fn on_connection_setup( + &self, + handle: PushHandle, + _ctx: &mut ConnectionContext, + ) { + // Spawn an async task to send a heartbeat after setup + tokio::spawn(async move { + let _ = handle.push_high_priority(b"ping".to_vec()).await; }); + } + + fn before_send(&self, _frame: &mut Self::Frame, _ctx: &mut ConnectionContext) {} + + fn on_command_end(&self, _ctx: &mut ConnectionContext) {} +} + +``` + +```rust +let app = WireframeApp::new().with_protocol(MySqlProtocolImpl); ``` ## Custom Extractors