wao 0.25.3 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/ao.js +235 -110
- package/cjs/armem-base.js +6 -5
- package/cjs/hb.js +185 -101
- package/cjs/hyperbeam.js +18 -15
- package/cjs/lua/aos_wamr.js +1 -0
- package/cjs/lua/hyper-aos.js +1 -0
- package/cjs/signer.js +35 -6
- package/cjs/utils.js +2 -1
- package/esm/ao.js +106 -46
- package/esm/armem-base.js +5 -2
- package/esm/hb.js +35 -13
- package/esm/hyperbeam.js +12 -9
- package/esm/lua/aos_wamr.js +1 -0
- package/esm/lua/hyper-aos.js +1 -0
- package/esm/signer.js +21 -4
- package/esm/utils.js +3 -1
- package/package.json +1 -1
- package/cjs/lua/aos2-wamr.wasm +0 -0
- package/cjs/lua/hyper-aos.lua +0 -2563
- package/esm/lua/aos2-wamr.wasm +0 -0
- package/esm/lua/hyper-aos.lua +0 -2563
package/cjs/lua/hyper-aos.lua
DELETED
|
@@ -1,2563 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
local function load_json()
|
|
3
|
-
local json = {_version = "0.2.0"}
|
|
4
|
-
|
|
5
|
-
-------------------------------------------------------------------------------
|
|
6
|
-
-- Encode
|
|
7
|
-
-------------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
local encode
|
|
10
|
-
|
|
11
|
-
local escape_char_map = {
|
|
12
|
-
["\\"] = "\\",
|
|
13
|
-
["\""] = "\"",
|
|
14
|
-
["\b"] = "b",
|
|
15
|
-
["\f"] = "f",
|
|
16
|
-
["\n"] = "n",
|
|
17
|
-
["\r"] = "r",
|
|
18
|
-
["\t"] = "t"
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
local escape_char_map_inv = {["/"] = "/"}
|
|
22
|
-
for k, v in pairs(escape_char_map) do escape_char_map_inv[v] = k end
|
|
23
|
-
|
|
24
|
-
local function escape_char(c)
|
|
25
|
-
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
local function encode_nil(val) return "null" end
|
|
29
|
-
|
|
30
|
-
local function encode_table(val, stack)
|
|
31
|
-
local res = {}
|
|
32
|
-
stack = stack or {}
|
|
33
|
-
|
|
34
|
-
-- Circular reference?
|
|
35
|
-
if stack[val] then error("circular reference") end
|
|
36
|
-
|
|
37
|
-
stack[val] = true
|
|
38
|
-
|
|
39
|
-
if rawget(val, 1) ~= nil or next(val) == nil then
|
|
40
|
-
-- Treat as array -- check keys are valid and it is not sparse
|
|
41
|
-
local n = 0
|
|
42
|
-
for k in pairs(val) do
|
|
43
|
-
if type(k) ~= "number" then
|
|
44
|
-
error("invalid table: mixed or invalid key types")
|
|
45
|
-
end
|
|
46
|
-
n = n + 1
|
|
47
|
-
end
|
|
48
|
-
if n ~= #val then error("invalid table: sparse array") end
|
|
49
|
-
-- Encode
|
|
50
|
-
for i = 1, #val do res[i] = encode(val[i], stack) end
|
|
51
|
-
stack[val] = nil
|
|
52
|
-
return "[" .. table.concat(res, ",") .. "]"
|
|
53
|
-
else
|
|
54
|
-
-- Treat as an object
|
|
55
|
-
local i = 1
|
|
56
|
-
for k, v in pairs(val) do
|
|
57
|
-
if type(k) ~= "string" then
|
|
58
|
-
error("invalid table: mixed or invalid key types")
|
|
59
|
-
end
|
|
60
|
-
if type(v) ~= "function" then
|
|
61
|
-
res[i] = encode(k, stack) .. ":" .. encode(v, stack)
|
|
62
|
-
i = i + 1
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
stack[val] = nil
|
|
66
|
-
return "{" .. table.concat(res, ",") .. "}"
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
local function encode_string(val)
|
|
71
|
-
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
local function encode_number(val)
|
|
75
|
-
-- Check for NaN, -inf and inf
|
|
76
|
-
if val ~= val or val <= -math.huge or val >= math.huge then
|
|
77
|
-
error("unexpected number value '" .. tostring(val) .. "'")
|
|
78
|
-
end
|
|
79
|
-
return string.format("%.14g", val)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
local type_func_map = {
|
|
83
|
-
["nil"] = encode_nil,
|
|
84
|
-
["table"] = encode_table,
|
|
85
|
-
["string"] = encode_string,
|
|
86
|
-
["number"] = encode_number,
|
|
87
|
-
["boolean"] = tostring
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
encode = function(val, stack)
|
|
91
|
-
local t = type(val)
|
|
92
|
-
local f = type_func_map[t]
|
|
93
|
-
if f then return f(val, stack) end
|
|
94
|
-
error("unexpected type '" .. t .. "'")
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
function json.encode(val) return (encode(val)) end
|
|
98
|
-
|
|
99
|
-
-------------------------------------------------------------------------------
|
|
100
|
-
-- Decode
|
|
101
|
-
-------------------------------------------------------------------------------
|
|
102
|
-
|
|
103
|
-
local parse
|
|
104
|
-
|
|
105
|
-
local function create_set(...)
|
|
106
|
-
local res = {}
|
|
107
|
-
for i = 1, select("#", ...) do res[select(i, ...)] = true end
|
|
108
|
-
return res
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
local space_chars = create_set(" ", "\t", "\r", "\n")
|
|
112
|
-
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
|
113
|
-
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
|
114
|
-
local literals = create_set("true", "false", "null")
|
|
115
|
-
|
|
116
|
-
local literal_map = {["true"] = true, ["false"] = false, ["null"] = nil}
|
|
117
|
-
|
|
118
|
-
local function next_char(str, idx, set, negate)
|
|
119
|
-
for i = idx, #str do if set[str:sub(i, i)] ~= negate then return i end end
|
|
120
|
-
return #str + 1
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
local function decode_error(str, idx, msg)
|
|
124
|
-
local line_count = 1
|
|
125
|
-
local col_count = 1
|
|
126
|
-
for i = 1, idx - 1 do
|
|
127
|
-
col_count = col_count + 1
|
|
128
|
-
if str:sub(i, i) == "\n" then
|
|
129
|
-
line_count = line_count + 1
|
|
130
|
-
col_count = 1
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
error(string.format("%s at line %d col %d", msg, line_count, col_count))
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
local function codepoint_to_utf8(n)
|
|
137
|
-
local f = math.floor
|
|
138
|
-
if n <= 0x7f then
|
|
139
|
-
return string.char(n)
|
|
140
|
-
elseif n <= 0x7ff then
|
|
141
|
-
return string.char(f(n / 64) + 192, n % 64 + 128)
|
|
142
|
-
elseif n <= 0xffff then
|
|
143
|
-
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128,
|
|
144
|
-
n % 64 + 128)
|
|
145
|
-
elseif n <= 0x10ffff then
|
|
146
|
-
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
|
|
147
|
-
f(n % 4096 / 64) + 128, n % 64 + 128)
|
|
148
|
-
end
|
|
149
|
-
error(string.format("invalid unicode codepoint '%x'", n))
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
local function parse_unicode_escape(s)
|
|
153
|
-
local n1 = tonumber(s:sub(1, 4), 16)
|
|
154
|
-
local n2 = tonumber(s:sub(7, 10), 16)
|
|
155
|
-
if n2 then
|
|
156
|
-
return
|
|
157
|
-
codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
|
|
158
|
-
else
|
|
159
|
-
return codepoint_to_utf8(n1)
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
local function parse_string(str, i)
|
|
164
|
-
local res = {}
|
|
165
|
-
local j = i + 1
|
|
166
|
-
local k = j
|
|
167
|
-
|
|
168
|
-
while j <= #str do
|
|
169
|
-
local x = str:byte(j)
|
|
170
|
-
|
|
171
|
-
if x < 32 then
|
|
172
|
-
decode_error(str, j, "control character in string")
|
|
173
|
-
elseif x == 92 then -- `\`: Escape
|
|
174
|
-
res[#res + 1] = str:sub(k, j - 1)
|
|
175
|
-
j = j + 1
|
|
176
|
-
local c = str:sub(j, j)
|
|
177
|
-
if c == "u" then
|
|
178
|
-
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) or
|
|
179
|
-
str:match("^%x%x%x%x", j + 1) or
|
|
180
|
-
decode_error(str, j - 1,
|
|
181
|
-
"invalid unicode escape in string")
|
|
182
|
-
res[#res + 1] = parse_unicode_escape(hex)
|
|
183
|
-
j = j + #hex
|
|
184
|
-
else
|
|
185
|
-
if not escape_chars[c] then
|
|
186
|
-
decode_error(str, j - 1,
|
|
187
|
-
"invalid escape char '" .. c .. "' in string")
|
|
188
|
-
end
|
|
189
|
-
res[#res + 1] = escape_char_map_inv[c]
|
|
190
|
-
end
|
|
191
|
-
k = j + 1
|
|
192
|
-
elseif x == 34 then -- `"`: End of string
|
|
193
|
-
res[#res + 1] = str:sub(k, j - 1)
|
|
194
|
-
return table.concat(res), j + 1
|
|
195
|
-
end
|
|
196
|
-
j = j + 1
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
decode_error(str, i, "expected closing quote for string")
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
local function parse_number(str, i)
|
|
203
|
-
local x = next_char(str, i, delim_chars)
|
|
204
|
-
local s = str:sub(i, x - 1)
|
|
205
|
-
local n = tonumber(s)
|
|
206
|
-
if not n then decode_error(str, i, "invalid number '" .. s .. "'") end
|
|
207
|
-
return n, x
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
local function parse_literal(str, i)
|
|
211
|
-
local x = next_char(str, i, delim_chars)
|
|
212
|
-
local word = str:sub(i, x - 1)
|
|
213
|
-
if not literals[word] then
|
|
214
|
-
decode_error(str, i, "invalid literal '" .. word .. "'")
|
|
215
|
-
end
|
|
216
|
-
return literal_map[word], x
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
local function parse_array(str, i)
|
|
220
|
-
local res = {}
|
|
221
|
-
local n = 1
|
|
222
|
-
i = i + 1
|
|
223
|
-
while true do
|
|
224
|
-
local x
|
|
225
|
-
i = next_char(str, i, space_chars, true)
|
|
226
|
-
if str:sub(i, i) == "]" then
|
|
227
|
-
i = i + 1
|
|
228
|
-
break
|
|
229
|
-
end
|
|
230
|
-
x, i = parse(str, i)
|
|
231
|
-
res[n] = x
|
|
232
|
-
n = n + 1
|
|
233
|
-
i = next_char(str, i, space_chars, true)
|
|
234
|
-
local chr = str:sub(i, i)
|
|
235
|
-
i = i + 1
|
|
236
|
-
if chr == "]" then break end
|
|
237
|
-
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
|
|
238
|
-
end
|
|
239
|
-
return res, i
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
local function parse_object(str, i)
|
|
243
|
-
local res = {}
|
|
244
|
-
i = i + 1
|
|
245
|
-
while true do
|
|
246
|
-
local key, val
|
|
247
|
-
i = next_char(str, i, space_chars, true)
|
|
248
|
-
if str:sub(i, i) == "}" then
|
|
249
|
-
i = i + 1
|
|
250
|
-
break
|
|
251
|
-
end
|
|
252
|
-
if str:sub(i, i) ~= '"' then
|
|
253
|
-
decode_error(str, i, "expected string for key")
|
|
254
|
-
end
|
|
255
|
-
key, i = parse(str, i)
|
|
256
|
-
i = next_char(str, i, space_chars, true)
|
|
257
|
-
if str:sub(i, i) ~= ":" then
|
|
258
|
-
decode_error(str, i, "expected ':' after key")
|
|
259
|
-
end
|
|
260
|
-
i = next_char(str, i + 1, space_chars, true)
|
|
261
|
-
val, i = parse(str, i)
|
|
262
|
-
res[key] = val
|
|
263
|
-
i = next_char(str, i, space_chars, true)
|
|
264
|
-
local chr = str:sub(i, i)
|
|
265
|
-
i = i + 1
|
|
266
|
-
if chr == "}" then break end
|
|
267
|
-
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
|
|
268
|
-
end
|
|
269
|
-
return res, i
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
local char_func_map = {
|
|
273
|
-
['"'] = parse_string,
|
|
274
|
-
["0"] = parse_number,
|
|
275
|
-
["1"] = parse_number,
|
|
276
|
-
["2"] = parse_number,
|
|
277
|
-
["3"] = parse_number,
|
|
278
|
-
["4"] = parse_number,
|
|
279
|
-
["5"] = parse_number,
|
|
280
|
-
["6"] = parse_number,
|
|
281
|
-
["7"] = parse_number,
|
|
282
|
-
["8"] = parse_number,
|
|
283
|
-
["9"] = parse_number,
|
|
284
|
-
["-"] = parse_number,
|
|
285
|
-
["t"] = parse_literal,
|
|
286
|
-
["f"] = parse_literal,
|
|
287
|
-
["n"] = parse_literal,
|
|
288
|
-
["["] = parse_array,
|
|
289
|
-
["{"] = parse_object
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
parse = function(str, idx)
|
|
293
|
-
local chr = str:sub(idx, idx)
|
|
294
|
-
local f = char_func_map[chr]
|
|
295
|
-
if f then return f(str, idx) end
|
|
296
|
-
decode_error(str, idx, "unexpected character '" .. chr .. "'")
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
function json.decode(str)
|
|
300
|
-
if type(str) ~= "string" then
|
|
301
|
-
error("expected argument of type string, got " .. type(str))
|
|
302
|
-
end
|
|
303
|
-
local res, idx = parse(str, next_char(str, 1, space_chars, true))
|
|
304
|
-
idx = next_char(str, idx, space_chars, true)
|
|
305
|
-
if idx <= #str then decode_error(str, idx, "trailing garbage") end
|
|
306
|
-
return res
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
return json
|
|
310
|
-
|
|
311
|
-
end
|
|
312
|
-
_G.package.loaded[".json"] = load_json()
|
|
313
|
-
print("loaded json")
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
local function load_stringify()
|
|
318
|
-
--- The Stringify module provides utilities for formatting and displaying Lua tables in a more readable manner. Returns the stringify table.
|
|
319
|
-
-- @module stringify
|
|
320
|
-
|
|
321
|
-
--- The stringify table
|
|
322
|
-
-- @table stringify
|
|
323
|
-
-- @field _version The version number of the stringify module
|
|
324
|
-
-- @field isSimpleArray The isSimpleArray function
|
|
325
|
-
-- @field format The format function
|
|
326
|
-
local stringify = { _version = "0.0.1" }
|
|
327
|
-
|
|
328
|
-
-- ANSI color codes
|
|
329
|
-
local colors = {
|
|
330
|
-
red = "\27[31m",
|
|
331
|
-
green = "\27[32m",
|
|
332
|
-
blue = "\27[34m",
|
|
333
|
-
reset = "\27[0m"
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
--- Checks if a table is a simple array (i.e., an array with consecutive numeric keys starting from 1).
|
|
337
|
-
-- @function isSimpleArray
|
|
338
|
-
-- @tparam {table} tbl The table to check
|
|
339
|
-
-- @treturn {boolean} Whether the table is a simple array
|
|
340
|
-
function stringify.isSimpleArray(tbl)
|
|
341
|
-
local arrayIndex = 1
|
|
342
|
-
for k, v in pairs(tbl) do
|
|
343
|
-
if k ~= arrayIndex or (type(v) ~= "number" and type(v) ~= "string") then
|
|
344
|
-
return false
|
|
345
|
-
end
|
|
346
|
-
arrayIndex = arrayIndex + 1
|
|
347
|
-
end
|
|
348
|
-
return true
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
--- Formats a table for display, handling circular references and formatting strings and tables recursively.
|
|
352
|
-
-- @function format
|
|
353
|
-
-- @tparam {table} tbl The table to format
|
|
354
|
-
-- @tparam {number} indent The indentation level (default is 0)
|
|
355
|
-
-- @tparam {table} visited A table to track visited tables and detect circular references (optional)
|
|
356
|
-
-- @treturn {string} A string representation of the table
|
|
357
|
-
function stringify.format(tbl, indent, visited)
|
|
358
|
-
indent = indent or 0
|
|
359
|
-
local toIndent = string.rep(" ", indent)
|
|
360
|
-
local toIndentChild = string.rep(" ", indent + 2)
|
|
361
|
-
|
|
362
|
-
local result = {}
|
|
363
|
-
local isArray = true
|
|
364
|
-
local arrayIndex = 1
|
|
365
|
-
|
|
366
|
-
if stringify.isSimpleArray(tbl) then
|
|
367
|
-
for _, v in ipairs(tbl) do
|
|
368
|
-
if type(v) == "string" then
|
|
369
|
-
v = colors.green .. '"' .. v .. '"' .. colors.reset
|
|
370
|
-
else
|
|
371
|
-
v = colors.blue .. tostring(v) .. colors.reset
|
|
372
|
-
end
|
|
373
|
-
table.insert(result, v)
|
|
374
|
-
end
|
|
375
|
-
return "{ " .. table.concat(result, ", ") .. " }"
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
for k, v in pairs(tbl) do
|
|
379
|
-
if isArray then
|
|
380
|
-
if k == arrayIndex then
|
|
381
|
-
arrayIndex = arrayIndex + 1
|
|
382
|
-
if type(v) == "table" then
|
|
383
|
-
v = stringify.format(v, indent + 2)
|
|
384
|
-
elseif type(v) == "string" then
|
|
385
|
-
v = colors.green .. '"' .. v .. '"' .. colors.reset
|
|
386
|
-
else
|
|
387
|
-
v = colors.blue .. tostring(v) .. colors.reset
|
|
388
|
-
end
|
|
389
|
-
table.insert(result, toIndentChild .. v)
|
|
390
|
-
else
|
|
391
|
-
isArray = false
|
|
392
|
-
result = {}
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
if not isArray then
|
|
396
|
-
if type(v) == "table" then
|
|
397
|
-
visited = visited or {}
|
|
398
|
-
if visited[v] then
|
|
399
|
-
return "<circular reference>"
|
|
400
|
-
end
|
|
401
|
-
visited[v] = true
|
|
402
|
-
|
|
403
|
-
v = stringify.format(v, indent + 2, visited)
|
|
404
|
-
elseif type(v) == "string" then
|
|
405
|
-
v = colors.green .. '"' .. v .. '"' .. colors.reset
|
|
406
|
-
else
|
|
407
|
-
v = colors.blue .. tostring(v) .. colors.reset
|
|
408
|
-
end
|
|
409
|
-
k = colors.red .. k .. colors.reset
|
|
410
|
-
table.insert(result, toIndentChild .. k .. " = " .. v)
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
local prefix = isArray and "{\n" or "{\n "
|
|
415
|
-
local suffix = isArray and "\n" .. toIndent .. " }" or "\n" .. toIndent .. "}"
|
|
416
|
-
local separator = isArray and ",\n" or ",\n "
|
|
417
|
-
return prefix .. table.concat(result, separator) .. suffix
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
return stringify
|
|
421
|
-
|
|
422
|
-
end
|
|
423
|
-
_G.package.loaded[".stringify"] = load_stringify()
|
|
424
|
-
print("loaded stringify")
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
local function load_eval()
|
|
429
|
-
--- The Eval module provides a handler for evaluating Lua expressions. Returns the eval function.
|
|
430
|
-
-- @module eval
|
|
431
|
-
|
|
432
|
-
local stringify = require(".stringify")
|
|
433
|
-
local json = require('.json')
|
|
434
|
-
--- The eval function.
|
|
435
|
-
-- Handler for executing and evaluating Lua expressions.
|
|
436
|
-
-- After execution, the result is stringified and placed in ao.outbox.Output.
|
|
437
|
-
-- @function eval
|
|
438
|
-
-- @tparam {table} ao The ao environment object
|
|
439
|
-
-- @treturn {function} The handler function, which takes a message as an argument.
|
|
440
|
-
-- @see stringify
|
|
441
|
-
return function (ao)
|
|
442
|
-
return function (req)
|
|
443
|
-
local msg = req.body
|
|
444
|
-
-- exec expression
|
|
445
|
-
local expr = msg.body and msg.body.body or msg.data or ""
|
|
446
|
-
local func, err = load("return " .. expr, 'aos', 't', _G)
|
|
447
|
-
local output = ""
|
|
448
|
-
local e = nil
|
|
449
|
-
if err then
|
|
450
|
-
func, err = load(expr, 'aos', 't', _G)
|
|
451
|
-
end
|
|
452
|
-
if func then
|
|
453
|
-
output, e = func()
|
|
454
|
-
else
|
|
455
|
-
ao.outbox.Error = err
|
|
456
|
-
return
|
|
457
|
-
end
|
|
458
|
-
if e then
|
|
459
|
-
ao.outbox.Error = e
|
|
460
|
-
return
|
|
461
|
-
end
|
|
462
|
-
if HandlerPrintLogs and output then
|
|
463
|
-
table.insert(HandlerPrintLogs,
|
|
464
|
-
type(output) == "table"
|
|
465
|
-
and stringify.format(output)
|
|
466
|
-
or tostring(output)
|
|
467
|
-
)
|
|
468
|
-
-- print(stringify.format(HandlerPrintLogs))
|
|
469
|
-
-- else
|
|
470
|
-
-- -- set result in outbox.Output (Left for backwards compatibility)
|
|
471
|
-
-- ao.outbox.Output = {
|
|
472
|
-
-- data = type(output) == "table"
|
|
473
|
-
-- and stringify.format(output) or tostring(output),
|
|
474
|
-
-- prompt = Prompt()
|
|
475
|
-
-- }
|
|
476
|
-
--
|
|
477
|
-
end
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
end
|
|
482
|
-
_G.package.loaded[".eval"] = load_eval()
|
|
483
|
-
print("loaded eval")
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
local function load_utils()
|
|
488
|
-
--- The Utils module provides a collection of utility functions for functional programming in Lua. It includes functions for array manipulation such as concatenation, mapping, reduction, filtering, and finding elements, as well as a property equality checker.
|
|
489
|
-
-- @module utils
|
|
490
|
-
|
|
491
|
-
--- The utils table
|
|
492
|
-
-- @table utils
|
|
493
|
-
-- @field _version The version number of the utils module
|
|
494
|
-
-- @field matchesPattern The matchesPattern function
|
|
495
|
-
-- @field matchesSpec The matchesSpec function
|
|
496
|
-
-- @field curry The curry function
|
|
497
|
-
-- @field concat The concat function
|
|
498
|
-
-- @field reduce The reduce function
|
|
499
|
-
-- @field map The map function
|
|
500
|
-
-- @field filter The filter function
|
|
501
|
-
-- @field find The find function
|
|
502
|
-
-- @field propEq The propEq function
|
|
503
|
-
-- @field reverse The reverse function
|
|
504
|
-
-- @field compose The compose function
|
|
505
|
-
-- @field prop The prop function
|
|
506
|
-
-- @field includes The includes function
|
|
507
|
-
-- @field keys The keys function
|
|
508
|
-
-- @field values The values function
|
|
509
|
-
local utils = { _version = "0.0.5" }
|
|
510
|
-
|
|
511
|
-
--- Given a pattern, a value, and a message, returns whether there is a pattern match.
|
|
512
|
-
-- @usage utils.matchesPattern(pattern, value, msg)
|
|
513
|
-
-- @param pattern The pattern to match
|
|
514
|
-
-- @param value The value to check for in the pattern
|
|
515
|
-
-- @param msg The message to check for the pattern
|
|
516
|
-
-- @treturn {boolean} Whether there is a pattern match
|
|
517
|
-
function utils.matchesPattern(pattern, value, msg)
|
|
518
|
-
-- If the key is not in the message, then it does not match
|
|
519
|
-
if (not pattern) then
|
|
520
|
-
return false
|
|
521
|
-
end
|
|
522
|
-
-- if the patternMatchSpec is a wildcard, then it always matches
|
|
523
|
-
if pattern == '_' then
|
|
524
|
-
return true
|
|
525
|
-
end
|
|
526
|
-
-- if the patternMatchSpec is a function, then it is executed on the tag value
|
|
527
|
-
if type(pattern) == "function" then
|
|
528
|
-
if pattern(value, msg) then
|
|
529
|
-
return true
|
|
530
|
-
else
|
|
531
|
-
return false
|
|
532
|
-
end
|
|
533
|
-
end
|
|
534
|
-
-- if the patternMatchSpec is a string, check it for special symbols (less `-` alone)
|
|
535
|
-
-- and exact string match mode
|
|
536
|
-
if (type(pattern) == 'string') then
|
|
537
|
-
if string.match(pattern, "[%^%$%(%)%%%.%[%]%*%+%?]") then
|
|
538
|
-
if string.match(value, pattern) then
|
|
539
|
-
return true
|
|
540
|
-
end
|
|
541
|
-
else
|
|
542
|
-
if value == pattern then
|
|
543
|
-
return true
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
end
|
|
547
|
-
|
|
548
|
-
-- if the pattern is a table, recursively check if any of its sub-patterns match
|
|
549
|
-
if type(pattern) == 'table' then
|
|
550
|
-
for _, subPattern in pairs(pattern) do
|
|
551
|
-
if utils.matchesPattern(subPattern, value, msg) then
|
|
552
|
-
return true
|
|
553
|
-
end
|
|
554
|
-
end
|
|
555
|
-
end
|
|
556
|
-
|
|
557
|
-
return false
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
--- Given a message and a spec, returns whether there is a spec match.
|
|
561
|
-
-- @usage utils.matchesSpec(msg, spec)
|
|
562
|
-
-- @param msg The message to check for the spec
|
|
563
|
-
-- @param spec The spec to check for in the message
|
|
564
|
-
-- @treturn {boolean} Whether there is a spec match
|
|
565
|
-
function utils.matchesSpec(msg, spec)
|
|
566
|
-
if type(spec) == 'function' then
|
|
567
|
-
return spec(msg)
|
|
568
|
-
-- If the spec is a table, step through every key/value pair in the pattern and check if the msg matches
|
|
569
|
-
-- Supported pattern types:
|
|
570
|
-
-- - Exact string match
|
|
571
|
-
-- - Lua gmatch string
|
|
572
|
-
-- - '_' (wildcard: Message has tag, but can be any value)
|
|
573
|
-
-- - Function execution on the tag, optionally using the msg as the second argument
|
|
574
|
-
-- - Table of patterns, where ANY of the sub-patterns matching the tag will result in a match
|
|
575
|
-
end
|
|
576
|
-
if type(spec) == 'table' then
|
|
577
|
-
for key, pattern in pairs(spec) do
|
|
578
|
-
-- The key can either be in the top level of the 'msg' object
|
|
579
|
-
-- or in the body table of the msg
|
|
580
|
-
local msgValue = msg[key] or msg.body[key]
|
|
581
|
-
if not msgValue then
|
|
582
|
-
return false
|
|
583
|
-
end
|
|
584
|
-
local matchesMsgValue = utils.matchesPattern(pattern, msgValue, msg)
|
|
585
|
-
if not matchesMsgValue then
|
|
586
|
-
return false
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
end
|
|
590
|
-
return true
|
|
591
|
-
end
|
|
592
|
-
|
|
593
|
-
if type(spec) == 'string' and msg.action and msg.action == spec then
|
|
594
|
-
return true
|
|
595
|
-
end
|
|
596
|
-
if type(spec) == 'string' and msg.body.action and msg.body.action == spec then
|
|
597
|
-
return true
|
|
598
|
-
end
|
|
599
|
-
return false
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
--- Given a table, returns whether it is an array.
|
|
603
|
-
-- An 'array' is defined as a table with integer keys starting from 1 and
|
|
604
|
-
-- having no gaps between the keys.
|
|
605
|
-
-- @lfunction isArray
|
|
606
|
-
-- @param table The table to check
|
|
607
|
-
-- @treturn {boolean} Whether the table is an array
|
|
608
|
-
local function isArray(table)
|
|
609
|
-
if type(table) == "table" then
|
|
610
|
-
local maxIndex = 0
|
|
611
|
-
for k, v in pairs(table) do
|
|
612
|
-
if type(k) ~= "number" or k < 1 or math.floor(k) ~= k then
|
|
613
|
-
return false -- If there's a non-integer key, it's not an array
|
|
614
|
-
end
|
|
615
|
-
maxIndex = math.max(maxIndex, k)
|
|
616
|
-
end
|
|
617
|
-
-- If the highest numeric index is equal to the number of elements, it's an array
|
|
618
|
-
return maxIndex == #table
|
|
619
|
-
end
|
|
620
|
-
return false
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
--- Curries a function.
|
|
624
|
-
-- @tparam {function} fn The function to curry
|
|
625
|
-
-- @tparam {number} arity The arity of the function
|
|
626
|
-
-- @treturn {function} The curried function
|
|
627
|
-
utils.curry = function (fn, arity)
|
|
628
|
-
assert(type(fn) == "function", "function is required as first argument")
|
|
629
|
-
arity = arity or debug.getinfo(fn, "u").nparams
|
|
630
|
-
if arity < 2 then return fn end
|
|
631
|
-
|
|
632
|
-
return function (...)
|
|
633
|
-
local args = {...}
|
|
634
|
-
|
|
635
|
-
if #args >= arity then
|
|
636
|
-
return fn(table.unpack(args))
|
|
637
|
-
else
|
|
638
|
-
return utils.curry(function (...)
|
|
639
|
-
return fn(table.unpack(args), ...)
|
|
640
|
-
end, arity - #args)
|
|
641
|
-
end
|
|
642
|
-
end
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
--- Concat two Array Tables
|
|
646
|
-
-- @function concat
|
|
647
|
-
-- @usage utils.concat(a)(b)
|
|
648
|
-
-- @usage utils.concat({1, 2})({3, 4}) --> {1, 2, 3, 4}
|
|
649
|
-
-- @tparam {table<Array>} a The first array
|
|
650
|
-
-- @tparam {table<Array>} b The second array
|
|
651
|
-
-- @treturn {table<Array>} The concatenated array
|
|
652
|
-
utils.concat = utils.curry(function (a, b)
|
|
653
|
-
assert(type(a) == "table", "first argument should be a table that is an array")
|
|
654
|
-
assert(type(b) == "table", "second argument should be a table that is an array")
|
|
655
|
-
assert(isArray(a), "first argument should be a table")
|
|
656
|
-
assert(isArray(b), "second argument should be a table")
|
|
657
|
-
|
|
658
|
-
local result = {}
|
|
659
|
-
for i = 1, #a do
|
|
660
|
-
result[#result + 1] = a[i]
|
|
661
|
-
end
|
|
662
|
-
for i = 1, #b do
|
|
663
|
-
result[#result + 1] = b[i]
|
|
664
|
-
end
|
|
665
|
-
return result
|
|
666
|
-
end, 2)
|
|
667
|
-
|
|
668
|
-
--- Applies a function to each element of a table, reducing it to a single value.
|
|
669
|
-
-- @function utils.reduce
|
|
670
|
-
-- @usage utils.reduce(fn)(initial)(t)
|
|
671
|
-
-- @usage utils.reduce(function(acc, x) return acc + x end)(0)({1, 2, 3}) --> 6
|
|
672
|
-
-- @tparam {function} fn The function to apply
|
|
673
|
-
-- @param initial The initial value
|
|
674
|
-
-- @tparam {table<Array>} t The table to reduce
|
|
675
|
-
-- @return The reduced value
|
|
676
|
-
utils.reduce = utils.curry(function (fn, initial, t)
|
|
677
|
-
assert(type(fn) == "function", "first argument should be a function that accepts (result, value, key)")
|
|
678
|
-
assert(type(t) == "table" and isArray(t), "third argument should be a table that is an array")
|
|
679
|
-
local result = initial
|
|
680
|
-
for k, v in pairs(t) do
|
|
681
|
-
if result == nil then
|
|
682
|
-
result = v
|
|
683
|
-
else
|
|
684
|
-
result = fn(result, v, k)
|
|
685
|
-
end
|
|
686
|
-
end
|
|
687
|
-
return result
|
|
688
|
-
end, 3)
|
|
689
|
-
|
|
690
|
-
--- Applies a function to each element of an array table, mapping it to a new value.
|
|
691
|
-
-- @function utils.map
|
|
692
|
-
-- @usage utils.map(fn)(t)
|
|
693
|
-
-- @usage utils.map(function(x) return x * 2 end)({1, 2, 3}) --> {2, 4, 6}
|
|
694
|
-
-- @tparam {function} fn The function to apply to each element
|
|
695
|
-
-- @tparam {table<Array>} data The table to map over
|
|
696
|
-
-- @treturn {table<Array>} The mapped table
|
|
697
|
-
utils.map = utils.curry(function (fn, data)
|
|
698
|
-
assert(type(fn) == "function", "first argument should be a unary function")
|
|
699
|
-
assert(type(data) == "table" and isArray(data), "second argument should be an Array")
|
|
700
|
-
|
|
701
|
-
local function map (result, v, k)
|
|
702
|
-
result[k] = fn(v, k)
|
|
703
|
-
return result
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
return utils.reduce(map, {}, data)
|
|
707
|
-
end, 2)
|
|
708
|
-
|
|
709
|
-
--- Filters an array table based on a predicate function.
|
|
710
|
-
-- @function utils.filter
|
|
711
|
-
-- @usage utils.filter(fn)(t)
|
|
712
|
-
-- @usage utils.filter(function(x) return x > 1 end)({1, 2, 3}) --> {2,3}
|
|
713
|
-
-- @tparam {function} fn The predicate function to determine if an element should be included.
|
|
714
|
-
-- @tparam {table<Array>} data The array to filter
|
|
715
|
-
-- @treturn {table<Array>} The filtered table
|
|
716
|
-
utils.filter = utils.curry(function (fn, data)
|
|
717
|
-
assert(type(fn) == "function", "first argument should be a unary function")
|
|
718
|
-
assert(type(data) == "table" and isArray(data), "second argument should be an Array")
|
|
719
|
-
|
|
720
|
-
local function filter (result, v, _k)
|
|
721
|
-
if fn(v) then
|
|
722
|
-
table.insert(result, v)
|
|
723
|
-
end
|
|
724
|
-
return result
|
|
725
|
-
end
|
|
726
|
-
|
|
727
|
-
return utils.reduce(filter,{}, data)
|
|
728
|
-
end, 2)
|
|
729
|
-
|
|
730
|
-
--- Finds the first element in an array table that satisfies a predicate function.
|
|
731
|
-
-- @function utils.find
|
|
732
|
-
-- @usage utils.find(fn)(t)
|
|
733
|
-
-- @usage utils.find(function(x) return x > 1 end)({1, 2, 3}) --> 2
|
|
734
|
-
-- @tparam {function} fn The predicate function to determine if an element should be included.
|
|
735
|
-
-- @tparam {table<Array>} t The array table to search
|
|
736
|
-
-- @treturn The first element that satisfies the predicate function
|
|
737
|
-
utils.find = utils.curry(function (fn, t)
|
|
738
|
-
assert(type(fn) == "function", "first argument should be a unary function")
|
|
739
|
-
assert(type(t) == "table", "second argument should be a table that is an array")
|
|
740
|
-
for _, v in pairs(t) do
|
|
741
|
-
if fn(v) then
|
|
742
|
-
return v
|
|
743
|
-
end
|
|
744
|
-
end
|
|
745
|
-
end, 2)
|
|
746
|
-
|
|
747
|
-
--- Checks if a property of an object is equal to a value.
|
|
748
|
-
-- @function utils.propEq
|
|
749
|
-
-- @usage utils.propEq(propName)(value)(object)
|
|
750
|
-
-- @usage utils.propEq("name")("Lua")({name = "Lua"}) --> true
|
|
751
|
-
-- @tparam {string} propName The property name to check
|
|
752
|
-
-- @tparam {string} value The value to check against
|
|
753
|
-
-- @tparam {table} object The object to check
|
|
754
|
-
-- @treturn {boolean} Whether the property is equal to the value
|
|
755
|
-
utils.propEq = utils.curry(function (propName, value, object)
|
|
756
|
-
assert(type(propName) == "string", "first argument should be a string")
|
|
757
|
-
assert(type(value) == "string", "second argument should be a string")
|
|
758
|
-
assert(type(object) == "table", "third argument should be a table<object>")
|
|
759
|
-
|
|
760
|
-
return object[propName] == value
|
|
761
|
-
end, 3)
|
|
762
|
-
|
|
763
|
-
--- Reverses an array table.
|
|
764
|
-
-- @function utils.reverse
|
|
765
|
-
-- @usage utils.reverse(data)
|
|
766
|
-
-- @usage utils.reverse({1, 2, 3}) --> {3, 2, 1}
|
|
767
|
-
-- @tparam {table<Array>} data The array table to reverse
|
|
768
|
-
-- @treturn {table<Array>} The reversed array table
|
|
769
|
-
utils.reverse = function (data)
|
|
770
|
-
assert(type(data) == "table", "argument needs to be a table that is an array")
|
|
771
|
-
return utils.reduce(
|
|
772
|
-
function (result, v, i)
|
|
773
|
-
result[#data - i + 1] = v
|
|
774
|
-
return result
|
|
775
|
-
end,
|
|
776
|
-
{},
|
|
777
|
-
data
|
|
778
|
-
)
|
|
779
|
-
end
|
|
780
|
-
|
|
781
|
-
--- Composes a series of functions into a single function.
|
|
782
|
-
-- @function utils.compose
|
|
783
|
-
-- @usage utils.compose(fn1)(fn2)(fn3)(v)
|
|
784
|
-
-- @usage utils.compose(function(x) return x + 1 end)(function(x) return x * 2 end)(3) --> 7
|
|
785
|
-
-- @tparam {function} ... The functions to compose
|
|
786
|
-
-- @treturn {function} The composed function
|
|
787
|
-
utils.compose = utils.curry(function (...)
|
|
788
|
-
local mutations = utils.reverse({...})
|
|
789
|
-
|
|
790
|
-
return function (v)
|
|
791
|
-
local result = v
|
|
792
|
-
for _, fn in pairs(mutations) do
|
|
793
|
-
assert(type(fn) == "function", "each argument needs to be a function")
|
|
794
|
-
result = fn(result)
|
|
795
|
-
end
|
|
796
|
-
return result
|
|
797
|
-
end
|
|
798
|
-
end, 2)
|
|
799
|
-
|
|
800
|
-
--- Returns the value of a property of an object.
|
|
801
|
-
-- @function utils.prop
|
|
802
|
-
-- @usage utils.prop(propName)(object)
|
|
803
|
-
-- @usage utils.prop("name")({name = "Lua"}) --> "Lua"
|
|
804
|
-
-- @tparam {string} propName The property name to get
|
|
805
|
-
-- @tparam {table} object The object to get the property from
|
|
806
|
-
-- @treturn The value of the property
|
|
807
|
-
utils.prop = utils.curry(function (propName, object)
|
|
808
|
-
return object[propName]
|
|
809
|
-
end, 2)
|
|
810
|
-
|
|
811
|
-
--- Checks if an array table includes a value.
|
|
812
|
-
-- @function utils.includes
|
|
813
|
-
-- @usage utils.includes(val)(t)
|
|
814
|
-
-- @usage utils.includes(2)({1, 2, 3}) --> true
|
|
815
|
-
-- @param val The value to check for
|
|
816
|
-
-- @tparam {table<Array>} t The array table to check
|
|
817
|
-
-- @treturn {boolean} Whether the value is in the array table
|
|
818
|
-
utils.includes = utils.curry(function (val, t)
|
|
819
|
-
assert(type(t) == "table", "argument needs to be a table")
|
|
820
|
-
assert(isArray(t), "argument should be a table that is an array")
|
|
821
|
-
return utils.find(function (v) return v == val end, t) ~= nil
|
|
822
|
-
end, 2)
|
|
823
|
-
|
|
824
|
-
--- Returns the keys of a table.
|
|
825
|
-
-- @usage utils.keys(t)
|
|
826
|
-
-- @usage utils.keys({name = "Lua", age = 25}) --> {"name", "age"}
|
|
827
|
-
-- @tparam {table} t The table to get the keys from
|
|
828
|
-
-- @treturn {table<Array>} The keys of the table
|
|
829
|
-
utils.keys = function (t)
|
|
830
|
-
assert(type(t) == "table", "argument needs to be a table")
|
|
831
|
-
local keys = {}
|
|
832
|
-
for key in pairs(t) do
|
|
833
|
-
table.insert(keys, key)
|
|
834
|
-
end
|
|
835
|
-
return keys
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
--- Returns the values of a table.
|
|
839
|
-
-- @usage utils.values(t)
|
|
840
|
-
-- @usage utils.values({name = "Lua", age = 25}) --> {"Lua", 25}
|
|
841
|
-
-- @tparam {table} t The table to get the values from
|
|
842
|
-
-- @treturn {table<Array>} The values of the table
|
|
843
|
-
utils.values = function (t)
|
|
844
|
-
assert(type(t) == "table", "argument needs to be a table")
|
|
845
|
-
local values = {}
|
|
846
|
-
for _, value in pairs(t) do
|
|
847
|
-
table.insert(values, value)
|
|
848
|
-
end
|
|
849
|
-
return values
|
|
850
|
-
end
|
|
851
|
-
|
|
852
|
-
--- Convert a message's tags to a table of key-value pairs
|
|
853
|
-
-- @function Tab
|
|
854
|
-
-- @tparam {table} msg The message containing tags
|
|
855
|
-
-- @treturn {table} A table with tag names as keys and their values
|
|
856
|
-
function utils.Tab(msg)
|
|
857
|
-
local inputs = {}
|
|
858
|
-
for _, o in ipairs(msg.Tags) do
|
|
859
|
-
if not inputs[o.name] then
|
|
860
|
-
inputs[o.name] = o.value
|
|
861
|
-
end
|
|
862
|
-
end
|
|
863
|
-
return inputs
|
|
864
|
-
end
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
return utils
|
|
868
|
-
|
|
869
|
-
end
|
|
870
|
-
_G.package.loaded[".utils"] = load_utils()
|
|
871
|
-
print("loaded utils")
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
local function load_handlers_utils()
|
|
876
|
-
--- The Handler Utils module is a lightweight Lua utility library designed to provide common functionalities for handling and processing messages within the AOS computer system. It offers a set of functions to check message attributes and send replies, simplifying the development of more complex scripts and modules. This document will guide you through the module's functionalities, installation, and usage. Returns the _utils table.
|
|
877
|
-
-- @module handlers-utils
|
|
878
|
-
|
|
879
|
-
--- The _utils table
|
|
880
|
-
-- @table _utils
|
|
881
|
-
-- @field _version The version number of the _utils module
|
|
882
|
-
-- @field hasMatchingTag The hasMatchingTag function
|
|
883
|
-
-- @field hasMatchingTagOf The hasMatchingTagOf function
|
|
884
|
-
-- @field hasMatchingData The hasMatchingData function
|
|
885
|
-
-- @field reply The reply function
|
|
886
|
-
-- @field continue The continue function
|
|
887
|
-
local _utils = { _version = "0.0.2" }
|
|
888
|
-
|
|
889
|
-
local _ = require('.utils')
|
|
890
|
-
|
|
891
|
-
--- Checks if a given message has a tag that matches the specified name and value.
|
|
892
|
-
-- @function hasMatchingTag
|
|
893
|
-
-- @tparam {string} name The tag name to check
|
|
894
|
-
-- @tparam {string} value The value to match for in the tag
|
|
895
|
-
-- @treturn {function} A function that takes a message and returns whether there is a tag match (-1 if matches, 0 otherwise)
|
|
896
|
-
function _utils.hasMatchingTag(name, value)
|
|
897
|
-
assert(type(name) == 'string' and type(value) == 'string', 'invalid arguments: (name : string, value : string)')
|
|
898
|
-
|
|
899
|
-
return function (msg)
|
|
900
|
-
return msg.Tags[name] == value
|
|
901
|
-
end
|
|
902
|
-
end
|
|
903
|
-
|
|
904
|
-
--- Checks if a given message has a tag that matches the specified name and one of the specified values.
|
|
905
|
-
-- @function hasMatchingTagOf
|
|
906
|
-
-- @tparam {string} name The tag name to check
|
|
907
|
-
-- @tparam {string[]} values The list of values of which one should match
|
|
908
|
-
-- @treturn {function} A function that takes a message and returns whether there is a tag match (-1 if matches, 0 otherwise)
|
|
909
|
-
function _utils.hasMatchingTagOf(name, values)
|
|
910
|
-
assert(type(name) == 'string' and type(values) == 'table', 'invalid arguments: (name : string, values : string[])')
|
|
911
|
-
return function (msg)
|
|
912
|
-
for _, value in ipairs(values) do
|
|
913
|
-
local patternResult = Handlers.utils.hasMatchingTag(name, value)(msg)
|
|
914
|
-
|
|
915
|
-
if patternResult ~= 0 and patternResult ~= false and patternResult ~= "skip" then
|
|
916
|
-
return patternResult
|
|
917
|
-
end
|
|
918
|
-
end
|
|
919
|
-
|
|
920
|
-
return 0
|
|
921
|
-
end
|
|
922
|
-
end
|
|
923
|
-
|
|
924
|
-
--- Checks if a given message has data that matches the specified value.
|
|
925
|
-
-- @function hasMatchingData
|
|
926
|
-
-- @tparam {string} value The value to match against the message data
|
|
927
|
-
-- @treturn {function} A function that takes a message and returns whether the data matches the value (-1 if matches, 0 otherwise)
|
|
928
|
-
function _utils.hasMatchingData(value)
|
|
929
|
-
assert(type(value) == 'string', 'invalid arguments: (value : string)')
|
|
930
|
-
return function (msg)
|
|
931
|
-
return msg.Data == value
|
|
932
|
-
end
|
|
933
|
-
end
|
|
934
|
-
|
|
935
|
-
--- Given an input, returns a function that takes a message and replies to it.
|
|
936
|
-
-- @function reply
|
|
937
|
-
-- @tparam {table | string} input The content to send back. If a string, it sends it as data. If a table, it assumes a structure with `Tags`.
|
|
938
|
-
-- @treturn {function} A function that takes a message and replies to it
|
|
939
|
-
function _utils.reply(input)
|
|
940
|
-
assert(type(input) == 'table' or type(input) == 'string', 'invalid arguments: (input : table or string)')
|
|
941
|
-
return function (msg)
|
|
942
|
-
if type(input) == 'string' then
|
|
943
|
-
msg.reply({ Data = input })
|
|
944
|
-
return
|
|
945
|
-
end
|
|
946
|
-
msg.reply(input)
|
|
947
|
-
end
|
|
948
|
-
end
|
|
949
|
-
|
|
950
|
-
--- Inverts the provided pattern's result if it matches, so that it continues execution with the next matching handler.
|
|
951
|
-
-- @function continue
|
|
952
|
-
-- @tparam {table | function} pattern The pattern to check for in the message
|
|
953
|
-
-- @treturn {function} Function that executes the pattern matching function and returns `1` (continue), so that the execution of handlers continues.
|
|
954
|
-
function _utils.continue(pattern)
|
|
955
|
-
return function (msg)
|
|
956
|
-
local match = _.matchesSpec(msg, pattern)
|
|
957
|
-
|
|
958
|
-
if not match or match == 0 or match == "skip" then
|
|
959
|
-
return match
|
|
960
|
-
end
|
|
961
|
-
return 1
|
|
962
|
-
end
|
|
963
|
-
end
|
|
964
|
-
|
|
965
|
-
return _utils
|
|
966
|
-
|
|
967
|
-
end
|
|
968
|
-
_G.package.loaded[".handlers-utils"] = load_handlers_utils()
|
|
969
|
-
print("loaded handlers-utils")
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
local function load_handlers()
|
|
974
|
-
--- The Handlers library provides a flexible way to manage and execute a series of handlers based on patterns. Each handler consists of a pattern function, a handle function, and a name. This library is suitable for scenarios where different actions need to be taken based on varying input criteria. Returns the handlers table.
|
|
975
|
-
-- @module handlers
|
|
976
|
-
|
|
977
|
-
--- The handlers table
|
|
978
|
-
-- @table handlers
|
|
979
|
-
-- @field _version The version number of the handlers module
|
|
980
|
-
-- @field list The list of handlers
|
|
981
|
-
-- @field onceNonce The nonce for the once handlers
|
|
982
|
-
-- @field utils The handlers-utils module
|
|
983
|
-
-- @field generateResolver The generateResolver function
|
|
984
|
-
-- @field receive The receive function
|
|
985
|
-
-- @field once The once function
|
|
986
|
-
-- @field add The add function
|
|
987
|
-
-- @field append The append function
|
|
988
|
-
-- @field prepend The prepend function
|
|
989
|
-
-- @field remove The remove function
|
|
990
|
-
-- @field evaluate The evaluate function
|
|
991
|
-
local handlers = { _version = "0.0.5" }
|
|
992
|
-
local utils = require('.utils')
|
|
993
|
-
|
|
994
|
-
handlers.utils = require('.handlers-utils')
|
|
995
|
-
-- if update we need to keep defined handlers
|
|
996
|
-
if Handlers then
|
|
997
|
-
handlers.list = Handlers.list or {}
|
|
998
|
-
else
|
|
999
|
-
handlers.list = {}
|
|
1000
|
-
end
|
|
1001
|
-
handlers.onceNonce = 0
|
|
1002
|
-
|
|
1003
|
-
--- Given an array, a property name, and a value, returns the index of the object in the array that has the property with the value.
|
|
1004
|
-
-- @lfunction findIndexByProp
|
|
1005
|
-
-- @tparam {table[]} array The array to search through
|
|
1006
|
-
-- @tparam {string} prop The property name to check
|
|
1007
|
-
-- @tparam {any} value The value to check for in the property
|
|
1008
|
-
-- @treturn {number | nil} The index of the object in the array that has the property with the value, or nil if no such object is found
|
|
1009
|
-
local function findIndexByProp(array, prop, value)
|
|
1010
|
-
for index, object in ipairs(array) do
|
|
1011
|
-
if object[prop] == value then
|
|
1012
|
-
return index
|
|
1013
|
-
end
|
|
1014
|
-
end
|
|
1015
|
-
return nil
|
|
1016
|
-
end
|
|
1017
|
-
|
|
1018
|
-
--- Given a name, a pattern, and a handle, asserts that the arguments are valid.
|
|
1019
|
-
-- @lfunction assertAddArgs
|
|
1020
|
-
-- @tparam {string} name The name of the handler
|
|
1021
|
-
-- @tparam {table | function | string} pattern The pattern to check for in the message
|
|
1022
|
-
-- @tparam {function} handle The function to call if the pattern matches
|
|
1023
|
-
-- @tparam {number | string | nil} maxRuns The maximum number of times the handler should run, or nil if there is no limit
|
|
1024
|
-
local function assertAddArgs(name, pattern, handle, maxRuns)
|
|
1025
|
-
assert(
|
|
1026
|
-
type(name) == 'string' and
|
|
1027
|
-
(type(pattern) == 'function' or type(pattern) == 'table' or type(pattern) == 'string'),
|
|
1028
|
-
'Invalid arguments given. Expected: \n' ..
|
|
1029
|
-
'\tname : string, ' ..
|
|
1030
|
-
'\tpattern : action : string | MsgMatch : table,\n' ..
|
|
1031
|
-
'\t\tfunction(msg: Message) : {-1 = break, 0 = skip, 1 = continue},\n' ..
|
|
1032
|
-
'\thandle(msg : Message) : void) | Resolver,\n' ..
|
|
1033
|
-
'\tMaxRuns? : number | "inf" | nil')
|
|
1034
|
-
end
|
|
1035
|
-
|
|
1036
|
-
--- Given a resolver specification, returns a resolver function.
|
|
1037
|
-
-- @function generateResolver
|
|
1038
|
-
-- @tparam {table | function} resolveSpec The resolver specification
|
|
1039
|
-
-- @treturn {function} A resolver function
|
|
1040
|
-
function handlers.generateResolver(resolveSpec)
|
|
1041
|
-
return function(msg)
|
|
1042
|
-
-- If the resolver is a single function, call it.
|
|
1043
|
-
-- Else, find the first matching pattern (by its matchSpec), and exec.
|
|
1044
|
-
if type(resolveSpec) == "function" then
|
|
1045
|
-
return resolveSpec(msg)
|
|
1046
|
-
else
|
|
1047
|
-
for matchSpec, func in pairs(resolveSpec) do
|
|
1048
|
-
if utils.matchesSpec(msg, matchSpec) then
|
|
1049
|
-
return func(msg)
|
|
1050
|
-
end
|
|
1051
|
-
end
|
|
1052
|
-
end
|
|
1053
|
-
end
|
|
1054
|
-
end
|
|
1055
|
-
|
|
1056
|
-
--- Given a pattern, returns the next message that matches the pattern.
|
|
1057
|
-
-- This function uses Lua's coroutines under-the-hood to add a handler, pause,
|
|
1058
|
-
-- and then resume the current coroutine. This allows us to effectively block
|
|
1059
|
-
-- processing of one message until another is received that matches the pattern.
|
|
1060
|
-
-- @function receive
|
|
1061
|
-
-- @tparam {table | function} pattern The pattern to check for in the message
|
|
1062
|
-
function handlers.receive(pattern)
|
|
1063
|
-
return 'not implemented'
|
|
1064
|
-
end
|
|
1065
|
-
|
|
1066
|
-
--- Given a name, a pattern, and a handle, adds a handler to the list.
|
|
1067
|
-
-- If name is not provided, "_once_" prefix plus onceNonce will be used as the name.
|
|
1068
|
-
-- Adds handler with maxRuns of 1 such that it will only be called once then removed from the list.
|
|
1069
|
-
-- @function once
|
|
1070
|
-
-- @tparam {string} name The name of the handler
|
|
1071
|
-
-- @tparam {table | function | string} pattern The pattern to check for in the message
|
|
1072
|
-
-- @tparam {function} handle The function to call if the pattern matches
|
|
1073
|
-
function handlers.once(...)
|
|
1074
|
-
local name, pattern, handle
|
|
1075
|
-
if select("#", ...) == 3 then
|
|
1076
|
-
name = select(1, ...)
|
|
1077
|
-
pattern = select(2, ...)
|
|
1078
|
-
handle = select(3, ...)
|
|
1079
|
-
else
|
|
1080
|
-
name = "_once_" .. tostring(handlers.onceNonce)
|
|
1081
|
-
handlers.onceNonce = handlers.onceNonce + 1
|
|
1082
|
-
pattern = select(1, ...)
|
|
1083
|
-
handle = select(2, ...)
|
|
1084
|
-
end
|
|
1085
|
-
handlers.prepend(name, pattern, handle, 1)
|
|
1086
|
-
end
|
|
1087
|
-
|
|
1088
|
-
--- Given a name, a pattern, and a handle, adds a handler to the list.
|
|
1089
|
-
-- @function add
|
|
1090
|
-
-- @tparam {string} name The name of the handler
|
|
1091
|
-
-- @tparam {table | function | string} pattern The pattern to check for in the message
|
|
1092
|
-
-- @tparam {function} handle The function to call if the pattern matches
|
|
1093
|
-
-- @tparam {number | string | nil} maxRuns The maximum number of times the handler should run, or nil if there is no limit
|
|
1094
|
-
function handlers.add(...)
|
|
1095
|
-
local name, pattern, handle, maxRuns
|
|
1096
|
-
local args = select("#", ...)
|
|
1097
|
-
if args == 2 then
|
|
1098
|
-
name = select(1, ...)
|
|
1099
|
-
pattern = select(1, ...)
|
|
1100
|
-
handle = select(2, ...)
|
|
1101
|
-
maxRuns = nil
|
|
1102
|
-
elseif args == 3 then
|
|
1103
|
-
name = select(1, ...)
|
|
1104
|
-
pattern = select(2, ...)
|
|
1105
|
-
handle = select(3, ...)
|
|
1106
|
-
maxRuns = nil
|
|
1107
|
-
else
|
|
1108
|
-
name = select(1, ...)
|
|
1109
|
-
pattern = select(2, ...)
|
|
1110
|
-
handle = select(3, ...)
|
|
1111
|
-
maxRuns = select(4, ...)
|
|
1112
|
-
end
|
|
1113
|
-
assertAddArgs(name, pattern, handle, maxRuns)
|
|
1114
|
-
|
|
1115
|
-
handle = handlers.generateResolver(handle)
|
|
1116
|
-
|
|
1117
|
-
-- update existing handler by name
|
|
1118
|
-
local idx = findIndexByProp(handlers.list, "name", name)
|
|
1119
|
-
if idx ~= nil and idx > 0 then
|
|
1120
|
-
-- found update
|
|
1121
|
-
handlers.list[idx].pattern = pattern
|
|
1122
|
-
handlers.list[idx].handle = handle
|
|
1123
|
-
handlers.list[idx].maxRuns = maxRuns
|
|
1124
|
-
else
|
|
1125
|
-
-- not found then add
|
|
1126
|
-
table.insert(handlers.list, { pattern = pattern, handle = handle, name = name, maxRuns = maxRuns })
|
|
1127
|
-
|
|
1128
|
-
end
|
|
1129
|
-
return #handlers.list
|
|
1130
|
-
end
|
|
1131
|
-
|
|
1132
|
-
--- Appends a new handler to the end of the handlers list.
|
|
1133
|
-
-- @function append
|
|
1134
|
-
-- @tparam {string} name The name of the handler
|
|
1135
|
-
-- @tparam {table | function | string} pattern The pattern to check for in the message
|
|
1136
|
-
-- @tparam {function} handle The function to call if the pattern matches
|
|
1137
|
-
-- @tparam {number | string | nil} maxRuns The maximum number of times the handler should run, or nil if there is no limit
|
|
1138
|
-
function handlers.append(...)
|
|
1139
|
-
local name, pattern, handle, maxRuns
|
|
1140
|
-
local args = select("#", ...)
|
|
1141
|
-
if args == 2 then
|
|
1142
|
-
name = select(1, ...)
|
|
1143
|
-
pattern = select(1, ...)
|
|
1144
|
-
handle = select(2, ...)
|
|
1145
|
-
maxRuns = nil
|
|
1146
|
-
elseif args == 3 then
|
|
1147
|
-
name = select(1, ...)
|
|
1148
|
-
pattern = select(2, ...)
|
|
1149
|
-
handle = select(3, ...)
|
|
1150
|
-
maxRuns = nil
|
|
1151
|
-
else
|
|
1152
|
-
name = select(1, ...)
|
|
1153
|
-
pattern = select(2, ...)
|
|
1154
|
-
handle = select(3, ...)
|
|
1155
|
-
maxRuns = select(4, ...)
|
|
1156
|
-
end
|
|
1157
|
-
assertAddArgs(name, pattern, handle, maxRuns)
|
|
1158
|
-
|
|
1159
|
-
handle = handlers.generateResolver(handle)
|
|
1160
|
-
-- update existing handler by name
|
|
1161
|
-
local idx = findIndexByProp(handlers.list, "name", name)
|
|
1162
|
-
if idx ~= nil and idx > 0 then
|
|
1163
|
-
-- found update
|
|
1164
|
-
handlers.list[idx].pattern = pattern
|
|
1165
|
-
handlers.list[idx].handle = handle
|
|
1166
|
-
handlers.list[idx].maxRuns = maxRuns
|
|
1167
|
-
else
|
|
1168
|
-
table.insert(handlers.list, { pattern = pattern, handle = handle, name = name, maxRuns = maxRuns })
|
|
1169
|
-
end
|
|
1170
|
-
end
|
|
1171
|
-
|
|
1172
|
-
--- Prepends a new handler to the beginning of the handlers list.
|
|
1173
|
-
-- @function prepend
|
|
1174
|
-
-- @tparam {string} name The name of the handler
|
|
1175
|
-
-- @tparam {table | function | string} pattern The pattern to check for in the message
|
|
1176
|
-
-- @tparam {function} handle The function to call if the pattern matches
|
|
1177
|
-
-- @tparam {number | string | nil} maxRuns The maximum number of times the handler should run, or nil if there is no limit
|
|
1178
|
-
function handlers.prepend(...)
|
|
1179
|
-
local name, pattern, handle, maxRuns
|
|
1180
|
-
local args = select("#", ...)
|
|
1181
|
-
if args == 2 then
|
|
1182
|
-
name = select(1, ...)
|
|
1183
|
-
pattern = select(1, ...)
|
|
1184
|
-
handle = select(2, ...)
|
|
1185
|
-
maxRuns = nil
|
|
1186
|
-
elseif args == 3 then
|
|
1187
|
-
name = select(1, ...)
|
|
1188
|
-
pattern = select(2, ...)
|
|
1189
|
-
handle = select(3, ...)
|
|
1190
|
-
maxRuns = nil
|
|
1191
|
-
else
|
|
1192
|
-
name = select(1, ...)
|
|
1193
|
-
pattern = select(2, ...)
|
|
1194
|
-
handle = select(3, ...)
|
|
1195
|
-
maxRuns = select(4, ...)
|
|
1196
|
-
end
|
|
1197
|
-
assertAddArgs(name, pattern, handle, maxRuns)
|
|
1198
|
-
|
|
1199
|
-
handle = handlers.generateResolver(handle)
|
|
1200
|
-
|
|
1201
|
-
-- update existing handler by name
|
|
1202
|
-
local idx = findIndexByProp(handlers.list, "name", name)
|
|
1203
|
-
if idx ~= nil and idx > 0 then
|
|
1204
|
-
-- found update
|
|
1205
|
-
handlers.list[idx].pattern = pattern
|
|
1206
|
-
handlers.list[idx].handle = handle
|
|
1207
|
-
handlers.list[idx].maxRuns = maxRuns
|
|
1208
|
-
else
|
|
1209
|
-
table.insert(handlers.list, 1, { pattern = pattern, handle = handle, name = name, maxRuns = maxRuns })
|
|
1210
|
-
end
|
|
1211
|
-
end
|
|
1212
|
-
|
|
1213
|
-
--- Returns an object that allows adding a new handler before a specified handler.
|
|
1214
|
-
-- @function before
|
|
1215
|
-
-- @tparam {string} handleName The name of the handler before which the new handler will be added
|
|
1216
|
-
-- @treturn {table} An object with an `add` method to insert the new handler
|
|
1217
|
-
function handlers.before(handleName)
|
|
1218
|
-
assert(type(handleName) == 'string', 'Handler name MUST be a string')
|
|
1219
|
-
|
|
1220
|
-
local idx = findIndexByProp(handlers.list, "name", handleName)
|
|
1221
|
-
return {
|
|
1222
|
-
add = function (name, pattern, handle, maxRuns)
|
|
1223
|
-
assertAddArgs(name, pattern, handle, maxRuns)
|
|
1224
|
-
handle = handlers.generateResolver(handle)
|
|
1225
|
-
if idx then
|
|
1226
|
-
table.insert(handlers.list, idx, { pattern = pattern, handle = handle, name = name, maxRuns = maxRuns })
|
|
1227
|
-
end
|
|
1228
|
-
end
|
|
1229
|
-
}
|
|
1230
|
-
end
|
|
1231
|
-
|
|
1232
|
-
--- Returns an object that allows adding a new handler after a specified handler.
|
|
1233
|
-
-- @function after
|
|
1234
|
-
-- @tparam {string} handleName The name of the handler after which the new handler will be added
|
|
1235
|
-
-- @treturn {table} An object with an `add` method to insert the new handler
|
|
1236
|
-
function handlers.after(handleName)
|
|
1237
|
-
assert(type(handleName) == 'string', 'Handler name MUST be a string')
|
|
1238
|
-
local idx = findIndexByProp(handlers.list, "name", handleName)
|
|
1239
|
-
return {
|
|
1240
|
-
add = function (name, pattern, handle, maxRuns)
|
|
1241
|
-
assertAddArgs(name, pattern, handle, maxRuns)
|
|
1242
|
-
handle = handlers.generateResolver(handle)
|
|
1243
|
-
if idx then
|
|
1244
|
-
table.insert(handlers.list, idx + 1, { pattern = pattern, handle = handle, name = name, maxRuns = maxRuns })
|
|
1245
|
-
end
|
|
1246
|
-
end
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
end
|
|
1250
|
-
|
|
1251
|
-
--- Removes a handler from the handlers list by name.
|
|
1252
|
-
-- @function remove
|
|
1253
|
-
-- @tparam {string} name The name of the handler to be removed
|
|
1254
|
-
function handlers.remove(name)
|
|
1255
|
-
assert(type(name) == 'string', 'name MUST be string')
|
|
1256
|
-
if #handlers.list == 1 and handlers.list[1].name == name then
|
|
1257
|
-
handlers.list = {}
|
|
1258
|
-
end
|
|
1259
|
-
|
|
1260
|
-
local idx = findIndexByProp(handlers.list, "name", name)
|
|
1261
|
-
if idx ~= nil and idx > 0 then
|
|
1262
|
-
table.remove(handlers.list, idx)
|
|
1263
|
-
end
|
|
1264
|
-
end
|
|
1265
|
-
|
|
1266
|
-
--- Evaluates each handler against a given message and environment. Handlers are called in the order they appear in the handlers list.
|
|
1267
|
-
-- Return 0 to not call handler, -1 to break after handler is called, 1 to continue
|
|
1268
|
-
-- @function evaluate
|
|
1269
|
-
-- @tparam {table} msg The message to be processed by the handlers.
|
|
1270
|
-
-- @tparam {table} env The environment in which the handlers are executed.
|
|
1271
|
-
-- @treturn The response from the handler(s). Returns a default message if no handler matches.
|
|
1272
|
-
function handlers.evaluate(msg, env)
|
|
1273
|
-
local handled = false
|
|
1274
|
-
assert(type(msg) == 'table', 'msg is not valid')
|
|
1275
|
-
assert(type(env) == 'table', 'env is not valid')
|
|
1276
|
-
for _, o in ipairs(handlers.list) do
|
|
1277
|
-
if o.name ~= "_default" then
|
|
1278
|
-
local match = utils.matchesSpec(msg, o.pattern)
|
|
1279
|
-
if not (type(match) == 'number' or type(match) == 'string' or type(match) == 'boolean') then
|
|
1280
|
-
error("Pattern result is not valid, it MUST be string, number, or boolean")
|
|
1281
|
-
end
|
|
1282
|
-
-- handle boolean returns
|
|
1283
|
-
if type(match) == "boolean" and match == true then
|
|
1284
|
-
match = -1
|
|
1285
|
-
elseif type(match) == "boolean" and match == false then
|
|
1286
|
-
match = 0
|
|
1287
|
-
end
|
|
1288
|
-
|
|
1289
|
-
-- handle string returns
|
|
1290
|
-
if type(match) == "string" then
|
|
1291
|
-
if match == "continue" then
|
|
1292
|
-
match = 1
|
|
1293
|
-
elseif match == "break" then
|
|
1294
|
-
match = -1
|
|
1295
|
-
else
|
|
1296
|
-
match = 0
|
|
1297
|
-
end
|
|
1298
|
-
end
|
|
1299
|
-
|
|
1300
|
-
if match ~= 0 then
|
|
1301
|
-
if match < 0 then
|
|
1302
|
-
handled = true
|
|
1303
|
-
end
|
|
1304
|
-
-- each handle function can accept, the msg, env
|
|
1305
|
-
local status, err = pcall(o.handle, msg, env)
|
|
1306
|
-
if not status then
|
|
1307
|
-
error(err)
|
|
1308
|
-
end
|
|
1309
|
-
-- remove handler if maxRuns is reached. maxRuns can be either a number or "inf"
|
|
1310
|
-
if o.maxRuns ~= nil and o.maxRuns ~= "inf" then
|
|
1311
|
-
o.maxRuns = o.maxRuns - 1
|
|
1312
|
-
if o.maxRuns == 0 then
|
|
1313
|
-
handlers.remove(o.name)
|
|
1314
|
-
end
|
|
1315
|
-
end
|
|
1316
|
-
end
|
|
1317
|
-
if match < 0 then
|
|
1318
|
-
return handled
|
|
1319
|
-
end
|
|
1320
|
-
end
|
|
1321
|
-
end
|
|
1322
|
-
-- do default
|
|
1323
|
-
if not handled then
|
|
1324
|
-
local idx = findIndexByProp(handlers.list, "name", "_default")
|
|
1325
|
-
handlers.list[idx].handle(msg,env)
|
|
1326
|
-
end
|
|
1327
|
-
end
|
|
1328
|
-
|
|
1329
|
-
return handlers
|
|
1330
|
-
|
|
1331
|
-
end
|
|
1332
|
-
_G.package.loaded[".handlers"] = load_handlers()
|
|
1333
|
-
print("loaded handlers")
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
local function load_dump()
|
|
1338
|
-
--
|
|
1339
|
-
-- Copyright (C) 2018 Masatoshi Teruya
|
|
1340
|
-
--
|
|
1341
|
-
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1342
|
-
-- of this software and associated documentation files (the "Software"), to deal
|
|
1343
|
-
-- in the Software without restriction, including without limitation the rights
|
|
1344
|
-
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1345
|
-
-- copies of the Software, and to permit persons to whom the Software is
|
|
1346
|
-
-- furnished to do so, subject to the following conditions:
|
|
1347
|
-
--
|
|
1348
|
-
-- The above copyright notice and this permission notice shall be included in
|
|
1349
|
-
-- all copies or substantial portions of the Software.
|
|
1350
|
-
--
|
|
1351
|
-
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1352
|
-
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1353
|
-
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1354
|
-
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1355
|
-
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1356
|
-
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1357
|
-
-- THE SOFTWARE.
|
|
1358
|
-
--
|
|
1359
|
-
-- dump.lua
|
|
1360
|
-
-- lua-dump
|
|
1361
|
-
-- Created by Masatoshi Teruya on 18/04/22.
|
|
1362
|
-
--
|
|
1363
|
-
--- file-scope variables
|
|
1364
|
-
local type = type
|
|
1365
|
-
local floor = math.floor
|
|
1366
|
-
local tostring = tostring
|
|
1367
|
-
local tblsort = table.sort
|
|
1368
|
-
local tblconcat = table.concat
|
|
1369
|
-
local strmatch = string.match
|
|
1370
|
-
local strformat = string.format
|
|
1371
|
-
--- constants
|
|
1372
|
-
local INFINITE_POS = math.huge
|
|
1373
|
-
local LUA_FIELDNAME_PAT = '^[a-zA-Z_][a-zA-Z0-9_]*$'
|
|
1374
|
-
local FOR_KEY = 'key'
|
|
1375
|
-
local FOR_VAL = 'val'
|
|
1376
|
-
local FOR_CIRCULAR = 'circular'
|
|
1377
|
-
local RESERVED_WORD = {
|
|
1378
|
-
-- primitive data
|
|
1379
|
-
['nil'] = true,
|
|
1380
|
-
['true'] = true,
|
|
1381
|
-
['false'] = true,
|
|
1382
|
-
-- declaraton
|
|
1383
|
-
['local'] = true,
|
|
1384
|
-
['function'] = true,
|
|
1385
|
-
-- boolean logic
|
|
1386
|
-
['and'] = true,
|
|
1387
|
-
['or'] = true,
|
|
1388
|
-
['not'] = true,
|
|
1389
|
-
-- conditional statement
|
|
1390
|
-
['if'] = true,
|
|
1391
|
-
['elseif'] = true,
|
|
1392
|
-
['else'] = true,
|
|
1393
|
-
-- iteration statement
|
|
1394
|
-
['for'] = true,
|
|
1395
|
-
['in'] = true,
|
|
1396
|
-
['while'] = true,
|
|
1397
|
-
['until'] = true,
|
|
1398
|
-
['repeat'] = true,
|
|
1399
|
-
-- jump statement
|
|
1400
|
-
['break'] = true,
|
|
1401
|
-
['goto'] = true,
|
|
1402
|
-
['return'] = true,
|
|
1403
|
-
-- block scope statement
|
|
1404
|
-
['then'] = true,
|
|
1405
|
-
['do'] = true,
|
|
1406
|
-
['end'] = true,
|
|
1407
|
-
}
|
|
1408
|
-
local DEFAULT_INDENT = 4
|
|
1409
|
-
|
|
1410
|
-
--- filter function for dump
|
|
1411
|
-
--- @param val any
|
|
1412
|
-
--- @param depth integer
|
|
1413
|
-
--- @param vtype string
|
|
1414
|
-
--- @param use string
|
|
1415
|
-
--- @param key any
|
|
1416
|
-
--- @param udata any
|
|
1417
|
-
--- @return any val
|
|
1418
|
-
--- @return boolean nodump
|
|
1419
|
-
local function DEFAULT_FILTER(val)
|
|
1420
|
-
return val
|
|
1421
|
-
end
|
|
1422
|
-
|
|
1423
|
-
--- sort_index
|
|
1424
|
-
--- @param a table
|
|
1425
|
-
--- @param b table
|
|
1426
|
-
local function sort_index(a, b)
|
|
1427
|
-
if a.typ == b.typ then
|
|
1428
|
-
if a.typ == 'boolean' then
|
|
1429
|
-
return b.key
|
|
1430
|
-
end
|
|
1431
|
-
|
|
1432
|
-
return a.key < b.key
|
|
1433
|
-
end
|
|
1434
|
-
|
|
1435
|
-
return a.typ == 'number'
|
|
1436
|
-
end
|
|
1437
|
-
|
|
1438
|
-
--- dumptbl
|
|
1439
|
-
--- @param tbl table
|
|
1440
|
-
--- @param depth integer
|
|
1441
|
-
--- @param indent string
|
|
1442
|
-
--- @param nestIndent string
|
|
1443
|
-
--- @param ctx table
|
|
1444
|
-
--- @return string
|
|
1445
|
-
local function dumptbl(tbl, depth, indent, nestIndent, ctx)
|
|
1446
|
-
local ref = tostring(tbl)
|
|
1447
|
-
|
|
1448
|
-
-- circular reference
|
|
1449
|
-
if ctx.circular[ref] then
|
|
1450
|
-
local val, nodump = ctx.filter(tbl, depth, type(tbl), FOR_CIRCULAR, tbl,
|
|
1451
|
-
ctx.udata)
|
|
1452
|
-
|
|
1453
|
-
if val ~= nil and val ~= tbl then
|
|
1454
|
-
local t = type(val)
|
|
1455
|
-
|
|
1456
|
-
if t == 'table' then
|
|
1457
|
-
-- dump table value
|
|
1458
|
-
if not nodump then
|
|
1459
|
-
return dumptbl(val, depth + 1, indent, nestIndent, ctx)
|
|
1460
|
-
end
|
|
1461
|
-
return tostring(val)
|
|
1462
|
-
elseif t == 'string' then
|
|
1463
|
-
return strformat('%q', val)
|
|
1464
|
-
elseif t == 'number' or t == 'boolean' then
|
|
1465
|
-
return tostring(val)
|
|
1466
|
-
end
|
|
1467
|
-
|
|
1468
|
-
return strformat('%q', tostring(val))
|
|
1469
|
-
end
|
|
1470
|
-
|
|
1471
|
-
return '"<Circular ' .. ref .. '>"'
|
|
1472
|
-
end
|
|
1473
|
-
|
|
1474
|
-
local res = {}
|
|
1475
|
-
local arr = {}
|
|
1476
|
-
local narr = 0
|
|
1477
|
-
local fieldIndent = indent .. nestIndent
|
|
1478
|
-
|
|
1479
|
-
-- save reference
|
|
1480
|
-
ctx.circular[ref] = true
|
|
1481
|
-
|
|
1482
|
-
for k, v in pairs(tbl) do
|
|
1483
|
-
-- check key
|
|
1484
|
-
local key, nokdump = ctx.filter(k, depth, type(k), FOR_KEY, nil,
|
|
1485
|
-
ctx.udata)
|
|
1486
|
-
|
|
1487
|
-
if key ~= nil then
|
|
1488
|
-
-- check val
|
|
1489
|
-
local val, novdump = ctx.filter(v, depth, type(v), FOR_VAL, key,
|
|
1490
|
-
ctx.udata)
|
|
1491
|
-
local kv
|
|
1492
|
-
|
|
1493
|
-
if val ~= nil then
|
|
1494
|
-
local kt = type(key)
|
|
1495
|
-
local vt = type(val)
|
|
1496
|
-
|
|
1497
|
-
-- convert key to suitable to be safely read back
|
|
1498
|
-
-- by the Lua interpreter
|
|
1499
|
-
if kt == 'number' or kt == 'boolean' then
|
|
1500
|
-
k = key
|
|
1501
|
-
key = '[' .. tostring(key) .. ']'
|
|
1502
|
-
-- dump table value
|
|
1503
|
-
elseif kt == 'table' and not nokdump then
|
|
1504
|
-
key = '[' ..
|
|
1505
|
-
dumptbl(key, depth + 1, fieldIndent, nestIndent,
|
|
1506
|
-
ctx) .. ']'
|
|
1507
|
-
k = key
|
|
1508
|
-
kt = 'string'
|
|
1509
|
-
elseif kt ~= 'string' or RESERVED_WORD[key] or
|
|
1510
|
-
not strmatch(key, LUA_FIELDNAME_PAT) then
|
|
1511
|
-
key = strformat("[%q]", tostring(key), v)
|
|
1512
|
-
k = key
|
|
1513
|
-
kt = 'string'
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
-- convert key-val pair to suitable to be safely read back
|
|
1517
|
-
-- by the Lua interpreter
|
|
1518
|
-
if vt == 'number' or vt == 'boolean' then
|
|
1519
|
-
kv = strformat('%s%s = %s', fieldIndent, key, tostring(val))
|
|
1520
|
-
elseif vt == 'string' then
|
|
1521
|
-
-- dump a string-value
|
|
1522
|
-
if not novdump then
|
|
1523
|
-
kv = strformat('%s%s = %q', fieldIndent, key, val)
|
|
1524
|
-
else
|
|
1525
|
-
kv = strformat('%s%s = %s', fieldIndent, key, val)
|
|
1526
|
-
end
|
|
1527
|
-
elseif vt == 'table' and not novdump then
|
|
1528
|
-
kv = strformat('%s%s = %s', fieldIndent, key, dumptbl(val,
|
|
1529
|
-
depth +
|
|
1530
|
-
1,
|
|
1531
|
-
fieldIndent,
|
|
1532
|
-
nestIndent,
|
|
1533
|
-
ctx))
|
|
1534
|
-
else
|
|
1535
|
-
kv = strformat('%s%s = %q', fieldIndent, key, tostring(val))
|
|
1536
|
-
end
|
|
1537
|
-
|
|
1538
|
-
-- add to array
|
|
1539
|
-
narr = narr + 1
|
|
1540
|
-
arr[narr] = {
|
|
1541
|
-
typ = kt,
|
|
1542
|
-
key = k,
|
|
1543
|
-
val = kv,
|
|
1544
|
-
}
|
|
1545
|
-
end
|
|
1546
|
-
end
|
|
1547
|
-
end
|
|
1548
|
-
|
|
1549
|
-
-- remove reference
|
|
1550
|
-
ctx.circular[ref] = nil
|
|
1551
|
-
-- concat result
|
|
1552
|
-
if narr > 0 then
|
|
1553
|
-
tblsort(arr, sort_index)
|
|
1554
|
-
|
|
1555
|
-
for i = 1, narr do
|
|
1556
|
-
res[i] = arr[i].val
|
|
1557
|
-
end
|
|
1558
|
-
res[1] = '{' .. ctx.LF .. res[1]
|
|
1559
|
-
res = tblconcat(res, ',' .. ctx.LF) .. ctx.LF .. indent .. '}'
|
|
1560
|
-
else
|
|
1561
|
-
res = '{}'
|
|
1562
|
-
end
|
|
1563
|
-
|
|
1564
|
-
return res
|
|
1565
|
-
end
|
|
1566
|
-
|
|
1567
|
-
--- is_uint
|
|
1568
|
-
--- @param v any
|
|
1569
|
-
--- @return boolean ok
|
|
1570
|
-
local function is_uint(v)
|
|
1571
|
-
return type(v) == 'number' and v < INFINITE_POS and v >= 0 and floor(v) == v
|
|
1572
|
-
end
|
|
1573
|
-
|
|
1574
|
-
--- dump
|
|
1575
|
-
--- @param val any
|
|
1576
|
-
--- @param indent integer
|
|
1577
|
-
--- @param padding integer
|
|
1578
|
-
--- @param filter function
|
|
1579
|
-
--- @param udata
|
|
1580
|
-
--- @return string
|
|
1581
|
-
local function dump(val, indent, padding, filter, udata)
|
|
1582
|
-
local t = type(val)
|
|
1583
|
-
|
|
1584
|
-
-- check indent
|
|
1585
|
-
if indent == nil then
|
|
1586
|
-
indent = DEFAULT_INDENT
|
|
1587
|
-
elseif not is_uint(indent) then
|
|
1588
|
-
error('indent must be unsigned integer', 2)
|
|
1589
|
-
end
|
|
1590
|
-
|
|
1591
|
-
-- check padding
|
|
1592
|
-
if padding == nil then
|
|
1593
|
-
padding = 0
|
|
1594
|
-
elseif not is_uint(padding) then
|
|
1595
|
-
error('padding must be unsigned integer', 2)
|
|
1596
|
-
end
|
|
1597
|
-
|
|
1598
|
-
-- check filter
|
|
1599
|
-
if filter == nil then
|
|
1600
|
-
filter = DEFAULT_FILTER
|
|
1601
|
-
elseif type(filter) ~= 'function' then
|
|
1602
|
-
error('filter must be function', 2)
|
|
1603
|
-
end
|
|
1604
|
-
|
|
1605
|
-
-- dump table
|
|
1606
|
-
if t == 'table' then
|
|
1607
|
-
local ispace = ''
|
|
1608
|
-
local pspace = ''
|
|
1609
|
-
|
|
1610
|
-
if indent > 0 then
|
|
1611
|
-
ispace = strformat('%' .. tostring(indent) .. 's', '')
|
|
1612
|
-
end
|
|
1613
|
-
|
|
1614
|
-
if padding > 0 then
|
|
1615
|
-
pspace = strformat('%' .. tostring(padding) .. 's', '')
|
|
1616
|
-
end
|
|
1617
|
-
|
|
1618
|
-
return dumptbl(val, 1, pspace, ispace, {
|
|
1619
|
-
LF = ispace == '' and ' ' or '\n',
|
|
1620
|
-
circular = {},
|
|
1621
|
-
filter = filter,
|
|
1622
|
-
udata = udata,
|
|
1623
|
-
})
|
|
1624
|
-
end
|
|
1625
|
-
|
|
1626
|
-
-- dump value
|
|
1627
|
-
local v, nodump = filter(val, 0, t, FOR_VAL, nil, udata)
|
|
1628
|
-
if nodump == true then
|
|
1629
|
-
return tostring(v)
|
|
1630
|
-
end
|
|
1631
|
-
return strformat('%q', tostring(v))
|
|
1632
|
-
end
|
|
1633
|
-
|
|
1634
|
-
return dump
|
|
1635
|
-
end
|
|
1636
|
-
_G.package.loaded[".dump"] = load_dump()
|
|
1637
|
-
print("loaded dump")
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
local function load_pretty()
|
|
1642
|
-
local pretty = { _version = "0.0.1" }
|
|
1643
|
-
|
|
1644
|
-
pretty.tprint = function (tbl, indent)
|
|
1645
|
-
if not indent then indent = 0 end
|
|
1646
|
-
local output = ""
|
|
1647
|
-
for k, v in pairs(tbl) do
|
|
1648
|
-
local formatting = string.rep(" ", indent) .. k .. ": "
|
|
1649
|
-
if type(v) == "table" then
|
|
1650
|
-
output = output .. formatting .. "\n"
|
|
1651
|
-
output = output .. pretty.tprint(v, indent+1)
|
|
1652
|
-
elseif type(v) == 'boolean' then
|
|
1653
|
-
output = output .. formatting .. tostring(v) .. "\n"
|
|
1654
|
-
else
|
|
1655
|
-
output = output .. formatting .. v .. "\n"
|
|
1656
|
-
end
|
|
1657
|
-
end
|
|
1658
|
-
return output
|
|
1659
|
-
end
|
|
1660
|
-
|
|
1661
|
-
return pretty
|
|
1662
|
-
|
|
1663
|
-
end
|
|
1664
|
-
_G.package.loaded[".pretty"] = load_pretty()
|
|
1665
|
-
print("loaded pretty")
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
local function load_chance()
|
|
1670
|
-
--- The Chance module provides utilities for generating random numbers and values. Returns the chance table.
|
|
1671
|
-
-- @module chance
|
|
1672
|
-
|
|
1673
|
-
local N = 624
|
|
1674
|
-
local M = 397
|
|
1675
|
-
local MATRIX_A = 0x9908b0df
|
|
1676
|
-
local UPPER_MASK = 0x80000000
|
|
1677
|
-
local LOWER_MASK = 0x7fffffff
|
|
1678
|
-
|
|
1679
|
-
--- Initializes mt[N] with a seed
|
|
1680
|
-
-- @lfunction init_genrand
|
|
1681
|
-
-- @tparam {table} o The table to initialize
|
|
1682
|
-
-- @tparam {number} s The seed
|
|
1683
|
-
local function init_genrand(o, s)
|
|
1684
|
-
o.mt[0] = s & 0xffffffff
|
|
1685
|
-
for i = 1, N - 1 do
|
|
1686
|
-
o.mt[i] = (1812433253 * (o.mt[i - 1] ~ (o.mt[i - 1] >> 30))) + i
|
|
1687
|
-
-- See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
|
|
1688
|
-
-- In the previous versions, MSBs of the seed affect
|
|
1689
|
-
-- only MSBs of the array mt[].
|
|
1690
|
-
-- 2002/01/09 modified by Makoto Matsumoto
|
|
1691
|
-
o.mt[i] = o.mt[i] & 0xffffffff
|
|
1692
|
-
-- for >32 bit machines
|
|
1693
|
-
end
|
|
1694
|
-
o.mti = N
|
|
1695
|
-
end
|
|
1696
|
-
|
|
1697
|
-
--- Generates a random number on [0,0xffffffff]-interval
|
|
1698
|
-
-- @lfunction genrand_int32
|
|
1699
|
-
-- @tparam {table} o The table to generate the random number from
|
|
1700
|
-
-- @treturn {number} The random number
|
|
1701
|
-
local function genrand_int32(o)
|
|
1702
|
-
local y
|
|
1703
|
-
local mag01 = {} -- mag01[x] = x * MATRIX_A for x=0,1
|
|
1704
|
-
mag01[0] = 0x0
|
|
1705
|
-
mag01[1] = MATRIX_A
|
|
1706
|
-
if o.mti >= N then -- generate N words at one time
|
|
1707
|
-
if o.mti == N + 1 then -- if init_genrand() has not been called,
|
|
1708
|
-
init_genrand(o, 5489) -- a default initial seed is used
|
|
1709
|
-
end
|
|
1710
|
-
for kk = 0, N - M - 1 do
|
|
1711
|
-
y = (o.mt[kk] & UPPER_MASK) | (o.mt[kk + 1] & LOWER_MASK)
|
|
1712
|
-
o.mt[kk] = o.mt[kk + M] ~ (y >> 1) ~ mag01[y & 0x1]
|
|
1713
|
-
end
|
|
1714
|
-
for kk = N - M, N - 2 do
|
|
1715
|
-
y = (o.mt[kk] & UPPER_MASK) | (o.mt[kk + 1] & LOWER_MASK)
|
|
1716
|
-
o.mt[kk] = o.mt[kk + (M - N)] ~ (y >> 1) ~ mag01[y & 0x1]
|
|
1717
|
-
end
|
|
1718
|
-
y = (o.mt[N - 1] & UPPER_MASK) | (o.mt[0] & LOWER_MASK)
|
|
1719
|
-
o.mt[N - 1] = o.mt[M - 1] ~ (y >> 1) ~ mag01[y & 0x1]
|
|
1720
|
-
|
|
1721
|
-
o.mti = 0
|
|
1722
|
-
end
|
|
1723
|
-
|
|
1724
|
-
y = o.mt[o.mti]
|
|
1725
|
-
o.mti = o.mti + 1
|
|
1726
|
-
|
|
1727
|
-
-- Tempering
|
|
1728
|
-
y = y ~ (y >> 11)
|
|
1729
|
-
y = y ~ ((y << 7) & 0x9d2c5680)
|
|
1730
|
-
y = y ~ ((y << 15) & 0xefc60000)
|
|
1731
|
-
y = y ~ (y >> 18)
|
|
1732
|
-
|
|
1733
|
-
return y
|
|
1734
|
-
end
|
|
1735
|
-
|
|
1736
|
-
local MersenneTwister = {}
|
|
1737
|
-
MersenneTwister.mt = {}
|
|
1738
|
-
MersenneTwister.mti = N + 1
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
--- The Random table
|
|
1742
|
-
-- @table Random
|
|
1743
|
-
-- @field seed The seed function
|
|
1744
|
-
-- @field random The random function
|
|
1745
|
-
-- @field integer The integer function
|
|
1746
|
-
local Random = {}
|
|
1747
|
-
|
|
1748
|
-
--- Sets a new random table given a seed.
|
|
1749
|
-
-- @function seed
|
|
1750
|
-
-- @tparam {number} seed The seed
|
|
1751
|
-
function Random.seed(seed)
|
|
1752
|
-
init_genrand(MersenneTwister, seed)
|
|
1753
|
-
end
|
|
1754
|
-
|
|
1755
|
-
--- Generates a random number on [0,1)-real-interval.
|
|
1756
|
-
-- @function random
|
|
1757
|
-
-- @treturn {number} The random number
|
|
1758
|
-
function Random.random()
|
|
1759
|
-
return genrand_int32(MersenneTwister) * (1.0 / 4294967296.0)
|
|
1760
|
-
end
|
|
1761
|
-
|
|
1762
|
-
--- Returns a random integer. The min and max are INCLUDED in the range.
|
|
1763
|
-
-- The max integer in lua is math.maxinteger
|
|
1764
|
-
-- The min is math.mininteger
|
|
1765
|
-
-- @function Random.integer
|
|
1766
|
-
-- @tparam {number} min The minimum value
|
|
1767
|
-
-- @tparam {number} max The maximum value
|
|
1768
|
-
-- @treturn {number} The random integer
|
|
1769
|
-
function Random.integer(min, max)
|
|
1770
|
-
assert(max >= min, "max must bigger than min")
|
|
1771
|
-
return math.floor(Random.random() * (max - min + 1) + min)
|
|
1772
|
-
end
|
|
1773
|
-
|
|
1774
|
-
return Random
|
|
1775
|
-
end
|
|
1776
|
-
_G.package.loaded[".chance"] = load_chance()
|
|
1777
|
-
print("loaded chance")
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
local function load_boot()
|
|
1782
|
-
--- The Boot module provides functionality for booting the process. Returns the boot function.
|
|
1783
|
-
-- @module boot
|
|
1784
|
-
|
|
1785
|
-
-- This is for aop6 Boot Loader
|
|
1786
|
-
-- See: https://github.com/permaweb/aos/issues/342
|
|
1787
|
-
-- For the Process as the first Message, if On-Boot
|
|
1788
|
-
-- has the value 'data' then evaluate the data
|
|
1789
|
-
-- if it is a tx id, then download and evaluate the tx
|
|
1790
|
-
|
|
1791
|
-
local drive = { _version = "0.0.1" }
|
|
1792
|
-
|
|
1793
|
-
function drive.getData(txId)
|
|
1794
|
-
local file = io.open('/data/' .. txId)
|
|
1795
|
-
if not file then
|
|
1796
|
-
return nil, "File not found!"
|
|
1797
|
-
end
|
|
1798
|
-
local contents = file:read(
|
|
1799
|
-
file:seek('end')
|
|
1800
|
-
)
|
|
1801
|
-
file:close()
|
|
1802
|
-
return contents
|
|
1803
|
-
end
|
|
1804
|
-
|
|
1805
|
-
--- The boot function.
|
|
1806
|
-
-- If the message has no On-Boot tag, do nothing.
|
|
1807
|
-
-- If the message has an On-Boot tag with the value 'Data', then evaluate the message.
|
|
1808
|
-
-- If the message has an On-Boot tag with a tx id, then download and evaluate the tx data.
|
|
1809
|
-
-- @function boot
|
|
1810
|
-
-- @param ao The ao environment object
|
|
1811
|
-
-- @see eval
|
|
1812
|
-
return function (ao)
|
|
1813
|
-
local eval = require(".eval")(ao)
|
|
1814
|
-
return function (msg)
|
|
1815
|
-
if #Inbox == 0 then
|
|
1816
|
-
table.insert(Inbox, msg)
|
|
1817
|
-
end
|
|
1818
|
-
if msg.Tags['On-Boot'] == nil then
|
|
1819
|
-
return
|
|
1820
|
-
end
|
|
1821
|
-
if msg.Tags['On-Boot'] == 'Data' then
|
|
1822
|
-
eval(msg)
|
|
1823
|
-
else
|
|
1824
|
-
local loadedVal = drive.getData(msg.Tags['On-Boot'])
|
|
1825
|
-
eval({ Data = loadedVal })
|
|
1826
|
-
end
|
|
1827
|
-
end
|
|
1828
|
-
end
|
|
1829
|
-
end
|
|
1830
|
-
_G.package.loaded[".boot"] = load_boot()
|
|
1831
|
-
print("loaded boot")
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
local function load_default()
|
|
1836
|
-
local json = require('.json')
|
|
1837
|
-
-- default handler for aos
|
|
1838
|
-
return function (insertInbox)
|
|
1839
|
-
return function (msg)
|
|
1840
|
-
-- Add Message to Inbox
|
|
1841
|
-
insertInbox(msg)
|
|
1842
|
-
|
|
1843
|
-
-- local txt = Colors.gray .. "New Message From " .. Colors.green ..
|
|
1844
|
-
-- (msg.From and (msg.From:sub(1,3) .. "..." .. msg.From:sub(-3)) or "unknown") .. Colors.gray .. ": "
|
|
1845
|
-
-- if msg.Action then
|
|
1846
|
-
-- txt = txt .. Colors.gray .. (msg.Action and ("Action = " .. Colors.blue .. msg.Action:sub(1,20)) or "") .. Colors.reset
|
|
1847
|
-
-- else
|
|
1848
|
-
-- local data = msg.Data
|
|
1849
|
-
-- if type(data) == 'table' then
|
|
1850
|
-
-- data = json.encode(data)
|
|
1851
|
-
-- end
|
|
1852
|
-
-- txt = txt .. Colors.gray .. "Data = " .. Colors.blue .. (data and data:sub(1,20) or "") .. Colors.reset
|
|
1853
|
-
-- end
|
|
1854
|
-
-- Print to Output
|
|
1855
|
-
-- print(txt)
|
|
1856
|
-
print("New Message")
|
|
1857
|
-
end
|
|
1858
|
-
|
|
1859
|
-
end
|
|
1860
|
-
|
|
1861
|
-
end
|
|
1862
|
-
_G.package.loaded[".default"] = load_default()
|
|
1863
|
-
print("loaded default")
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
local function load_ao()
|
|
1868
|
-
Handlers = Handlers or require('.handlers')
|
|
1869
|
-
|
|
1870
|
-
local oldao = ao or {}
|
|
1871
|
-
|
|
1872
|
-
local utils = require('.utils')
|
|
1873
|
-
|
|
1874
|
-
local ao = {
|
|
1875
|
-
_version = "0.0.6",
|
|
1876
|
-
id = oldao.id or "",
|
|
1877
|
-
_module = oldao._module or "",
|
|
1878
|
-
authorities = oldao.authorities or {},
|
|
1879
|
-
reference = oldao.reference or 0,
|
|
1880
|
-
outbox = oldao.outbox or
|
|
1881
|
-
{Output = {}, Messages = {}, Spawns = {}, Assignments = {}},
|
|
1882
|
-
nonExtractableTags = {
|
|
1883
|
-
'data-protocol', 'variant', 'from-process', 'from-module', 'type',
|
|
1884
|
-
'from', 'owner', 'anchor', 'target', 'data', 'tags', 'read-only'
|
|
1885
|
-
},
|
|
1886
|
-
nonForwardableTags = {
|
|
1887
|
-
'data-protocol', 'variant', 'from-process', 'from-module', 'type',
|
|
1888
|
-
'from', 'owner', 'anchor', 'target', 'tags', 'tagArray', 'hash-chain',
|
|
1889
|
-
'timestamp', 'nonce', 'slot', 'epoch', 'signature', 'forwarded-by',
|
|
1890
|
-
'pushed-for', 'read-only', 'cron', 'block-height', 'reference', 'id',
|
|
1891
|
-
'reply-to'
|
|
1892
|
-
},
|
|
1893
|
-
Nonce = nil
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
function ao.clearOutbox()
|
|
1897
|
-
ao.outbox = { Output = {}, Messages = {}, Spawns = {}, Assignments = {}}
|
|
1898
|
-
end
|
|
1899
|
-
|
|
1900
|
-
local function getId(m)
|
|
1901
|
-
local id = ""
|
|
1902
|
-
utils.map(function (k)
|
|
1903
|
-
local c = m.commitments[k]
|
|
1904
|
-
if c.alg == "rsa-pss-sha512" then
|
|
1905
|
-
id = k
|
|
1906
|
-
elseif c.alg == "signed" and c['commitment-device'] == "ans104" then
|
|
1907
|
-
id = k
|
|
1908
|
-
end
|
|
1909
|
-
end, utils.keys(m.commitments)
|
|
1910
|
-
)
|
|
1911
|
-
return id
|
|
1912
|
-
end
|
|
1913
|
-
|
|
1914
|
-
function ao.init(env)
|
|
1915
|
-
if ao.id == "" then ao.id = getId(env.process) end
|
|
1916
|
-
|
|
1917
|
-
-- if ao._module == "" then
|
|
1918
|
-
-- ao._module = env.Module.Id
|
|
1919
|
-
-- end
|
|
1920
|
-
-- TODO: need to deal with assignables
|
|
1921
|
-
if #ao.authorities < 1 then
|
|
1922
|
-
if type(env.process.authority) == 'string' then
|
|
1923
|
-
ao.authorities = { env.process.authority }
|
|
1924
|
-
else
|
|
1925
|
-
ao.authorities = env.process.authority
|
|
1926
|
-
end
|
|
1927
|
-
end
|
|
1928
|
-
|
|
1929
|
-
ao.outbox = {Output = {}, Messages = {}, Spawns = {}, Assignments = {}}
|
|
1930
|
-
ao.env = env
|
|
1931
|
-
|
|
1932
|
-
end
|
|
1933
|
-
|
|
1934
|
-
function ao.send(msg)
|
|
1935
|
-
assert(type(msg) == 'table', 'msg should be a table')
|
|
1936
|
-
|
|
1937
|
-
ao.reference = ao.reference + 1
|
|
1938
|
-
local referenceString = tostring(ao.reference)
|
|
1939
|
-
-- set kv
|
|
1940
|
-
msg.reference = referenceString
|
|
1941
|
-
|
|
1942
|
-
-- clone message info and add to outbox
|
|
1943
|
-
table.insert(ao.outbox.Messages, utils.reduce(
|
|
1944
|
-
function (acc, key)
|
|
1945
|
-
acc[key] = msg[key]
|
|
1946
|
-
return acc
|
|
1947
|
-
end,
|
|
1948
|
-
{},
|
|
1949
|
-
utils.keys(msg)
|
|
1950
|
-
))
|
|
1951
|
-
|
|
1952
|
-
if msg.target then
|
|
1953
|
-
msg.onReply = function(...)
|
|
1954
|
-
local from, resolver
|
|
1955
|
-
if select("#", ...) == 2 then
|
|
1956
|
-
from = select(1, ...)
|
|
1957
|
-
resolver = select(2, ...)
|
|
1958
|
-
else
|
|
1959
|
-
from = msg.target
|
|
1960
|
-
resolver = select(1, ...)
|
|
1961
|
-
end
|
|
1962
|
-
Handlers.once({
|
|
1963
|
-
from = from,
|
|
1964
|
-
["x-reference"] = referenceString
|
|
1965
|
-
}, resolver)
|
|
1966
|
-
end
|
|
1967
|
-
end
|
|
1968
|
-
return msg
|
|
1969
|
-
end
|
|
1970
|
-
|
|
1971
|
-
function ao.spawn(module, msg)
|
|
1972
|
-
assert(type(module) == "string", "Module source id is required!")
|
|
1973
|
-
assert(type(msg) == "table", "Message must be a table.")
|
|
1974
|
-
|
|
1975
|
-
ao.reference = ao.reference + 1
|
|
1976
|
-
|
|
1977
|
-
local spawnRef = tostring(ao.reference)
|
|
1978
|
-
|
|
1979
|
-
msg["reference"] = spawnRef
|
|
1980
|
-
|
|
1981
|
-
-- clone message info and add to outbox
|
|
1982
|
-
table.insert(ao.outbox.Spawns, utils.reduce(
|
|
1983
|
-
function (acc, key)
|
|
1984
|
-
acc[key] = msg[key]
|
|
1985
|
-
return acc
|
|
1986
|
-
end,
|
|
1987
|
-
{},
|
|
1988
|
-
utils.keys(msg)
|
|
1989
|
-
))
|
|
1990
|
-
|
|
1991
|
-
msg.onReply = function(cb)
|
|
1992
|
-
Handlers.once({
|
|
1993
|
-
action = "Spawned",
|
|
1994
|
-
from = ao.id,
|
|
1995
|
-
["x-reference"] = spawnRef
|
|
1996
|
-
}, cb)
|
|
1997
|
-
end
|
|
1998
|
-
|
|
1999
|
-
return msg
|
|
2000
|
-
|
|
2001
|
-
end
|
|
2002
|
-
|
|
2003
|
-
function ao.result(result)
|
|
2004
|
-
if ao.outbox.Error or result.Error then
|
|
2005
|
-
return { Error = result.Error or ao.outbox.Error }
|
|
2006
|
-
end
|
|
2007
|
-
return {
|
|
2008
|
-
Output = result.Output or ao.output.Output,
|
|
2009
|
-
Messages = ao.outbox.Messages,
|
|
2010
|
-
Spawns = ao.outbox.Spawns,
|
|
2011
|
-
Assignments = ao.outbox.Assignments
|
|
2012
|
-
}
|
|
2013
|
-
end
|
|
2014
|
-
|
|
2015
|
-
-- set global Send and Spawn
|
|
2016
|
-
Send = Send or ao.send
|
|
2017
|
-
Spawn = Spawn or ao.spawn
|
|
2018
|
-
|
|
2019
|
-
return ao
|
|
2020
|
-
|
|
2021
|
-
end
|
|
2022
|
-
_G.package.loaded[".ao"] = load_ao()
|
|
2023
|
-
print("loaded ao")
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
local function load_base64()
|
|
2028
|
-
--[[
|
|
2029
|
-
|
|
2030
|
-
base64 -- v1.5.3 public domain Lua base64 encoder/decoder
|
|
2031
|
-
no warranty implied; use at your own risk
|
|
2032
|
-
|
|
2033
|
-
Needs bit32.extract function. If not present it's implemented using BitOp
|
|
2034
|
-
or Lua 5.3 native bit operators. For Lua 5.1 fallbacks to pure Lua
|
|
2035
|
-
implementation inspired by Rici Lake's post:
|
|
2036
|
-
http://ricilake.blogspot.co.uk/2007/10/iterating-bits-in-lua.html
|
|
2037
|
-
|
|
2038
|
-
author: Ilya Kolbin (iskolbin@gmail.com)
|
|
2039
|
-
url: github.com/iskolbin/lbase64
|
|
2040
|
-
|
|
2041
|
-
COMPATIBILITY
|
|
2042
|
-
|
|
2043
|
-
Lua 5.1+, LuaJIT
|
|
2044
|
-
|
|
2045
|
-
LICENSE
|
|
2046
|
-
|
|
2047
|
-
See end of file for license information.
|
|
2048
|
-
|
|
2049
|
-
--]]
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
local base64 = {}
|
|
2053
|
-
|
|
2054
|
-
local extract = _G.bit32 and _G.bit32.extract -- Lua 5.2/Lua 5.3 in compatibility mode
|
|
2055
|
-
if not extract then
|
|
2056
|
-
if _G.bit then -- LuaJIT
|
|
2057
|
-
local shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.band
|
|
2058
|
-
extract = function( v, from, width )
|
|
2059
|
-
return band( shr( v, from ), shl( 1, width ) - 1 )
|
|
2060
|
-
end
|
|
2061
|
-
elseif _G._VERSION == "Lua 5.1" then
|
|
2062
|
-
extract = function( v, from, width )
|
|
2063
|
-
local w = 0
|
|
2064
|
-
local flag = 2^from
|
|
2065
|
-
for i = 0, width-1 do
|
|
2066
|
-
local flag2 = flag + flag
|
|
2067
|
-
if v % flag2 >= flag then
|
|
2068
|
-
w = w + 2^i
|
|
2069
|
-
end
|
|
2070
|
-
flag = flag2
|
|
2071
|
-
end
|
|
2072
|
-
return w
|
|
2073
|
-
end
|
|
2074
|
-
else -- Lua 5.3+
|
|
2075
|
-
extract = load[[return function( v, from, width )
|
|
2076
|
-
return ( v >> from ) & ((1 << width) - 1)
|
|
2077
|
-
end]]()
|
|
2078
|
-
end
|
|
2079
|
-
end
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
function base64.makeencoder( s62, s63, spad )
|
|
2083
|
-
local encoder = {}
|
|
2084
|
-
for b64code, char in pairs{[0]='A','B','C','D','E','F','G','H','I','J',
|
|
2085
|
-
'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y',
|
|
2086
|
-
'Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
|
|
2087
|
-
'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2',
|
|
2088
|
-
'3','4','5','6','7','8','9',s62 or '+',s63 or'/',spad or'='} do
|
|
2089
|
-
encoder[b64code] = char:byte()
|
|
2090
|
-
end
|
|
2091
|
-
return encoder
|
|
2092
|
-
end
|
|
2093
|
-
|
|
2094
|
-
function base64.makedecoder( s62, s63, spad )
|
|
2095
|
-
local decoder = {}
|
|
2096
|
-
for b64code, charcode in pairs( base64.makeencoder( s62, s63, spad )) do
|
|
2097
|
-
decoder[charcode] = b64code
|
|
2098
|
-
end
|
|
2099
|
-
return decoder
|
|
2100
|
-
end
|
|
2101
|
-
|
|
2102
|
-
local DEFAULT_ENCODER = base64.makeencoder()
|
|
2103
|
-
local DEFAULT_DECODER = base64.makedecoder()
|
|
2104
|
-
|
|
2105
|
-
local char, concat = string.char, table.concat
|
|
2106
|
-
|
|
2107
|
-
function base64.encode( str, encoder, usecaching )
|
|
2108
|
-
encoder = encoder or DEFAULT_ENCODER
|
|
2109
|
-
local t, k, n = {}, 1, #str
|
|
2110
|
-
local lastn = n % 3
|
|
2111
|
-
local cache = {}
|
|
2112
|
-
for i = 1, n-lastn, 3 do
|
|
2113
|
-
local a, b, c = str:byte( i, i+2 )
|
|
2114
|
-
local v = a*0x10000 + b*0x100 + c
|
|
2115
|
-
local s
|
|
2116
|
-
if usecaching then
|
|
2117
|
-
s = cache[v]
|
|
2118
|
-
if not s then
|
|
2119
|
-
s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
|
|
2120
|
-
cache[v] = s
|
|
2121
|
-
end
|
|
2122
|
-
else
|
|
2123
|
-
s = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[extract(v,0,6)])
|
|
2124
|
-
end
|
|
2125
|
-
t[k] = s
|
|
2126
|
-
k = k + 1
|
|
2127
|
-
end
|
|
2128
|
-
if lastn == 2 then
|
|
2129
|
-
local a, b = str:byte( n-1, n )
|
|
2130
|
-
local v = a*0x10000 + b*0x100
|
|
2131
|
-
t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[extract(v,6,6)], encoder[64])
|
|
2132
|
-
elseif lastn == 1 then
|
|
2133
|
-
local v = str:byte( n )*0x10000
|
|
2134
|
-
t[k] = char(encoder[extract(v,18,6)], encoder[extract(v,12,6)], encoder[64], encoder[64])
|
|
2135
|
-
end
|
|
2136
|
-
return concat( t )
|
|
2137
|
-
end
|
|
2138
|
-
|
|
2139
|
-
function base64.decode( b64, decoder, usecaching )
|
|
2140
|
-
decoder = decoder or DEFAULT_DECODER
|
|
2141
|
-
local pattern = '[^%w%+%/%=]'
|
|
2142
|
-
if decoder then
|
|
2143
|
-
local s62, s63
|
|
2144
|
-
for charcode, b64code in pairs( decoder ) do
|
|
2145
|
-
if b64code == 62 then s62 = charcode
|
|
2146
|
-
elseif b64code == 63 then s63 = charcode
|
|
2147
|
-
end
|
|
2148
|
-
end
|
|
2149
|
-
pattern = ('[^%%w%%%s%%%s%%=]'):format( char(s62), char(s63) )
|
|
2150
|
-
end
|
|
2151
|
-
b64 = b64:gsub( pattern, '' )
|
|
2152
|
-
local cache = usecaching and {}
|
|
2153
|
-
local t, k = {}, 1
|
|
2154
|
-
local n = #b64
|
|
2155
|
-
local padding = b64:sub(-2) == '==' and 2 or b64:sub(-1) == '=' and 1 or 0
|
|
2156
|
-
for i = 1, padding > 0 and n-4 or n, 4 do
|
|
2157
|
-
local a, b, c, d = b64:byte( i, i+3 )
|
|
2158
|
-
local s
|
|
2159
|
-
if usecaching then
|
|
2160
|
-
local v0 = a*0x1000000 + b*0x10000 + c*0x100 + d
|
|
2161
|
-
s = cache[v0]
|
|
2162
|
-
if not s then
|
|
2163
|
-
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
|
|
2164
|
-
s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
|
|
2165
|
-
cache[v0] = s
|
|
2166
|
-
end
|
|
2167
|
-
else
|
|
2168
|
-
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40 + decoder[d]
|
|
2169
|
-
s = char( extract(v,16,8), extract(v,8,8), extract(v,0,8))
|
|
2170
|
-
end
|
|
2171
|
-
t[k] = s
|
|
2172
|
-
k = k + 1
|
|
2173
|
-
end
|
|
2174
|
-
if padding == 1 then
|
|
2175
|
-
local a, b, c = b64:byte( n-3, n-1 )
|
|
2176
|
-
local v = decoder[a]*0x40000 + decoder[b]*0x1000 + decoder[c]*0x40
|
|
2177
|
-
t[k] = char( extract(v,16,8), extract(v,8,8))
|
|
2178
|
-
elseif padding == 2 then
|
|
2179
|
-
local a, b = b64:byte( n-3, n-2 )
|
|
2180
|
-
local v = decoder[a]*0x40000 + decoder[b]*0x1000
|
|
2181
|
-
t[k] = char( extract(v,16,8))
|
|
2182
|
-
end
|
|
2183
|
-
return concat( t )
|
|
2184
|
-
end
|
|
2185
|
-
|
|
2186
|
-
return base64
|
|
2187
|
-
|
|
2188
|
-
--[[
|
|
2189
|
-
------------------------------------------------------------------------------
|
|
2190
|
-
This software is available under 2 licenses -- choose whichever you prefer.
|
|
2191
|
-
------------------------------------------------------------------------------
|
|
2192
|
-
ALTERNATIVE A - MIT License
|
|
2193
|
-
Copyright (c) 2018 Ilya Kolbin
|
|
2194
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
2195
|
-
this software and associated documentation files (the "Software"), to deal in
|
|
2196
|
-
the Software without restriction, including without limitation the rights to
|
|
2197
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
2198
|
-
of the Software, and to permit persons to whom the Software is furnished to do
|
|
2199
|
-
so, subject to the following conditions:
|
|
2200
|
-
The above copyright notice and this permission notice shall be included in all
|
|
2201
|
-
copies or substantial portions of the Software.
|
|
2202
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2203
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2204
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2205
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
2206
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
2207
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
2208
|
-
SOFTWARE.
|
|
2209
|
-
------------------------------------------------------------------------------
|
|
2210
|
-
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
|
2211
|
-
This is free and unencumbered software released into the public domain.
|
|
2212
|
-
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
|
2213
|
-
software, either in source code form or as a compiled binary, for any purpose,
|
|
2214
|
-
commercial or non-commercial, and by any means.
|
|
2215
|
-
In jurisdictions that recognize copyright laws, the author or authors of this
|
|
2216
|
-
software dedicate any and all copyright interest in the software to the public
|
|
2217
|
-
domain. We make this dedication for the benefit of the public at large and to
|
|
2218
|
-
the detriment of our heirs and successors. We intend this dedication to be an
|
|
2219
|
-
overt act of relinquishment in perpetuity of all present and future rights to
|
|
2220
|
-
this software under copyright law.
|
|
2221
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
2222
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
2223
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
2224
|
-
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
2225
|
-
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
2226
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
2227
|
-
------------------------------------------------------------------------------
|
|
2228
|
-
--]]
|
|
2229
|
-
end
|
|
2230
|
-
_G.package.loaded[".base64"] = load_base64()
|
|
2231
|
-
print("loaded base64")
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
local function load_state()
|
|
2236
|
-
ao = ao or require('.ao')
|
|
2237
|
-
local state = {}
|
|
2238
|
-
local stringify = require('.stringify')
|
|
2239
|
-
local utils = require('.utils')
|
|
2240
|
-
|
|
2241
|
-
Colors = { red = "\27[31m", green = "\27[32m",
|
|
2242
|
-
blue = "\27[34m", reset = "\27[0m", gray = "\27[90m"
|
|
2243
|
-
}
|
|
2244
|
-
Bell = "\x07"
|
|
2245
|
-
|
|
2246
|
-
Initialized = Initialized or false
|
|
2247
|
-
Name = Name or "aos"
|
|
2248
|
-
|
|
2249
|
-
Owner = Owner or ""
|
|
2250
|
-
Inbox = Inbox or {}
|
|
2251
|
-
|
|
2252
|
-
-- global prompt function
|
|
2253
|
-
function Prompt()
|
|
2254
|
-
return "aos> "
|
|
2255
|
-
end
|
|
2256
|
-
|
|
2257
|
-
local maxInboxCount = 10000
|
|
2258
|
-
|
|
2259
|
-
function state.insertInbox(msg)
|
|
2260
|
-
table.insert(Inbox, msg)
|
|
2261
|
-
local overflow = #Inbox - maxInboxCount
|
|
2262
|
-
for i = 1,overflow do
|
|
2263
|
-
table.remove(Inbox,1)
|
|
2264
|
-
end
|
|
2265
|
-
end
|
|
2266
|
-
local function getOwnerAddress(m)
|
|
2267
|
-
local _owner = nil
|
|
2268
|
-
utils.map(function (k)
|
|
2269
|
-
local c = m.commitments[k]
|
|
2270
|
-
if c.alg == "rsa-pss-sha512" then
|
|
2271
|
-
_owner = c.committer
|
|
2272
|
-
elseif c.alg == "signed" and c['commitment-device'] == "ans104" then
|
|
2273
|
-
_owner = c.commiter
|
|
2274
|
-
end
|
|
2275
|
-
end, utils.keys(m.commitments))
|
|
2276
|
-
return _owner
|
|
2277
|
-
end
|
|
2278
|
-
|
|
2279
|
-
local function isFromOwner(m)
|
|
2280
|
-
local _owner = getOwnerAddress(m)
|
|
2281
|
-
local _fromProcess = m['from-process'] or _owner
|
|
2282
|
-
return _owner ~= nil and _fromProcess == _owner
|
|
2283
|
-
end
|
|
2284
|
-
|
|
2285
|
-
local function getOwner(m)
|
|
2286
|
-
local id = ""
|
|
2287
|
-
if m['from-process'] then
|
|
2288
|
-
return m['from-process']
|
|
2289
|
-
end
|
|
2290
|
-
|
|
2291
|
-
utils.map(function (k)
|
|
2292
|
-
local c = m.commitments[k]
|
|
2293
|
-
if c.alg == "rsa-pss-sha512" then
|
|
2294
|
-
id = c.committer
|
|
2295
|
-
elseif c.alg == "signed" and c['commitment-device'] == "ans104" then
|
|
2296
|
-
id = c.committer
|
|
2297
|
-
end
|
|
2298
|
-
end, utils.keys(m.commitments)
|
|
2299
|
-
)
|
|
2300
|
-
return id
|
|
2301
|
-
end
|
|
2302
|
-
|
|
2303
|
-
function state.init(req, base)
|
|
2304
|
-
if not Initialized then
|
|
2305
|
-
Owner = getOwner(base.process)
|
|
2306
|
-
-- if process id is equal to message id then set Owner
|
|
2307
|
-
-- TODO: need additional check, like msg.Slot == 1
|
|
2308
|
-
-- if env.Process.Id == msg.Id and Owner ~= msg.Id then
|
|
2309
|
-
-- Owner = env.Process['From-Process'] or msg.From
|
|
2310
|
-
-- end
|
|
2311
|
-
-- if env.Process.Name then
|
|
2312
|
-
-- Name = Name == "aos" and env.Process.Name
|
|
2313
|
-
-- end
|
|
2314
|
-
-- global print function
|
|
2315
|
-
function print(a)
|
|
2316
|
-
if type(a) == "table" then
|
|
2317
|
-
a = stringify.format(a)
|
|
2318
|
-
end
|
|
2319
|
-
|
|
2320
|
-
if type(a) == "boolean" then
|
|
2321
|
-
a = Colors.blue .. tostring(a) .. Colors.reset
|
|
2322
|
-
end
|
|
2323
|
-
if type(a) == "nil" then
|
|
2324
|
-
a = Colors.red .. tostring(a) .. Colors.reset
|
|
2325
|
-
end
|
|
2326
|
-
if type(a) == "number" then
|
|
2327
|
-
a = Colors.green .. tostring(a) .. Colors.reset
|
|
2328
|
-
end
|
|
2329
|
-
|
|
2330
|
-
if HandlerPrintLogs then
|
|
2331
|
-
table.insert(HandlerPrintLogs, a)
|
|
2332
|
-
return nil
|
|
2333
|
-
end
|
|
2334
|
-
|
|
2335
|
-
return tostring(a)
|
|
2336
|
-
end
|
|
2337
|
-
|
|
2338
|
-
Initialized = true
|
|
2339
|
-
end
|
|
2340
|
-
end
|
|
2341
|
-
|
|
2342
|
-
function state.getFrom(req)
|
|
2343
|
-
return getOwner(req.body)
|
|
2344
|
-
end
|
|
2345
|
-
|
|
2346
|
-
function state.isTrusted(req)
|
|
2347
|
-
if isFromOwner(req.body) then
|
|
2348
|
-
return true
|
|
2349
|
-
end
|
|
2350
|
-
local _trusted = false
|
|
2351
|
-
|
|
2352
|
-
if req.body['from-process'] then
|
|
2353
|
-
_trusted = utils.includes(
|
|
2354
|
-
req.body['from-process'],
|
|
2355
|
-
ao.authorities
|
|
2356
|
-
)
|
|
2357
|
-
end
|
|
2358
|
-
|
|
2359
|
-
if not _trusted then
|
|
2360
|
-
_trusted = utils.includes(
|
|
2361
|
-
getOwner(req.body), ao.authorities
|
|
2362
|
-
)
|
|
2363
|
-
end
|
|
2364
|
-
return _trusted
|
|
2365
|
-
end
|
|
2366
|
-
|
|
2367
|
-
function state.checkSlot(req, ao)
|
|
2368
|
-
-- slot check
|
|
2369
|
-
if not ao.slot then
|
|
2370
|
-
ao.slot = tonumber(req.slot)
|
|
2371
|
-
else
|
|
2372
|
-
if tonumber(req.slot) ~= (ao.slot + 1) then
|
|
2373
|
-
print(table.concat({
|
|
2374
|
-
Colors.red,
|
|
2375
|
-
"WARNING: Slot did not match, may be due to an error generated by process",
|
|
2376
|
-
Colors.reset
|
|
2377
|
-
}))
|
|
2378
|
-
print("")
|
|
2379
|
-
end
|
|
2380
|
-
end
|
|
2381
|
-
end
|
|
2382
|
-
|
|
2383
|
-
function state.reset(tbl)
|
|
2384
|
-
tbl = nil
|
|
2385
|
-
collectgarbage()
|
|
2386
|
-
return {}
|
|
2387
|
-
end
|
|
2388
|
-
|
|
2389
|
-
return state
|
|
2390
|
-
|
|
2391
|
-
end
|
|
2392
|
-
_G.package.loaded[".state"] = load_state()
|
|
2393
|
-
print("loaded state")
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
local function load_process()
|
|
2398
|
-
ao = ao or require('.ao')
|
|
2399
|
-
Handlers = require('.handlers')
|
|
2400
|
-
Utils = require('.utils')
|
|
2401
|
-
Dump = require('.dump')
|
|
2402
|
-
|
|
2403
|
-
local process = { _version = "2.0.7" }
|
|
2404
|
-
local state = require('.state')
|
|
2405
|
-
local eval = require('.eval')
|
|
2406
|
-
local default = require('.default')
|
|
2407
|
-
local json = require('.json')
|
|
2408
|
-
|
|
2409
|
-
function Prompt()
|
|
2410
|
-
return "aos> "
|
|
2411
|
-
end
|
|
2412
|
-
|
|
2413
|
-
function process.handle(req, base)
|
|
2414
|
-
HandlerPrintLogs = state.reset(HandlerPrintLogs)
|
|
2415
|
-
os.time = function () return tonumber(req['block-timestamp']) end
|
|
2416
|
-
|
|
2417
|
-
ao.init(base)
|
|
2418
|
-
-- initialize state
|
|
2419
|
-
state.init(req, base)
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
-- magic table
|
|
2423
|
-
req.body.data = req.body['Content-Type'] == 'application/json'
|
|
2424
|
-
and json.decode(req.body.data or "{}")
|
|
2425
|
-
or req.body.data
|
|
2426
|
-
|
|
2427
|
-
Errors = Errors or {}
|
|
2428
|
-
-- clear outbox
|
|
2429
|
-
ao.clearOutbox()
|
|
2430
|
-
|
|
2431
|
-
if not state.isTrusted(req) then
|
|
2432
|
-
return ao.result({
|
|
2433
|
-
Output = {
|
|
2434
|
-
data = "Message is not trusted."
|
|
2435
|
-
}
|
|
2436
|
-
})
|
|
2437
|
-
end
|
|
2438
|
-
|
|
2439
|
-
req.reply = function (_reply)
|
|
2440
|
-
local _from = state.getFrom(req)
|
|
2441
|
-
_reply.target = _reply.target and _reply.target or _from
|
|
2442
|
-
_reply['x-reference'] = req.body.reference or nil
|
|
2443
|
-
_reply['x-origin'] = req.body['x-origin'] or nil
|
|
2444
|
-
return ao.send(_reply)
|
|
2445
|
-
end
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
-- state.checkSlot(msg, ao)
|
|
2449
|
-
Handlers.add("_eval", function (_req)
|
|
2450
|
-
local function getMsgFrom(m)
|
|
2451
|
-
local from = ""
|
|
2452
|
-
Utils.map(
|
|
2453
|
-
function (k)
|
|
2454
|
-
local c = m.commitments[k]
|
|
2455
|
-
if c.alg == "rsa-pss-sha512" then
|
|
2456
|
-
from = c.committer
|
|
2457
|
-
end
|
|
2458
|
-
end,
|
|
2459
|
-
Utils.keys(m.commitments)
|
|
2460
|
-
)
|
|
2461
|
-
return from
|
|
2462
|
-
end
|
|
2463
|
-
return _req.body.action == "Eval" and Owner == getMsgFrom(_req.body)
|
|
2464
|
-
end, eval(ao))
|
|
2465
|
-
|
|
2466
|
-
Handlers.add("_default",
|
|
2467
|
-
function () return true end,
|
|
2468
|
-
default(state.insertInbox)
|
|
2469
|
-
)
|
|
2470
|
-
|
|
2471
|
-
local status, error = pcall(Handlers.evaluate, req, base)
|
|
2472
|
-
|
|
2473
|
-
-- cleanup handlers so that they are always at the end of the pipeline
|
|
2474
|
-
Handlers.remove("_eval")
|
|
2475
|
-
Handlers.remove("_default")
|
|
2476
|
-
|
|
2477
|
-
local printData = table.concat(HandlerPrintLogs, "\n")
|
|
2478
|
-
if not status then
|
|
2479
|
-
if req.body.action == "Eval" then
|
|
2480
|
-
return {
|
|
2481
|
-
Error = table.concat({
|
|
2482
|
-
printData,
|
|
2483
|
-
"\n",
|
|
2484
|
-
Colors.red,
|
|
2485
|
-
"error: " .. error,
|
|
2486
|
-
Colors.reset,
|
|
2487
|
-
})
|
|
2488
|
-
}
|
|
2489
|
-
end
|
|
2490
|
-
print(Colors.red .. "Error" .. Colors.gray .. " handling message " .. Colors.reset)
|
|
2491
|
-
print(Colors.green .. error .. Colors.reset)
|
|
2492
|
-
-- print("\n" .. Colors.gray .. debug.traceback() .. Colors.reset)
|
|
2493
|
-
return ao.result({
|
|
2494
|
-
Output = {
|
|
2495
|
-
data = printData .. '\n\n' .. Colors.red .. 'error:\n' .. Colors.reset .. error
|
|
2496
|
-
},
|
|
2497
|
-
Messages = {},
|
|
2498
|
-
Spawns = {},
|
|
2499
|
-
Assignments = {}
|
|
2500
|
-
})
|
|
2501
|
-
end
|
|
2502
|
-
|
|
2503
|
-
local response = {}
|
|
2504
|
-
|
|
2505
|
-
if req.body.action == "Eval" then
|
|
2506
|
-
response = ao.result({
|
|
2507
|
-
Output = {
|
|
2508
|
-
data = printData,
|
|
2509
|
-
prompt = Prompt()
|
|
2510
|
-
}
|
|
2511
|
-
})
|
|
2512
|
-
else
|
|
2513
|
-
response = ao.result({
|
|
2514
|
-
Output = {
|
|
2515
|
-
data = printData,
|
|
2516
|
-
prompt = Prompt(),
|
|
2517
|
-
print = true
|
|
2518
|
-
}
|
|
2519
|
-
})
|
|
2520
|
-
end
|
|
2521
|
-
|
|
2522
|
-
HandlerPrintLogs = state.reset(HandlerPrintLogs) -- clear logs
|
|
2523
|
-
-- ao.Slot = msg.Slot
|
|
2524
|
-
return response
|
|
2525
|
-
end
|
|
2526
|
-
|
|
2527
|
-
function Version()
|
|
2528
|
-
print("version: " .. process._version)
|
|
2529
|
-
end
|
|
2530
|
-
|
|
2531
|
-
return process
|
|
2532
|
-
|
|
2533
|
-
end
|
|
2534
|
-
_G.package.loaded[".process"] = load_process()
|
|
2535
|
-
print("loaded process")
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
---@diagnostic disable lowercase-global
|
|
2539
|
-
function compute(base, req, opts)
|
|
2540
|
-
-- local _ao = require('.ao')
|
|
2541
|
-
local _process = require('.process')
|
|
2542
|
-
|
|
2543
|
-
ao.event(base.process)
|
|
2544
|
-
ao.event(req.body)
|
|
2545
|
-
local _results = _process.handle(req, base)
|
|
2546
|
-
base.results = {
|
|
2547
|
-
info = "hyper-aos",
|
|
2548
|
-
outbox = {},
|
|
2549
|
-
output = _results.Output
|
|
2550
|
-
}
|
|
2551
|
-
for i=1,#_results.Messages do
|
|
2552
|
-
base.results.outbox[tostring(i)] = _results.Messages[i]
|
|
2553
|
-
end
|
|
2554
|
-
return base
|
|
2555
|
-
end
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
print [[ _ ___ ____
|
|
2559
|
-
/ \ / _ \/ ___|
|
|
2560
|
-
/ _ \| | | \___ \
|
|
2561
|
-
/ ___ \ |_| |___) |
|
|
2562
|
-
/_/ \_\___/|____/
|
|
2563
|
-
]]
|