mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-23 08:32:23 +03:00
200 lines
5.9 KiB
Plaintext
200 lines
5.9 KiB
Plaintext
package component:uq-process
|
|
|
|
interface types {
|
|
// JSON is passed over WASM boundary as a string.
|
|
type json = string
|
|
|
|
type node-id = string
|
|
|
|
// context is a string of UTF-8 JSON.
|
|
// 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 = json
|
|
|
|
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: option<json>,
|
|
metadata: option<json>,
|
|
// to grab payload, use get_payload()
|
|
}
|
|
|
|
record response {
|
|
ipc: option<json>,
|
|
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?
|
|
}
|
|
}
|
|
|
|
world uq-process {
|
|
use types.{
|
|
json,
|
|
node-id,
|
|
context,
|
|
process-id,
|
|
address,
|
|
|
|
payload,
|
|
request,
|
|
response,
|
|
message,
|
|
|
|
capabilities,
|
|
signed-capability,
|
|
|
|
on-panic,
|
|
send-error,
|
|
send-error-kind,
|
|
spawn-error
|
|
}
|
|
|
|
// entry point to all programs
|
|
export init: func(our: address)
|
|
|
|
// system utils:
|
|
|
|
import print-to-terminal: func(verbosity: u8, message: string)
|
|
import get-unix-time: func() -> u64
|
|
import get-eth-block: func() -> u64
|
|
|
|
// process management:
|
|
|
|
import set-on-panic: func(on-panic: on-panic)
|
|
|
|
import get-state: func() -> option<list<u8>>
|
|
|
|
import set-state: func(bytes: list<u8>)
|
|
|
|
import clear-state: func()
|
|
|
|
import 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
|
|
import get-capabilities: func() -> list<signed-capability>
|
|
|
|
// gets a single specific capability
|
|
import get-capability: func(issuer: address, params: json) -> option<signed-capability>
|
|
|
|
// attaches a specific signed capability to our next message
|
|
import attach-capability: func(capability: signed-capability)
|
|
|
|
// saves capabilities to our store, so we can use them
|
|
import 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.
|
|
import has-capability: func(params: json) -> bool
|
|
|
|
|
|
// message I/O:
|
|
|
|
// ingest next message when it arrives along with its source.
|
|
// almost all long-running processes will call this in a loop
|
|
import receive: func() -> result<tuple<address, message>, tuple<send-error, option<context>>>
|
|
|
|
// gets payload, if any, of the message we just received
|
|
import get-payload: func() -> option<payload>
|
|
|
|
// send message(s) to target(s)
|
|
import send-request:
|
|
func(target: address, request: request, context: option<context>, payload: option<payload>)
|
|
import send-requests:
|
|
func(requests: list<tuple<address, request, option<context>, option<payload>>>)
|
|
import 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
|
|
import send-and-await-response:
|
|
func(target: address, request: request, payload: option<payload>) ->
|
|
result<tuple<address, message>, send-error>
|
|
|
|
// wasi
|
|
import wasi:random/insecure
|
|
import wasi:random/insecure-seed
|
|
import wasi:random/random
|
|
}
|