use std::sync::Arc;
use anyhow::{Context, Result};
use wasm_sql::SqlHostStateView;
use wasmtime::component::{Component, Linker, ResourceTable};
use wasmtime::{Config, Engine, Store};
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView};
use wasm_sql::core::bindings::SqlHostState;
use wasm_sql::sqldb::SqlDB;
use wasm_sql::sqldb::sqlx::postgres::PgPoolOptions;
struct HostState {
sql: SqlHostState,
wasi: WasiCtx,
table: ResourceTable,
}
mod bindings {
wasmtime::component::bindgen!({
world: "example:guest-app/app",
path: ["./wit", "./wit/postgres", "./examples/guest-app/wit"],
});
}
impl WasiView for HostState {
fn ctx(&mut self) -> WasiCtxView<'_> {
WasiCtxView {
ctx: &mut self.wasi,
table: &mut self.table,
}
}
}
impl SqlHostStateView for HostState {
fn sql_host_state(&mut self) -> &mut SqlHostState {
&mut self.sql
}
}
#[tokio::main]
async fn main() -> Result<()> {
let database_url =
std::env::var("DATABASE_URL").expect("DATABASE_URL variable is not set");
println!("Connecting to database: {}", database_url);
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&database_url)
.await
.context("Failed to connect to database")?;
let sql_db = Arc::new(SqlDB::new(pool));
let mut config = Config::new();
config.async_support(true);
config.wasm_component_model(true);
config.wasm_component_model_async(true);
let engine = Engine::new(&config)?;
let mut linker: Linker<HostState> = Linker::new(&engine);
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
wasm_sql::add_to_linker(&mut linker)?;
let wasm_path = "target/wasm32-wasip2/debug/wasm_sql_guest_app_example.wasm";
println!("Loading component from: {}", wasm_path);
let component = Component::from_file(&engine, wasm_path)
.context("Failed to load WASM component. Did you build guest-app?")?;
let state = HostState {
sql: SqlHostState::new(sql_db),
wasi: WasiCtxBuilder::new().inherit_stdio().build(),
table: ResourceTable::new(),
};
let mut store = Store::new(&engine, state);
let instance = bindings::App::instantiate_async(&mut store, &component, &mut linker).await.expect("failed to instantiate guest-app");
let _ = store.run_concurrent(async move |accessor| {
let _ = instance.example_guest_app_main().call_run(accessor).await;
}).await;
println!("Guest executed successfully!");
Ok(())
}