pub use crate::hyperware::process::standard::*;
use serde_json::Value;
wit_bindgen::generate!({
path: "hyperware-wit",
world: "process-lib",
generate_unused_types: true,
});
pub mod bindings;
pub mod dao;
pub mod eth;
pub mod homepage;
pub mod http;
pub mod hypermap;
pub mod kernel_types;
pub mod kv;
#[cfg(feature = "logging")]
pub mod logging;
pub mod net;
pub mod sign;
#[cfg(feature = "hyperwallet")]
pub mod signer;
pub mod sqlite;
pub mod timer;
pub mod vfs;
#[cfg(feature = "hyperwallet")]
pub mod wallet;
pub mod scripting;
#[cfg(feature = "hyperapp")]
pub mod hyperapp;
#[cfg(feature = "hyperwallet")]
pub mod hyperwallet_client;
mod types;
pub use types::{
address::{Address, AddressParseError},
capability::Capability,
lazy_load_blob::LazyLoadBlob,
message::{BuildError, Message, _wit_message_to_message},
on_exit::OnExit,
package_id::PackageId,
process_id::{ProcessId, ProcessIdParseError},
request::Request,
response::Response,
send_error::{SendError, SendErrorKind, _wit_send_error_to_send_error},
};
#[macro_export]
macro_rules! call_init {
($init_func:ident) => {
struct Component;
impl Guest for Component {
fn init(our: String) {
let our: Address = our.parse().unwrap();
$init_func(our);
}
}
export!(Component);
};
}
#[macro_export]
macro_rules! println {
() => {
$crate::print_to_terminal(0, "\n");
};
($($arg:tt)*) => {{
$crate::print_to_terminal(0, &format!($($arg)*));
}};
}
#[macro_export]
macro_rules! kiprintln {
() => {
$crate::print_to_terminal(0, "\n");
};
($($arg:tt)*) => {{
$crate::print_to_terminal(0, &format!($($arg)*));
}};
}
#[macro_export]
macro_rules! process_println {
() => {
let our = $crate::our();
$crate::print_to_terminal(0, format!("{}: ", our.process()).as_str());
};
($($arg:tt)*) => {{
let our = $crate::our();
$crate::print_to_terminal(0, format!("{}: {}", our.process(), format!($($arg)*)).as_str());
}};
}
pub fn await_message() -> Result<Message, SendError> {
match crate::receive() {
Ok((source, message)) => Ok(_wit_message_to_message(source, message)),
Err((send_err, context)) => Err(_wit_send_error_to_send_error(send_err, context)),
}
}
pub fn await_next_message_body() -> Result<Vec<u8>, SendError> {
match await_message() {
Ok(msg) => Ok(msg.body().to_vec()),
Err(e) => Err(e.into()),
}
}
pub fn spawn(
name: Option<&str>,
wasm_path: &str,
on_exit: OnExit,
request_capabilities: Vec<Capability>,
grant_capabilities: Vec<(ProcessId, Json)>,
public: bool,
) -> Result<ProcessId, SpawnError> {
crate::hyperware::process::standard::spawn(
name,
wasm_path,
&on_exit._to_standard().map_err(|_e| SpawnError::NameTaken)?,
&request_capabilities,
&grant_capabilities,
public,
)
}
pub fn make_blob<T, F, E>(blob: &T, serializer: F) -> Result<LazyLoadBlob, E>
where
F: Fn(&T) -> Result<Vec<u8>, E>,
E: std::error::Error,
{
Ok(LazyLoadBlob {
mime: None,
bytes: serializer(blob)?,
})
}
pub fn get_typed_blob<T, F, E>(deserializer: F) -> Option<T>
where
F: Fn(&[u8]) -> Result<T, E>,
E: std::error::Error,
{
match crate::get_blob() {
Some(blob) => match deserializer(&blob.bytes) {
Ok(thing) => Some(thing),
Err(_) => None,
},
None => None,
}
}
pub fn get_typed_state<T, F, E>(deserializer: F) -> Option<T>
where
F: Fn(&[u8]) -> Result<T, E>,
E: std::error::Error,
{
match crate::get_state() {
Some(bytes) => match deserializer(&bytes) {
Ok(thing) => Some(thing),
Err(_) => None,
},
None => None,
}
}
pub fn can_message(address: &Address) -> bool {
let address = eval_our(address);
crate::our_capabilities()
.iter()
.any(|cap| cap.params == "\"messaging\"" && cap.issuer == address)
}
pub fn get_capability(issuer: &Address, params: &str) -> Option<Capability> {
let issuer = eval_our(issuer);
let params = serde_json::from_str::<Value>(params).unwrap_or_default();
crate::our_capabilities().into_iter().find(|cap| {
let cap_params = serde_json::from_str::<Value>(&cap.params).unwrap_or_default();
cap.issuer == issuer && params == cap_params
})
}
pub fn eval_our(address: &Address) -> Address {
let mut address = address.clone();
if address.node() == "our" {
let our = crate::our();
address.node = our.node().to_string()
}
address
}
#[derive(Debug, PartialEq, Eq)]
pub enum WaitClassification {
Starting,
Ready,
Unknown,
}
pub fn wait_for_process_ready<F>(
target: Address,
request_body: Vec<u8>,
timeout_s: u64,
retry_delay_s: u64,
mut classify: F,
treat_unknown_as_ready: bool,
max_attempts: Option<u32>,
) where
F: FnMut(&[u8]) -> WaitClassification,
{
let mut attempt = 1;
loop {
let mut fail_message_suffix = format!(", retrying in {retry_delay_s}s");
if let Some(ma) = max_attempts {
if attempt >= ma {
fail_message_suffix = ", abandoning waiting and proceeding as if ready".to_string()
}
}
match Request::to(target.clone())
.body(request_body.clone())
.send_and_await_response(timeout_s)
{
Ok(Ok(response)) => {
let classification = classify(response.body());
match classification {
WaitClassification::Starting => {
crate::print_to_terminal(
2,
&format!(
"Target {} still starting (attempt {}){}",
target, attempt, fail_message_suffix
),
);
}
WaitClassification::Ready => {
crate::print_to_terminal(
2,
&format!("Target {} ready after {} attempt(s)", target, attempt),
);
break;
}
WaitClassification::Unknown => {
if treat_unknown_as_ready {
crate::print_to_terminal(
2,
&format!(
"Target {} responded with unknown payload, proceeding as ready",
target
),
);
break;
} else {
crate::print_to_terminal(
2,
&format!(
"Target {} responded with unknown payload{}",
target, fail_message_suffix
),
);
}
}
}
}
Ok(Err(e)) => {
crate::print_to_terminal(
2,
&format!(
"Error response from {} (attempt {}): {:?}{}",
target, attempt, e, fail_message_suffix
),
);
}
Err(e) => {
crate::print_to_terminal(
2,
&format!(
"Failed to contact {} (attempt {}): {:?}{}",
target, attempt, e, fail_message_suffix
),
);
}
}
attempt += 1;
std::thread::sleep(std::time::Duration::from_secs(retry_delay_s));
}
}
#[macro_export]
macro_rules! Spawn {
(|$($param:ident : $type:ty),+ $(,)?| $body:block) => {};
($fn_name:ident($($arg:expr),* $(,)?)) => {};
(
|$($param:ident : $type:ty),+ $(,)?| $body:block,
$(
$key:ident : $value:expr
$(,)?
)*
) => {{
$crate::validate_spawn_args!($($key),*);
}};
(
$fn_name:ident($($arg:expr),* $(,)?),
$(
$key:ident : $value:expr
$(,)?
)*
) => {{
$crate::validate_spawn_args!($($key),*);
}};
}
#[macro_export]
macro_rules! validate_spawn_args {
() => {};
(name) => {};
(on_exit) => {};
(request_capabilities) => {};
(grant_capabilities) => {};
(public) => {};
($first:ident, $($rest:ident),+ $(,)?) => {
validate_spawn_args!($first);
validate_spawn_args!($($rest),+);
};
($invalid:ident $(, $($rest:tt)*)?) => {
compile_error!(concat!(
"Invalid Spawn argument '",
stringify!($invalid),
"'. Valid options are: name, on_exit, request_capabilities, grant_capabilities, public"
));
};
}