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.

Cross-Platform Deployment

Loading…

Cross-Platform Deployment

Relevant source files

Purpose and Scope

This page explains strategies for deploying muxio-based RPC services across multiple runtime environments using a single shared service definition. It covers how to structure projects, configure builds, and deploy the same business logic to native applications (using Tokio) and web browsers (using WebAssembly).

For details on creating service definitions themselves, see Creating Service Definitions. For information on the WASM JavaScript bridge architecture, see JavaScript and WASM Integration. For runtime-specific implementation details, see Tokio RPC Client and WASM RPC Client.


Cross-Platform Architecture Overview

Muxio achieves cross-platform compatibility through a layered architecture where the core multiplexing and RPC logic remain platform-agnostic, while platform-specific extensions provide concrete implementations for different environments.

graph TB
    subgraph "Shared Business Logic"
        APP["Application Code\nType-safe RPC calls"]
SERVICE_DEF["Service Definition Crate\nRpcMethodPrebuffered traits\nMETHOD_ID constants"]
end
    
    subgraph "Abstraction Layer"
        CALLER_INTERFACE["RpcServiceCallerInterface\nPlatform-agnostic trait"]
ENDPOINT_INTERFACE["RpcServiceEndpointInterface\nHandler registration"]
end
    
    subgraph "Native Platform"
        TOKIO_CLIENT["RpcClient\nArc-based lifecycle\ntokio-tungstenite"]
TOKIO_SERVER["RpcServer\nAxum + WebSocket"]
end
    
    subgraph "Web Platform"
        WASM_CLIENT["RpcWasmClient\nwasm-bindgen\nJS WebSocket bridge"]
end
    
    subgraph "Core Layer"
        MUXIO_CORE["muxio core\nCallback-driven\nNo async runtime"]
RPC_FRAMEWORK["muxio-rpc-service\nMethod ID generation\nbitcode serialization"]
end
    
 
   APP --> SERVICE_DEF
 
   APP --> CALLER_INTERFACE
 
   SERVICE_DEF --> CALLER_INTERFACE
    
    CALLER_INTERFACE -.implemented by.-> TOKIO_CLIENT
    CALLER_INTERFACE -.implemented by.-> WASM_CLIENT
    
 
   TOKIO_CLIENT --> RPC_FRAMEWORK
 
   WASM_CLIENT --> RPC_FRAMEWORK
 
   TOKIO_SERVER --> ENDPOINT_INTERFACE
    
 
   RPC_FRAMEWORK --> MUXIO_CORE
 
   ENDPOINT_INTERFACE --> RPC_FRAMEWORK

Platform Independence Strategy

Sources : README.md:35-41 README.md:48-49 Cargo.lock:426-431 Cargo.lock:898-915 Cargo.lock:935-953


Shared Service Definition Pattern

The foundation of cross-platform deployment is a shared service definition crate that contains no platform-specific code. This crate defines the RPC methods, request/response types, and method identifiers that both client and server implementations depend on.

Service Definition Crate Structure

ComponentPurposeExample
RPC Method TraitsDefine method signatures and serializationimpl RpcMethodPrebuffered for Add
Method ID ConstantsCompile-time generated identifiersAdd::METHOD_ID
Request/Response TypesShared data structuresVec<f64> parameters
Serialization LogicEncoding/decoding with bitcodeencode_request(), decode_response()

Sources : README.md:50-51 README.md:71-74 Cargo.lock:426-431


Platform-Specific Client Implementations

While service definitions remain identical, client implementations differ based on the target platform. Both implementations satisfy the same RpcServiceCallerInterface trait, enabling application code to remain platform-agnostic.

Native (Tokio) Client

The muxio-tokio-rpc-client crate provides a native Rust client implementation using:

  • Async runtime : Tokio for concurrent I/O
  • Transport : tokio-tungstenite for WebSocket connections
  • Lifecycle : Arc<RpcClient> for shared ownership across async tasks
  • State management : Background task for connection monitoring

Sources : Cargo.lock:898-915 README.md:75-77 README.md:137-142

WebAssembly Client

