This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Extending the Framework
Loading…
Extending the Framework
Relevant source files
Purpose and Scope
This document provides guidance for extending the muxio framework with custom transport implementations, runtime-specific client and server implementations, and platform-specific adaptations. It covers the architectural extension points, required trait implementations, and patterns for integrating new runtime environments.
For information about deploying existing implementations across platforms, see Cross-Platform Deployment. For details about the existing Tokio and WASM implementations, see Platform Implementations.
Sources: Cargo.toml:19-31 extensions/muxio-rpc-service-endpoint/Cargo.toml:1-33
Extension Points in the Architecture
The muxio framework provides several well-defined extension points that enable custom implementations without modifying core logic. The layered architecture isolates platform-specific concerns from runtime-agnostic abstractions.
Diagram 1: Framework Extension Points
graph TB
subgraph "Core Layer - No Extensions Needed"
CORE["muxio Core"]
DISPATCHER["RpcDispatcher"]
SESSION["RpcSession"]
FRAME["Binary Framing Protocol"]
end
subgraph "Framework Layer - Extension Points"
CALLER["RpcServiceCallerInterface\nTrait for Client Logic"]
ENDPOINT["RpcServiceEndpointInterface\nTrait for Server Logic"]
SERVICE["RpcMethodPrebuffered\nService Definitions"]
end
subgraph "Platform Layer - Your Extensions"
CUSTOM_CLIENT["Custom RPC Client\nYour Transport"]
CUSTOM_SERVER["Custom RPC Server\nYour Runtime"]
CUSTOM_TRANSPORT["Custom Transport Layer\nYour Protocol"]
end
CORE --> DISPATCHER
CORE --> SESSION
CORE --> FRAME
DISPATCHER --> CALLER
DISPATCHER --> ENDPOINT
SESSION --> CALLER
SESSION --> ENDPOINT
CALLER --> SERVICE
ENDPOINT --> SERVICE
CUSTOM_CLIENT -.implements.-> CALLER
CUSTOM_SERVER -.implements.-> ENDPOINT
CUSTOM_TRANSPORT -.uses.-> CORE
CUSTOM_CLIENT --> CUSTOM_TRANSPORT
CUSTOM_SERVER --> CUSTOM_TRANSPORT
Key Extension Points
| Extension Point | Location | Purpose | Required Traits |
|---|---|---|---|
| Client Implementation | Custom crate | Platform-specific RPC client | RpcServiceCallerInterface |
| Server Implementation | Custom crate | Platform-specific RPC server | RpcServiceEndpointInterface |
| Transport Layer | Any | Custom wire protocol or runtime | None (callback-driven) |
| Service Definitions | Shared crate | Business logic contracts | RpcMethodPrebuffered |
| Feature Flags | Cargo.toml | Conditional compilation | N/A |
Sources: Cargo.toml:20-31 extensions/muxio-rpc-service-endpoint/Cargo.toml:23-27
Creating Custom Transports
Custom transports wrap the RpcDispatcher and provide platform-specific I/O mechanisms. The core dispatcher is runtime-agnostic and callback-driven, enabling integration with any execution model.
Diagram 2: Custom Transport Integration Pattern
graph LR
subgraph "Your Custom Transport"
INIT["Initialize Transport\nCustom I/O Setup"]
WRITE["Write Callback\nfn(Vec<u8>)"]
READ["Read Loop\nPlatform-Specific"]
LIFECYCLE["Connection Lifecycle\nState Management"]
end
subgraph "Core muxio Components"
DISPATCHER["RpcDispatcher"]
SESSION["RpcSession"]
end
INIT --> DISPATCHER
DISPATCHER --> WRITE
READ --> DISPATCHER
LIFECYCLE --> DISPATCHER
DISPATCHER --> SESSION
Transport Implementation Requirements
- Initialize
RpcDispatcherwith a write callback that sends binary frames via your transport - Implement read loop that feeds received bytes to
RpcDispatcher::read() - Handle lifecycle events such as connection, disconnection, and errors
- Manage concurrency model appropriate for your runtime (async, sync, thread-per-connection, etc.)
Example Transport Structure
Key patterns:
- Write Callback : Closure or function that writes bytes to transport [see extensions/muxio-tokio-rpc-client/src/rpc_client.rs100-226](https://github.com/jzombie/rust-muxio/blob/30450c98/see extensions/muxio-tokio-rpc-client/src/rpc_client.rs#L100-L226)
- Read Integration : Feed incoming bytes to
RpcDispatcher::read()[see src/rpc/rpc_dispatcher.rs130-264](https://github.com/jzombie/rust-muxio/blob/30450c98/see src/rpc/rpc_dispatcher.rs#L130-L264) - State Management : Track connection lifecycle with callbacks [see extensions/muxio-tokio-rpc-client/src/rpc_client.rs30-38](https://github.com/jzombie/rust-muxio/blob/30450c98/see extensions/muxio-tokio-rpc-client/src/rpc_client.rs#L30-L38)
Sources: extensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-226 src/rpc/rpc_dispatcher.rs:130-264
Implementing Platform-Specific Clients
Platform-specific clients implement the RpcServiceCallerInterface trait to provide type-safe RPC invocation. The trait is defined in muxio-rpc-service-caller.
Diagram 3: Client Implementation Architecture
graph TB
subgraph "Your Client Implementation"
CLIENT["CustomRpcClient\nPlatform-Specific Lifecycle"]
CALLER_IMPL["impl RpcServiceCallerInterface"]
end
subgraph "Required Integration"
DISPATCHER["RpcDispatcher\nOwned or Arc Reference"]
MUTEX["Sync Primitive\nMutex, TokioMutex, etc."]
WRITE["write_callback\nPlatform I/O"]
READ["read_loop\nBackground Task/Thread"]
end
subgraph "Trait Methods to Implement"
CALL["async fn call()\nRpcRequest -> RpcResponse"]
GET_DISP["fn get_dispatcher()\nAccess to Dispatcher"]
end
CLIENT --> CALLER_IMPL
CLIENT --> DISPATCHER
CLIENT --> MUTEX
CLIENT --> WRITE
CLIENT --> READ
CALLER_IMPL -.implements.-> CALL
CALLER_IMPL -.implements.-> GET_DISP
CALL --> GET_DISP
GET_DISP --> DISPATCHER
Required Trait Implementation
The RpcServiceCallerInterface trait requires implementing two core methods:
| Method | Signature | Purpose |
|---|---|---|
call | async fn call(&self, request: RpcRequest) -> Result<RpcResponse> | Send RPC request and await response |
get_dispatcher | fn get_dispatcher(&self) -> Arc<...> | Provide access to underlying dispatcher |
Client Lifecycle Considerations
- Construction : Initialize
RpcDispatcherwith write callback - Connection : Establish transport and start read loop
- Operation : Handle
call()invocations by delegating to dispatcher - Cleanup : Close connection and stop background tasks on drop
Reference Implementation Pattern
For Tokio-based clients, see extensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-226 which demonstrates:
- Arc-based shared ownership of
RpcDispatcher TokioMutexfor async-safe access- Background task for read loop using
tokio::spawn - Connection state tracking with callbacks
For WASM-based clients, see extensions/muxio-wasm-rpc-client/src/rpc_wasm_client.rs:15-32 which demonstrates:
- Single-threaded execution model
- JavaScript bridge integration
- Static singleton pattern for WASM constraints
Sources: extensions/muxio-rpc-service-caller/ extensions/muxio-tokio-rpc-client/src/rpc_client.rs:30-226 extensions/muxio-wasm-rpc-client/src/rpc_wasm_client.rs:15-32
graph TB
subgraph "Your Server Implementation"
SERVER["CustomRpcServer\nPlatform-Specific Server"]
ENDPOINT_IMPL["impl RpcServiceEndpointInterface"]
HANDLER_REG["Handler Registration\nregister_handler()"]
end
subgraph "Request Processing Pipeline"
ACCEPT["Accept Connection\nPlatform-Specific"]
DISPATCHER["RpcDispatcher\nPer-Connection"]
READ["Read Loop\nFeed to Dispatcher"]
ENDPOINT["RpcServiceEndpoint\nHandler Registry"]
end
subgraph "Handler Execution"
DECODE["Decode RpcRequest\nDeserialize Parameters"]
DISPATCH["Dispatch to Handler\nMatch method_id"]
EXECUTE["Execute Handler\nUser Business Logic"]
RESPOND["Encode RpcResponse\nSend via Dispatcher"]
end
SERVER --> ENDPOINT_IMPL
SERVER --> HANDLER_REG
ACCEPT --> DISPATCHER
DISPATCHER --> READ
READ --> ENDPOINT
ENDPOINT --> DECODE
DECODE --> DISPATCH
DISPATCH --> EXECUTE
EXECUTE --> RESPOND
RESPOND --> DISPATCHER
Implementing Platform-Specific Servers
Platform-specific servers implement the RpcServiceEndpointInterface trait to handle incoming RPC requests and dispatch them to registered handlers. The trait is defined in muxio-rpc-service-endpoint.
Diagram 4: Server Implementation Flow
Required Trait Implementation
The RpcServiceEndpointInterface trait provides default implementations but allows customization:
| Method | Default Implementation | Override When |
|---|---|---|
register_handler | Registers handler in internal map | Custom dispatch logic needed |
handle_finalized_request | Deserializes and invokes handler | Custom request processing required |
handle_stream_open | Routes streamed requests | Custom stream handling needed |
Server Architecture Patterns
Connection Management:
- Create new
RpcDispatcherinstance per connection - Create new
RpcServiceEndpointinstance per connection - Share handler registrations across connections (using
Arc)
Handler Registration:
- Register handlers at server startup or connection time
- Use
RpcServiceEndpoint::register_handler()with closure - Handlers receive deserialized parameters and return typed results
Reference Implementation Pattern
For Tokio-based servers, see extensions/muxio-tokio-rpc-server/ which demonstrates:
- Axum framework integration for HTTP/WebSocket serving
- Per-connection
RpcDispatcherandRpcServiceEndpoint - Handler registration with async closures
- Graceful shutdown handling
Sources: extensions/muxio-rpc-service-endpoint/src/endpoint_interface.rs:65-137 extensions/muxio-tokio-rpc-server/
Feature Flags and Conditional Compilation
The muxio ecosystem uses Cargo feature flags to enable optional dependencies and platform-specific code. This pattern allows extensions to remain lightweight while supporting multiple runtimes.
Diagram 5: Feature Flag Pattern
graph LR
subgraph "Extension Crate Cargo.toml"
DEFAULT["default = []\nMinimal Dependencies"]
FEATURE1["tokio_support\ndep:tokio"]
FEATURE2["async_std_support\ndep:async-std"]
FEATURE3["custom_feature\nYour Feature"]
end
subgraph "Conditional Code"
CFG1["#[cfg(feature = tokio_support)]\nTokio-Specific Impl"]
CFG2["#[cfg(feature = async_std_support)]\nasync-std Impl"]
CFG3["#[cfg(not(any(...)))]\nFallback Impl"]
end
DEFAULT --> CFG3
FEATURE1 --> CFG1
FEATURE2 --> CFG2
FEATURE3 --> CFG1
Feature Flag Best Practices
InCargo.toml:
In source code:
Example: muxio-rpc-service-endpoint
The muxio-rpc-service-endpoint crate demonstrates this pattern at extensions/muxio-rpc-service-endpoint/Cargo.toml:23-27:
This enables Tokio-specific mutex types while maintaining compatibility with synchronous code.
Sources: extensions/muxio-rpc-service-endpoint/Cargo.toml:23-27 Cargo.toml:39-65
Integration Patterns
When creating a new platform extension, follow these patterns to ensure compatibility with the muxio ecosystem.
Workspace Integration
Directory Structure:
rust-muxio/
├── extensions/
│ ├── muxio-custom-client/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── muxio-custom-server/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
Add to workspace: Cargo.toml:19-31
Dependency Configuration
Workspace Dependencies: Cargo.toml:39-48
Extension Crate Dependencies:
Metadata Inheritance
Use workspace metadata inheritance to maintain consistency Cargo.toml:1-17:
Testing Integration
Create dev dependencies for integration testing:
Reference the example service definitions for end-to-end tests, as demonstrated in extensions/muxio-rpc-service-endpoint/Cargo.toml:29-33
Sources: Cargo.toml:1-71 extensions/muxio-rpc-service-endpoint/Cargo.toml:1-33
Extension Checklist
When implementing a new platform extension, ensure the following:
For Client Extensions
- Implement
RpcServiceCallerInterfacetrait - Create
RpcDispatcherwith platform-specific write callback - Start read loop that feeds bytes to
RpcDispatcher::read() - Manage connection lifecycle with state tracking
- Provide async or sync API appropriate for runtime
- Handle connection errors and cleanup
- Add feature flags for optional dependencies
- Document platform-specific requirements
For Server Extensions
- Implement
RpcServiceEndpointInterfacetrait - Accept connections and create per-connection
RpcDispatcher - Create per-connection
RpcServiceEndpoint - Register handlers from shared definitions
- Implement request routing and execution
- Send responses via
RpcDispatcher - Handle graceful shutdown
- Document server setup and configuration
For Transport Extensions
- Define platform-specific connection type
- Implement write callback for outgoing frames
- Implement read mechanism for incoming frames
- Handle connection establishment and teardown
- Provide error handling and recovery
- Document transport-specific limitations
Sources: extensions/muxio-tokio-rpc-client/ extensions/muxio-tokio-rpc-server/ extensions/muxio-wasm-rpc-client/