I've built this as a personal learning project to improve my understanding of WebAssembly on the server side. This project demonstrates how to run a native Rust Host (using Wasmtime, Tokio, Axum) that orchestrates multiple Wasm Guests written in different languages (Rust and Python), all communicating via WASI Preview 2.
The project focuses on the end-to-end integration while the business logic implemented by the guest and the capbilities provided by the host are rather basic.
The file wit/cipher.wit specifies a encoder-decoder-service interface which declares two functions encr and decr (see Cannot use function name "encrypt" #187) and consumes the host's audit-log capability.
Currently there is one Rust-based guest providing the Caesar cipher algorithm and a Python-based guest implementing the Vigenère cipher.
- Interface (
wit/cipher.wit): Defines the interface. Guests must exportencranddecrfunctions; the Host must provideaudit-log. - Host: Wasm-Runner based on wasmtime that expects guests to implement the
encoder-decoder-serviceinterface specified inwit/cipher.wit. It is compiled to a native Rust binary. Runs the engine and the web server. - Guest 1: Written in Rust. Compiled to wasm32-wasip2. Implements the Caesar cipher.
- Guest 2: Written in Python. Compiled to Wasm using componentize-py. Implements the Vigenère cipher.
- Host calls the guests encrypt/decrypt functions based on the algorithm specified in the incoming requests.
- Both guests in turn call the audit-log function.
- Rust: latest stable version.
- Wasm target: run
rustup target add wasm32-wasip2 - Python: 3.10+
- componentize-py: For the
vigenere-guest. Runpip install requirements.txt - Optional: wasm-tools for debugging (
cargo install wasm-tools)
You can configure the algorithms using environment variables:
SHIFT_AMOUNT: Shift offset for the Caesar cipher guest (Default:3)VIGENERE_KEYWORD: Keyword for the Vigenère cipher guest (Default:WASM).PORT: for the Host's axum-based webserver (Default:3000)
Use the Makefile to handle the compilation of both the Rust and Python code.
# Build the Host and both Guests
make build
# Directly run the Host (Dev profile with debug info)
make runOnce the server is ready and running it should print out on which port it is listening to.
Note that the algorithm-name capitlization matters.
Encrypt using Caesar cipher
With default SHIFT_AMOUNT of 3
curl -X POST http://localhost:3000/encrypt \
-H "Content-Type: application/json" \
-d '{"message": "Hello, World!", "algorithm": "Caesar"}'
# Output: { "result": "Khoor, Zruog!" }Decrypt using Caesar cipher
With default SHIFT_AMOUNT of 3
curl -X POST http://localhost:3000/decrypt \
-H "Content-Type: application/json" \
-d '{"message": "Khoor, Zruog!", "algorithm": "Caesar"}'
# Output: { "result": "Hello, World!" }Encrypt using Vigenère
With default VIGENERE_KEYWORD set to WASM
curl -X POST http://localhost:3000/encrypt \
-H "Content-Type: application/json" \
-d '{ "message": "Hello, World!", "algorithm": "Vigenere" }'
# Output: { "result": "Dedxk, Wgdhd!" }Decrypt using Vigenère
With default VIGENERE_KEYWORD set to WASM
curl -X POST http://localhost:3000/decrypt \
-H "Content-Type: application/json" \
-d '{ "message": "Dedxk, Wgdhd!", "algorithm": "Vigenere" }'
# Output: { "result": "Hello, World!" }The list of sources I used to build this: