This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Simple Calculator Service
Relevant source files
- README.md
- extensions/muxio-rpc-service-caller/src/prebuffered/traits.rs
- extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs
- extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rs
Purpose and Scope
This page provides a step-by-step tutorial for building a simple calculator RPC service using the rust-muxio framework. It demonstrates how to define service contracts, implement server-side handlers, and make client-side calls using the prebuffered RPC pattern. This tutorial covers the core workflow from service definition to testing.
For a walkthrough of the complete example application, see WebSocket RPC Application. For general information about creating service definitions, see Creating Service Definitions. For details on the prebuffered RPC mechanism, see Prebuffered RPC Calls.
Overview
The calculator service implements three basic mathematical operations:
- Add : Sums a list of floating-point numbers
- Mult : Multiplies a list of floating-point numbers
- Echo : Returns the input bytes unchanged
Each operation is defined as a separate RPC method implementing the RpcMethodPrebuffered trait, enabling type-safe, compile-time verified communication between client and server.
Sources: README.md:69-161 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-97
Service Architecture
Figure 1: Calculator Service Component Structure
This diagram illustrates how the shared service definitions in example_muxio_rpc_service_definition provide the contract between server handlers and client calls. Both sides depend on the same METHOD_ID and serialization logic.
Sources: README.md:69-161 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-97
Step 1: Define Service Methods
The calculator service requires three method definitions in the shared service definition crate. Each method implements RpcMethodPrebuffered, which requires:
| Required Item | Description | Example |
|---|---|---|
METHOD_ID | Compile-time generated constant identifying the method | Add::METHOD_ID |
Input | Associated type for method parameters | Vec<f64> |
Output | Associated type for method return value | f64 |
encode_request() | Serializes input to bytes | Uses bitcode |
decode_request() | Deserializes bytes to input | Uses bitcode |
encode_response() | Serializes output to bytes | Uses bitcode |
decode_response() | Deserializes bytes to output | Uses bitcode |
The Add, Mult, and Echo method definitions are located in the example_muxio_rpc_service_definition crate and used by both server and client implementations.
Sources: README.md:70-73 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-6
Step 2: Implement Server Handlers
Figure 2: Server Handler Registration and Execution Flow
Server Setup Pattern
The server setup follows a consistent pattern:
- Create
RpcServerinstance wrapped inArc - Get endpoint handle via
server.endpoint() - Register handlers using
endpoint.register_prebuffered() - Spawn server task with
server.serve_with_listener()
Handler Implementation
Each handler is an async closure that:
- Receives
request_bytes: Vec<u8>and an optional context - Decodes the request using the method's
decode_request() - Performs the calculation
- Encodes the result using the method's
encode_response() - Returns
Ok(response_bytes)orErr(e)
Example from README.md:
The Add handler implementation at README.md:101-106:
- Decodes request bytes to
Vec<f64> - Computes sum using
request_params.iter().sum() - Encodes result back to bytes
The Mult handler implementation at README.md:107-112:
- Decodes request bytes to
Vec<f64> - Computes product using
request_params.iter().product() - Encodes result back to bytes
The Echo handler implementation at README.md:113-117:
- Decodes request bytes to
Vec<u8> - Returns the same bytes unchanged
- Encodes result back to bytes
Sources: README.md:94-118 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:26-61
Step 3: Create Client Calls
Figure 3: Client Call Flow with Code Entities
Client Usage Pattern
The client-side code uses the RpcCallPrebuffered trait, which provides a high-level call() method. This trait is automatically implemented for all types that implement RpcMethodPrebuffered.
Key client steps:
- Create
RpcClientconnection to server - Call methods using
MethodName::call(&client, input) - Await results or use
tokio::join!for concurrent calls - Handle
Result<Output, RpcServiceError>responses
Example from README.md:
The client code at README.md:136-151 demonstrates:
- Creating client with
RpcClient::new() - Making concurrent calls using
tokio::join!() - Passing typed inputs directly (e.g.,
vec![1.0, 2.0, 3.0]) - Receiving typed outputs (e.g.,
f64orVec<u8>)
Argument Size Handling
The RpcCallPrebuffered implementation at extensions/muxio-rpc-service-caller/src/prebuffered/traits.rs:30-48 automatically handles large arguments:
| Argument Size | Transport Strategy | Location |
|---|---|---|
| < 64KB | Sent in rpc_param_bytes field | Header frame |
| ≥ 64KB | Sent in rpc_prebuffered_payload_bytes | Streamed after header |
This ensures that RPC calls with large argument sets (like the test at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:155-203 using 12.8 MB payloads) do not fail due to transport limitations.
Sources: README.md:130-159 extensions/muxio-rpc-service-caller/src/prebuffered/traits.rs:10-98
Step 4: Full Integration Example
Complete Server Setup
Complete Client Usage
Sources: README.md:69-161
Testing Patterns
Success Path Testing
The integration tests at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:16-97 demonstrate the complete success flow:
- Start server with handlers registered
- Wait for server to be ready
- Connect client
- Make multiple concurrent calls
- Assert all results are correct
Error Handling Testing
The error test at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:99-152 shows:
- Register handler that returns
Err("Addition failed".into()) - Make RPC call
- Verify error is
RpcServiceError::Rpcvariant - Check error code is
RpcServiceErrorCode::System - Verify error message is propagated
Large Payload Testing
The large payload test at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:154-203 validates:
- Payloads of 200× chunk size (12.8 MB) are handled correctly
- Request payload is automatically chunked
- Response payload is correctly reassembled
- Round-trip data integrity is maintained
Method Not Found Testing
The not-found test at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:205-240 verifies:
- Server with no handlers registered
- Client calls method
- Error is
RpcServiceError::RpcwithRpcServiceErrorCode::NotFound
Sources: extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-241
Cross-Platform Compatibility
Figure 4: Cross-Platform Service Usage
The same calculator service definitions work across all client types:
| Client Type | Test File | Key Features |
|---|---|---|
| Tokio Client | extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs | Native async/await, Tokio runtime |
| WASM Client | extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rs | Browser-compatible, JavaScript bridge |
Both test files at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:81-88 and extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rs:126-133 use identical calling patterns:
This demonstrates the "write once, deploy everywhere" capability of the muxio framework.
Sources: extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-97 extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rs:39-142
Key Implementation Details
Handler Context
Handlers receive a context parameter (_ctx) at README.md101 README.md107 and README.md113 which can be used for:
- Access to connection metadata
- Request tracing
- Authentication state
- Custom per-connection data
Error Propagation
Errors flow through multiple layers:
- Handler returns
Result<Vec<u8>, RpcServiceError> - Serialization errors from
encode_response()are automatically converted - Client receives
Result<Output, RpcServiceError> - Error payload includes code and message
The error handling pattern at extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:140-150 shows proper error matching:
Concurrent Request Handling
Using tokio::join! at README.md:144-151 enables:
- Multiple concurrent RPC calls over single connection
- Request correlation by unique IDs
- Multiplexed responses arriving in any order
- Efficient connection utilization
Sources: README.md:94-161 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:99-152
Summary
The calculator service tutorial demonstrates the complete workflow for building type-safe RPC services with rust-muxio:
- Define methods implementing
RpcMethodPrebufferedin shared crate - Register handlers on server using
endpoint.register_prebuffered() - Make calls from client using
MethodName::call(client, input) - Test with integration tests covering success, errors, and edge cases
This pattern scales from simple calculators to complex production services while maintaining compile-time type safety and cross-platform compatibility.
Sources: README.md:69-161 extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rs:1-241 extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rs:1-313
Dismiss
Refresh this wiki
Enter email to refresh