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.

Shared Service Definition Pattern

Loading…

Shared Service Definition Pattern

Relevant source files

The Shared Service Definition Pattern is a core architectural idiom in Muxio that allows both the client and the server to share a single source of truth for RPC method signatures and serialization logic. By defining services in a dedicated crate, developers ensure type safety and protocol consistency across different transport implementations (e.g., Tokio-based servers and WASM-based clients).

Purpose and Scope

The primary goal of this pattern is to decouple the what (the RPC contract) from the how (the network transport and runtime). This is achieved through the RpcMethodPrebuffered trait, which defines how high-level Rust types are transformed into binary payloads and identifies methods using unique 64-bit hashes.

In the provided examples, the example-muxio-rpc-service-definition crate serves as this shared contract, utilized by both the server and client.

Sources: examples/example-muxio-rpc-service-definition/src/lib.rs4 examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs17

Crate Structure

A typical service definition crate is lightweight and usually depends only on muxio-rpc-service and a serialization library like bitcode examples/example-muxio-rpc-service-definition/Cargo.toml:10-12 The example structure follows a modular approach:

The crate re-exposes the RpcMethodPrebuffered trait for simplicity examples/example-muxio-rpc-service-definition/src/lib.rs4

Sources: examples/example-muxio-rpc-service-definition/src/lib.rs:1-5 examples/example-muxio-rpc-service-definition/src/prebuffered.rs:1-9 examples/example-muxio-rpc-service-definition/Cargo.toml:1-13

Implementation: RpcMethodPrebuffered

The RpcMethodPrebuffered trait is the cornerstone of the shared definition. It requires the implementation of four serialization methods and a unique METHOD_ID.

Method Identification via rpc_method_id!

To avoid manual management of integer IDs, Muxio uses the rpc_method_id! macro. This macro generates a u64 at compile-time by hashing a string literal (e.g., "math.add") using the XXH3 algorithm examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs18 This ensures that as long as the string name is consistent, the client and server will agree on the dispatch ID.

Data Flow and Serialization

The pattern typically uses a serialization library (like bitcode) to handle the conversion of parameters into bytes examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs1

StageFunctionDirection
Request Encodingencode_requestCaller: Input -> Vec<u8>
Request Decodingdecode_requestEndpoint: &[u8] -> Input
Response Encodingencode_responseEndpoint: Output -> Vec<u8>
Response Decodingdecode_responseCaller: &[u8] -> Output

Example: The Add Service

In add.rs, the service defines internal structs for request and response parameters that are hidden from the public API of the Add unit struct.

Entity Mapping: Add Service

graph TD
    subgraph "Natural Language Space"
        "Math Addition Service"
    end

    subgraph "Code Entity Space"
        Add["struct Add"]
AddReq["struct AddRequestParams"]
AddRes["struct AddResponseParams"]
Trait["RpcMethodPrebuffered"]
Add -- "implements" --> Trait
        AddReq -- "serialized by" --> Add
        AddRes -- "serialized by" --> Add
        
        Add -- "uses" --> rpc_method_id["rpc_method_id!('math.add')"]
end

Sources: examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:5-15 examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:17-18

Detailed Method Implementations

Structured Data: Add and Mult

The Add and Mult implementations use bitcode to handle Vec<f64> inputs.

Passthrough: Echo

The Echo service demonstrates a “raw” implementation where no external serialization is needed because the Input and Output types are already Vec<u8> examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:9-10 The implementation simply returns the input bytes or clones them into a vector examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:12-26

sequenceDiagram
    participant Client as "RpcClient (Caller)"
    participant Shared as "example-muxio-rpc-service-definition"
    participant Server as "RpcServer (Endpoint)"

    Note over Client, Server: Both crates depend on Shared Definition

    rect rgb(240, 240, 240)
    Note right of Client: call_rpc_buffered::<Add>(...)
    Client->>Shared: encode_request(Vec<f64>)
    Shared-->>Client: Vec<u8> (Payload)
    end

    Client->>Server: Frame (METHOD_ID: math.add)

    rect rgb(240, 240, 240)
    Note left of Server: handle_request (Add)
    Server->>Shared: decode_request(Vec<u8>)
    Shared-->>Server: Vec<f64> (Input)
    Note left of Server: Execute Logic
    Server->>Shared: encode_response(f64)
    Shared-->>Server: Vec<u8> (Payload)
    end

    Server->>Client: Frame (Response)

    rect rgb(240, 240, 240)
    Client->>Shared: decode_response(Vec<u8>)
    Shared-->>Client: f64 (Output)
    end

Shared Usage Diagram

The following diagram illustrates how the shared crate bridges the Client and Server components by providing common serialization logic.

Protocol Interaction Flow

Sources: examples/example-muxio-rpc-service-definition/src/prebuffered/add.rs:23-43 examples/example-muxio-rpc-service-definition/src/prebuffered/echo.rs:6-27

Key Functions and Traits

Sources: