Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

GitHub

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

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 ItemDescriptionExample
METHOD_IDCompile-time generated constant identifying the methodAdd::METHOD_ID
InputAssociated type for method parametersVec<f64>
OutputAssociated type for method return valuef64
encode_request()Serializes input to bytesUses bitcode
decode_request()Deserializes bytes to inputUses bitcode
encode_response()Serializes output to bytesUses bitcode
decode_response()Deserializes bytes to outputUses 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:

  1. Create RpcServer instance wrapped in Arc
  2. Get endpoint handle via server.endpoint()
  3. Register handlers using endpoint.register_prebuffered()
  4. Spawn server task with server.serve_with_listener()

Handler Implementation

Each handler is an async closure that:

  1. Receives request_bytes: Vec<u8> and an optional context
  2. Decodes the request using the method's decode_request()
  3. Performs the calculation
  4. Encodes the result using the method's encode_response()
  5. Returns Ok(response_bytes) or Err(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:

  1. Create RpcClient connection to server
  2. Call methods using MethodName::call(&client, input)
  3. Await results or use tokio::join! for concurrent calls
  4. 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., f64 or Vec<u8>)

Argument Size Handling

The RpcCallPrebuffered implementation at extensions/muxio-rpc-service-caller/src/prebuffered/traits.rs:30-48 automatically handles large arguments:

Argument SizeTransport StrategyLocation
< 64KBSent in rpc_param_bytes fieldHeader frame
≥ 64KBSent in rpc_prebuffered_payload_bytesStreamed 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:

  1. Start server with handlers registered
  2. Wait for server to be ready
  3. Connect client
  4. Make multiple concurrent calls
  5. 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:

  1. Register handler that returns Err("Addition failed".into())
  2. Make RPC call
  3. Verify error is RpcServiceError::Rpc variant
  4. Check error code is RpcServiceErrorCode::System
  5. 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:

  1. Payloads of 200× chunk size (12.8 MB) are handled correctly
  2. Request payload is automatically chunked
  3. Response payload is correctly reassembled
  4. 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:

  1. Server with no handlers registered
  2. Client calls method
  3. Error is RpcServiceError::Rpc with RpcServiceErrorCode::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 TypeTest FileKey Features
Tokio Client extensions/muxio-tokio-rpc-client/tests/prebuffered_integration_tests.rsNative async/await, Tokio runtime
WASM Client extensions/muxio-wasm-rpc-client/tests/prebuffered_integration_tests.rsBrowser-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:

  1. Handler returns Result<Vec<u8>, RpcServiceError>
  2. Serialization errors from encode_response() are automatically converted
  3. Client receives Result<Output, RpcServiceError>
  4. 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:

  1. Define methods implementing RpcMethodPrebuffered in shared crate
  2. Register handlers on server using endpoint.register_prebuffered()
  3. Make calls from client using MethodName::call(client, input)
  4. 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