use alloc::string::ToString;
use myrmic_common::db::Scope;
use myrmic_common::gateway::{AssetMount, MountRequest, UnmountRequest, asset_scope};
use myrmic_common::types::error::SUCCESS;
use crate::db::store::BlobStore;
use crate::{Sri, String};
pub use myrmic_common::gateway::{Fallback, GatewayError};
mod c_functions {
use core::ffi::c_int;
#[link(wasm_import_module = "gateway")]
unsafe extern "C" {
pub(super) fn gateway_mount(buffer: *const u8, length: c_int) -> c_int;
pub(super) fn gateway_unmount(buffer: *const u8, length: c_int) -> c_int;
}
}
#[must_use]
pub fn assets(sri: Sri) -> BlobStore {
BlobStore::new(asset_scope(&sri.to_string()))
}
pub fn mount(mount: impl Into<String>) -> Mount {
Mount {
request: MountRequest {
mount: mount.into(),
api: None,
ws: None,
assets: None,
},
}
}
pub fn unmount(mount: impl Into<String>) -> Result<(), GatewayError> {
let request = UnmountRequest {
mount: mount.into(),
};
let payload = postcard::to_allocvec(&request).map_err(|_| GatewayError::WriteFailed)?;
let status = unsafe {
c_functions::gateway_unmount(payload.as_ptr(), payload.len() as core::ffi::c_int)
};
to_result(status)
}
pub struct Mount {
request: MountRequest,
}
impl Mount {
#[must_use]
pub fn api(mut self, path: impl Into<String>) -> Self {
self.request.api = Some(path.into());
self
}
#[must_use]
pub fn ws(mut self, path: impl Into<String>) -> Self {
self.request.ws = Some(path.into());
self
}
#[must_use]
pub fn assets(mut self) -> Self {
self.asset_mount();
self
}
#[must_use]
pub fn index(mut self, path: impl Into<String>) -> Self {
self.asset_mount().index = Some(path.into());
self
}
#[must_use]
pub fn fallback(mut self, fallback: Fallback) -> Self {
self.asset_mount().fallback = fallback;
self
}
#[must_use]
pub fn scope(mut self, scope: Scope) -> Self {
self.asset_mount().scope = Some(scope);
self
}
pub fn bind(self) -> Result<(), GatewayError> {
let payload =
postcard::to_allocvec(&self.request).map_err(|_| GatewayError::WriteFailed)?;
let status = unsafe {
c_functions::gateway_mount(payload.as_ptr(), payload.len() as core::ffi::c_int)
};
to_result(status)
}
fn asset_mount(&mut self) -> &mut AssetMount {
self.request.assets.get_or_insert_with(AssetMount::default)
}
}
fn to_result(status: core::ffi::c_int) -> Result<(), GatewayError> {
match status {
code if code == SUCCESS => Ok(()),
code => Err(GatewayError::try_from(code)
.unwrap_or_else(|code| panic!("unexpected gateway error code from host: {code}"))),
}
}