nectar/wit/uqbar.wit
2023-11-02 23:43:10 -04:00

187 lines
5.8 KiB
Plaintext

package uqbar:process@0.3.0
interface standard {
// JSON is passed over WASM boundary as a string.
type json = string
type node-id = string
// context, like ipc, 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,
}
// TODO better name for this
record address {
node: node-id,
process: process-id,
}
record payload {
mime: option<string>,
bytes: list<u8>,
}
record request {
// if true, this request inherits context AND payload of incipient
// request, and cannot have its own context.
inherit: bool,
// if Some, this request expects a response in the number of seconds given
expects-response: option<u64>,
ipc: list<u8>,
metadata: option<json>,
// to grab payload, use get_payload()
}
record response {
inherit: bool,
ipc: list<u8>,
metadata: option<json>,
// to grab payload, use get_payload()
}
// 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>>),
}
variant capabilities {
none,
all,
some(list<signed-capability>),
}
record signed-capability {
issuer: address,
params: json,
signature: list<u8>,
}
// on-panic is a setting that determines what happens when a process panics.
// NOTE: requests should have expects-response set to false, will always be set to that by kernel
variant on-panic {
none,
restart,
requests(list<tuple<address, request, option<payload>>>),
}
// network errors come from trying to send a message to another node.
// a message can fail by timing out, or by the node being entirely unreachable (offline).
// in either case, the message is not delivered, and the process that sent it
// receives that message along with any assigned context and/or payload,
// and is free to handle it as it sees fit.
// note that if the message is a response, the process can issue a response again,
// and it will be directed to the same (remote) request as the original.
record send-error {
kind: send-error-kind,
message: message,
payload: option<payload>,
}
enum send-error-kind {
offline,
timeout,
}
enum spawn-error {
name-taken,
no-file-at-path,
// TODO more here?
}
// system utils:
print-to-terminal: func(verbosity: u8, message: string)
// **more will be added here with regard to blockchains**
get-eth-block: func() -> u64
// process management:
set-on-panic: func(on-panic: on-panic)
get-state: func() -> option<list<u8>>
set-state: func(bytes: list<u8>)
clear-state: func()
spawn: func(
name: option<string>,
wasm-path: string, // must be located within package's drive
on-panic: on-panic,
capabilities: capabilities,
public: bool
) -> result<process-id, spawn-error>
// capabilities management
// gives us all our signed capabilities so we can send them to others
get-capabilities: func() -> list<signed-capability>
// gets a single specific capability
get-capability: func(issuer: address, params: json) -> option<signed-capability>
// attaches a specific signed capability to our next message
attach-capability: func(capability: signed-capability)
// saves capabilities to our store, so we can use them
save-capabilities: func(capabilities: list<signed-capability>)
// check to see if the sender of a prompting message has a given capability, issued by us
// if the prompting message has a remote source, they must have attached it.
has-capability: func(params: json) -> bool
// generates a new capability with our process as the issuer and gives it to the target,
// which must be a locally-running process.
create-capability: func(to: process-id, params: json)
// take a signed capability and save it to a given locally-running process
share-capability: func(to: process-id, capability: signed-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>>>
// gets payload, if any, of the message we just received
get-payload: func() -> option<payload>
// send message(s) to target(s)
send-request:
func(target: address, request: request, context: option<context>, payload: option<payload>)
send-requests:
func(requests: list<tuple<address, request, option<context>, option<payload>>>)
send-response:
func(response: response, payload: option<payload>)
// send a single request, then block (internally) until its response
// the type is Message but will always contain Response
send-and-await-response:
func(target: address, request: request, payload: option<payload>) ->
result<tuple<address, message>, send-error>
}
world lib {
import standard
}
world process {
include lib
export init: func(our: string)
}