package hyperware:process@1.0.0;
interface standard {
// ˗ˏˋ ♡ ˎˊ˗
// System Types
// ˗ˏˋ ♡ ˎˊ˗
/// JSON is passed over Wasm boundary as a string.
type json = string;
/// In types passed from kernel, node-id will be a valid Hypermap entry.
type node-id = string;
/// Context, like a message body, is a protocol-defined serialized byte
/// array. It is used when building a Request to save information that
/// will not be part of a Response, in order to more easily handle
/// ("contextualize") that Response.
type context = list<u8>;
record process-id {
process-name: string,
package-name: string,
publisher-node: node-id,
}
record package-id {
package-name: string,
publisher-node: node-id,
}
record address {
node: node-id,
process: process-id,
}
record lazy-load-blob {
mime: option<string>,
bytes: list<u8>,
}
record request {
// set in order to inherit lazy-load-blob from parent message, and if
// expects-response is none, direct response to source of parent.
// also carries forward certain aspects of parent message in kernel,
// see documentation for formal spec and examples:
// https://docs.rs/hyperware_process_lib/latest/hyperware_process_lib/struct.Request.html
inherit: bool,
// if some, request expects a response in the given number of seconds
expects-response: option<u64>,
body: list<u8>,
metadata: option<json>,
capabilities: list<capability>,
// to grab lazy-load-blob, use get_blob()
}
record response {
inherit: bool,
body: list<u8>,
metadata: option<json>,
capabilities: list<capability>,
// to grab lazy-load-blob, use get_blob()
}
/// A message can be a request or a response. Within a response, there is
/// a result which surfaces any error that happened because of a request.
/// A successful response will contain the context of the request it
/// matches, if any was set.
variant message {
request(request),
response(tuple<response, option<context>>),
}
record capability {
issuer: address,
params: json,
}
/// On-exit is a setting that determines what happens when a process
/// panics, completes, or otherwise "ends".
/// NOTE: requests will always have expects-response set to false by kernel.
variant on-exit {
none,
restart,
requests(list<tuple<address, request, option<lazy-load-blob>>>),
}
/// Send errors come from trying to send a message to another process,
/// either locally or on another node.
/// A message can fail by timing out, or by the node being entirely
/// unreachable (offline or can't be found in PKI). In either case,
/// the message is not delivered and the process that sent it receives
/// that message back along with any assigned context and/or lazy-load-blob,
/// and is free to handle it as it sees fit.
/// In the local case, only timeout errors are possible and also cover the case
/// in which a process is not running or does not exist.
record send-error {
kind: send-error-kind,
target: address,
message: message,
lazy-load-blob: option<lazy-load-blob>,
}
enum send-error-kind {
offline,
timeout,
}
enum spawn-error {
name-taken,
no-file-at-path,
}
// ˗ˏˋ ♡ ˎˊ˗
// System Utils
// ˗ˏˋ ♡ ˎˊ˗
/// Prints to the terminal at a given verbosity level.
/// Higher verbosity levels print more information.
/// Level 0 is always printed -- use sparingly.
print-to-terminal: func(verbosity: u8, message: string);
/// Returns the address of the process.
our: func() -> address;
// ˗ˏˋ ♡ ˎˊ˗
// Process Management
// ˗ˏˋ ♡ ˎˊ˗
get-on-exit: func() -> on-exit;
set-on-exit: func(on-exit: on-exit);
get-state: func() -> option<list<u8>>;
set-state: func(bytes: list<u8>);
clear-state: func();
spawn: func(
// name is optional. if not provided, name will be a random u64.
name: option<string>,
// wasm-path must be located within package's drive
wasm-path: string,
on-exit: on-exit,
// requested capabilities must be owned by the caller
request-capabilities: list<capability>,
// granted capabilities will be generated by the child process
// and handed out to the indicated process-id.
grant-capabilities: list<tuple<process-id, json>>,
public: bool
) -> result<process-id, spawn-error>;
// ˗ˏˋ ♡ ˎˊ˗
// Capabilities Management
// ˗ˏˋ ♡ ˎˊ˗
/// Saves the capabilities to persisted process state.
save-capabilities: func(caps: list<capability>);
/// Deletes the capabilities from persisted process state.
drop-capabilities: func(caps: list<capability>);
/// Gets all capabilities from persisted process state.
our-capabilities: func() -> list<capability>;
// ˗ˏˋ ♡ ˎˊ˗
// Message I/O
// ˗ˏˋ ♡ ˎˊ˗
/// Ingest next message when it arrives along with its source.
/// Almost all long-running processes will call this in a loop.
receive: func() ->
result<tuple<address, message>, tuple<send-error, option<context>>>;
/// Returns whether or not the current message has a blob.
has-blob: func() -> bool;
/// Returns the blob of the current message, if any.
get-blob: func() -> option<lazy-load-blob>;
/// Returns the last blob this process received.
last-blob: func() -> option<lazy-load-blob>;
/// Send request to target.
send-request: func(
target: address,
request: request,
context: option<context>,
lazy-load-blob: option<lazy-load-blob>
);
/// Send requests to targets.
send-requests: func(
requests: list<tuple<address,
request,
option<context>,
option<lazy-load-blob>>>
);
/// Send response to the request currently being handled.
send-response: func(
response: response,
lazy-load-blob: option<lazy-load-blob>
);
/// Send a single request, then block (internally) until its response. The
/// type returned is Message but will always contain Response.
send-and-await-response: func(
target: address,
request: request,
lazy-load-blob: option<lazy-load-blob>
) -> result<tuple<address, message>, send-error>;
}
world lib {
import standard;
}
world process-v1 {
include lib;
export init: func(our: string);
}