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
| Component | Purpose | Example |
|---|---|---|
| RPC Method Traits | Define method signatures and serialization | impl RpcMethodPrebuffered for Add |
| Method ID Constants | Compile-time generated identifiers | Add::METHOD_ID |
| Request/Response Types | Shared data structures | Vec<f64> parameters |
| Serialization Logic | Encoding/decoding with bitcode | encode_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-tungstenitefor 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 :
| Crate | Native | WASM | Notes |
|---|---|---|---|
muxio | ✓ | ✓ | Core, no async required |
muxio-rpc-service | ✓ | ✓ | Platform-agnostic serialization |
muxio-tokio-rpc-client | ✓ | ✗ | Requires Tokio runtime |
muxio-tokio-rpc-server | ✓ | ✗ | Requires Tokio + Axum |
muxio-wasm-rpc-client | ✗ | ✓ | Requires 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 :
tokiowithfullfeaturestokio-tungstenitefor WebSocket transportaxumfor 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-bindgenfor Rust-JavaScript interopwasm-bindgen-futuresfor async/await in WASMjs-sysfor 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 WASMwrite_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:
| Aspect | Native (Tokio) | WASM |
|---|---|---|
| Client storage | Arc<RpcClient> | thread_local! RefCell<RpcWasmClient> |
| Dispatcher mutex | TokioMutex | StdMutex |
| Task spawning | tokio::spawn() | Direct execution, no spawning |
| Async runtime | Tokio multi-threaded | Single-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
| Benefit | Description | Implementation |
|---|---|---|
| Code Reuse | Write business logic once | Shared service definition crate |
| Type Safety | Compile-time API contract | RpcMethodPrebuffered trait |
| Binary Efficiency | Same protocol across platforms | bitcode serialization |
| Single Server | One backend serves all clients | Platform-agnostic RpcServer |
| Flexibility | Easy to add new platforms | Implement RpcServiceCallerInterface |
Sources : README.md:48-49 README.md:50-51