-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhyperware.wit
224 lines (181 loc) · 6.81 KB
/
hyperware.wit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package hyperware:[email protected];
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 Kimap 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);
}