Proof of Concept for creating and using WASM plugins from Rust apps/servers
This project demonstrates how can Rust plugins packaged as WebAssembly System Interface (WASI) Preview 1 be built and used by a "server" logic that loads + use them at runtime; i.e. no compile-time knowledge except for the Trait(s) they're supposed to implement, and where their WASM files are to be found.
Normally you would use an Interface Definition Language (IDL) to specify the Interface(s) those plugins are supposed to implement, generate language specific bindings for them, and later in the server/app that will be using them, load + interact w/ them through some runtime layer. For WASI, the IDL is the WIT (WASM Interface Type) language. A wit-bindgen crate1, and wit-bindgen-cli2, should theoretically generate working Rust traits and macros to use. I however was not able to use those resources to generate and re-use a clean Rust crate representing the Interface without additional edits to the resulting Guest trait.
Besides, for a simple interface, w/ a single stateless function like the one described here, a simple macro to generate the C Foreign Function Interface (FFI) wrapper was not too hard. The original WIT source looked like this...
package wit:api@0.1.0;
interface hashing {
hash: func(seed: u32, salt: u32, data: string) -> u32;
}
world lib {
export hashing;
}
This project is organized as a Cargo Workspace. One Interface crate is defined in interfaces/hashing, and named Hashing:
pub trait Hashing {
fn hash(&self, seed: u32, salt: u32, data: &[u8]) -> u32;
}It's sole function is a one-shot call to instantiate a hashing algorithm with a provided seed, then digest a salt (an unsigned 32-bit integer), followed by a byte slice to produce + return an unsigned 32-bit integer result.
Two implementations using fxhash and twox-hash algorithms are provided in crates plugins/fx-plugin and plugins/xx-plugin respectively.
This project builds the plugins using the cargo build command with the target wasm32-wasip1. That target must be installed beforehand w/
$ rustup target add wasm32-wasip1 ↵.
A Bourne Again SHell (build-plugins.sh) is provided in the project's root directory to compile both plugins and copy the resulting WASM files to a folder named plugins inside the server.
The main() function of server expects the plugins to be found there.
From the project's root, do
$ ./build-plugins.sh ↵.
Once the plugins are built (and copied to the server's plugins folder), do
$ cargo r -p server -r ↵.
The main() function of the server loads, then calls both plugins w/ the same data and prints the results.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.