The muxio-wasm-rpc-client crate provides a browser-compatible client using:

  • Platform : WebAssembly compiled from Rust
  • Transport : JavaScript WebSocket APIs via wasm-bindgen
  • Lifecycle : Thread-local static reference (MUXIO_STATIC_RPC_CLIENT_REF)
  • Bridge : static_muxio_write_bytes() function for JS-to-Rust communication

Sources : Cargo.lock:935-953 README.md:40-41 README.md:52-53

Unified Interface Usage

Application code can use the same RPC calling pattern regardless of platform:

Sources : README.md:145-152


graph TB
    subgraph "Core Layer"
        MUXIO["muxio\nno_std compatible"]
RPC_SERVICE["muxio-rpc-service\nplatform agnostic"]
end
    
    subgraph "Framework Layer"
        CALLER["muxio-rpc-service-caller"]
ENDPOINT["muxio-rpc-service-endpoint"]
end
    
    subgraph "Native Extensions"
        TOKIO_CLIENT["muxio-tokio-rpc-client\ntarget: native"]
TOKIO_SERVER["muxio-tokio-rpc-server\ntarget: native"]
end
    
    subgraph "WASM Extensions"
        WASM_CLIENT["muxio-wasm-rpc-client\ntarget: wasm32-unknown-unknown"]
end
    
    subgraph "Application Layer"
        SERVICE_DEF["example-muxio-rpc-service-definition\nplatform agnostic"]
EXAMPLE_APP["example-muxio-ws-rpc-app\nnative only"]
end
    
 
   RPC_SERVICE --> MUXIO
 
   CALLER --> RPC_SERVICE
 
   ENDPOINT --> RPC_SERVICE
    
 
   TOKIO_CLIENT --> CALLER
 
   TOKIO_SERVER --> ENDPOINT
 
   WASM_CLIENT --> CALLER
    
 
   SERVICE_DEF --> RPC_SERVICE
 
   EXAMPLE_APP --> SERVICE_DEF
 
   EXAMPLE_APP --> TOKIO_CLIENT
 
   EXAMPLE_APP --> TOKIO_SERVER

Cargo Workspace Configuration

Muxio uses a Cargo workspace to organize crates by layer and platform target. This structure enables selective compilation based on target architecture.

Workspace Structure

Dependency Requirements by Platform :

CrateNativeWASMNotes
muxioCore, no async required
muxio-rpc-servicePlatform-agnostic serialization
muxio-tokio-rpc-clientRequires Tokio runtime
muxio-tokio-rpc-serverRequires Tokio + Axum
muxio-wasm-rpc-clientRequires wasm-bindgen

Sources : Cargo.lock:830-839 Cargo.lock:858-867 Cargo.lock:898-915 Cargo.lock:918-932 Cargo.lock:935-953


Build Targets and Compilation

Cross-platform deployment requires configuring separate build targets for native and WASM outputs.

Native Build Configuration

Native applications compile with the standard Rust toolchain:

Key dependencies for native builds :

  • tokio with full features
  • tokio-tungstenite for WebSocket transport
  • axum for HTTP server (server-side only)

Sources : Cargo.lock:1417-1432 Cargo.lock:1446-1455 Cargo.lock:80-114

WebAssembly Build Configuration

WASM applications require the wasm32-unknown-unknown target:

Key dependencies for WASM builds :

  • wasm-bindgen for Rust-JavaScript interop
  • wasm-bindgen-futures for async/await in WASM
  • js-sys for JavaScript standard library access
  • No Tokio or native I/O dependencies

Sources : Cargo.lock:1637-1646 Cargo.lock:1663-1673 Cargo.lock:745-752


Deployment Patterns

Pattern 1: Unified Service Definition

Create a dedicated crate for service definitions that contains no platform-specific code:

my-rpc-services/
├── Cargo.toml          # Only depend on muxio-rpc-service + bitcode
└── src/
    ├── lib.rs
    └── methods/
        ├── user_auth.rs
        ├── data_sync.rs
        └── notifications.rs

Dependencies :

This crate can be used by all platforms.

Sources : Cargo.lock:426-431

Pattern 2: Platform-Specific Applications

Structure application code to depend on platform-appropriate client implementations:

my-project/
├── shared-services/         # Platform-agnostic service definitions
├── native-app/              # Tokio-based desktop/server app
│   ├── Cargo.toml           # Depends on muxio-tokio-rpc-client
│   └── src/
├── wasm-app/                # Browser-based web app
│   ├── Cargo.toml           # Depends on muxio-wasm-rpc-client
│   └── src/
└── server/                  # Backend server
    ├── Cargo.toml           # Depends on muxio-tokio-rpc-server
    └── src/

Pattern 3: Conditional Compilation

Use Cargo features to conditionally compile platform-specific code:

Application code uses conditional compilation:

Sources : Cargo.lock:434-449


sequenceDiagram
    participant JS as "JavaScript Host"
    participant WS as "WebSocket"
    participant WASM as "WASM Module"
    participant CLIENT as "RpcWasmClient"
    
    Note over JS,CLIENT: Initialization
    JS->>WASM: Import WASM module
    WASM->>CLIENT: Initialize static client
    JS->>WS: Create WebSocket connection
    
    Note over JS,CLIENT: Outbound RPC Call
    CLIENT->>WASM: Emit bytes via callback
    WASM->>JS: Call write_bytes_to_js()
    JS->>WS: WebSocket.send(bytes)
    
    Note over JS,CLIENT: Inbound Response
    WS->>JS: onmessage event
    JS->>WASM: static_muxio_write_bytes(bytes)
    WASM->>CLIENT: Process response
    CLIENT->>CLIENT: Resolve awaited call

WebAssembly-Specific Considerations

JavaScript Bridge Requirements

WASM clients require a thin JavaScript layer to handle WebSocket communication:

Key Functions :

  • static_muxio_write_bytes(bytes: &[u8]): Entry point for JavaScript to pass received bytes to WASM
  • write_bytes_to_js(): Callback function exposed to WASM for outbound data

Sources : README.md:52-53

Memory Management

WASM clients use different ownership patterns than native clients:

AspectNative (Tokio)WASM
Client storageArc<RpcClient>thread_local! RefCell<RpcWasmClient>
Dispatcher mutexTokioMutexStdMutex
Task spawningtokio::spawn()Direct execution, no spawning
Async runtimeTokio multi-threadedSingle-threaded, promise-based

Sources : Cargo.lock:898-915 Cargo.lock:935-953

Build Optimization for WASM

Optimize WASM builds for size:

graph TB
    subgraph "Server Process"
        LISTENER["TcpListener\nBind to port"]
SERVER["Arc<RpcServer>"]
ENDPOINT["RpcServiceEndpoint\nHandler registry"]
HANDLERS["Registered handlers"]
end
    
    subgraph "Per-Connection"
        WS_UPGRADE["WebSocket upgrade"]
CONNECTION["Connection handler"]
DISPATCHER["RpcDispatcher"]
SESSION["RpcSession"]
end
    
 
   LISTENER --> WS_UPGRADE
 
   WS_UPGRADE --> CONNECTION
 
   SERVER --> ENDPOINT
 
   ENDPOINT --> HANDLERS
 
   CONNECTION --> DISPATCHER
 
   DISPATCHER --> SESSION
 
   HANDLERS --> DISPATCHER

Additional size reduction via wasm-opt:


Server Deployment Considerations

While clients differ by platform, servers typically run in native environments using Tokio.

Server Architecture

Deployment Checklist :

  • Single server binary serves all client types (native and WASM)
  • WebSocket endpoint accessible to both platforms
  • Same binary protocol used for all connections
  • Service handlers registered once, used by all clients

Sources : README.md:83-128


Integration Example

The following example shows how shared service definitions enable identical calling patterns across platforms:

Shared Service Definition

Native Client Usage

WASM Client Usage

Server Implementation

Sources : README.md:70-161


Benefits of Cross-Platform Deployment

BenefitDescriptionImplementation
Code ReuseWrite business logic onceShared service definition crate
Type SafetyCompile-time API contractRpcMethodPrebuffered trait
Binary EfficiencySame protocol across platformsbitcode serialization
Single ServerOne backend serves all clientsPlatform-agnostic RpcServer
FlexibilityEasy to add new platformsImplement RpcServiceCallerInterface

Sources : README.md:48-49 README.md:50-51