wao 0.3.1 → 0.4.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/accounts.js +12 -12
- package/cjs/aoconnect.js +410 -1475
- package/cjs/ar.js +1 -1
- package/cjs/armem.js +52 -0
- package/cjs/gql.js +393 -0
- package/cjs/index.js +7 -0
- package/cjs/tao.js +9 -9
- package/cjs/tar.js +279 -0
- package/cjs/test.js +57 -3
- package/cjs/utils.js +41 -1
- package/cjs/weavedrive.js +979 -0
- package/esm/accounts.js +36 -30
- package/esm/aoconnect.js +65 -808
- package/esm/ar.js +1 -1
- package/esm/armem.js +38 -0
- package/esm/gql.js +218 -0
- package/esm/index.js +2 -1
- package/esm/tao.js +7 -9
- package/esm/tar.js +98 -0
- package/esm/test.js +13 -2
- package/esm/utils.js +10 -0
- package/esm/weavedrive.js +709 -0
- package/package.json +1 -1
package/esm/aoconnect.js
CHANGED
|
@@ -1,764 +1,28 @@
|
|
|
1
|
-
let _txs = {}
|
|
2
|
-
|
|
3
|
-
import Arweave from "arweave"
|
|
4
|
-
|
|
5
|
-
const KB = 1024
|
|
6
|
-
const MB = KB * 1024
|
|
7
|
-
const CACHE_SZ = 32 * KB
|
|
8
|
-
const CHUNK_SZ = 128 * MB
|
|
9
|
-
const NOTIFY_SZ = 512 * MB
|
|
10
|
-
|
|
11
|
-
function WeaveDrive(mod, FS) {
|
|
12
|
-
return {
|
|
13
|
-
reset(fd) {
|
|
14
|
-
//console.log("WeaveDrive: Resetting fd: ", fd)
|
|
15
|
-
FS.streams[fd].node.position = 0
|
|
16
|
-
FS.streams[fd].node.cache = new Uint8Array(0)
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
joinUrl({ url, path }) {
|
|
20
|
-
if (!path) return url
|
|
21
|
-
if (path.startsWith("/"))
|
|
22
|
-
return this.joinUrl({ url, path: path.slice(1) })
|
|
23
|
-
|
|
24
|
-
url = new URL(url)
|
|
25
|
-
url.pathname += path
|
|
26
|
-
return url.toString()
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
async customFetch(path, options) {
|
|
30
|
-
txs[path] = true
|
|
31
|
-
/**
|
|
32
|
-
* mod.ARWEAVE may be a comma-delimited list of urls.
|
|
33
|
-
* So we parse it into an array that we sequentially consume
|
|
34
|
-
* using fetch, and return the first successful response.
|
|
35
|
-
*
|
|
36
|
-
* The first url is considered "primary". So if all urls fail
|
|
37
|
-
* to produce a successful response, then we return the primary's
|
|
38
|
-
* error response
|
|
39
|
-
*/
|
|
40
|
-
const urlList = mod.ARWEAVE.includes(",")
|
|
41
|
-
? mod.ARWEAVE.split(",").map(url => url.trim())
|
|
42
|
-
: [mod.ARWEAVE]
|
|
43
|
-
|
|
44
|
-
let p
|
|
45
|
-
for (const url of urlList) {
|
|
46
|
-
//txs[this.joinUrl({ url, path })] = true
|
|
47
|
-
const res = fetch(this.joinUrl({ url, path }), options)
|
|
48
|
-
if (await res.then(r => r.ok).catch(() => false)) return res
|
|
49
|
-
if (!p) p = res
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* None succeeded so fallback to the primary and accept
|
|
54
|
-
* whatever it returned
|
|
55
|
-
*/
|
|
56
|
-
return p
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
async create(id) {
|
|
60
|
-
var properties = { isDevice: false, contents: null }
|
|
61
|
-
|
|
62
|
-
if (!(await this.checkAdmissible(id))) {
|
|
63
|
-
//console.log("WeaveDrive: Arweave ID is not admissable! ", id)
|
|
64
|
-
return 0
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Create the file in the emscripten FS
|
|
68
|
-
|
|
69
|
-
// This check/mkdir was added for AOP 6 Boot loader because create is
|
|
70
|
-
// called first because were only loading Data, we needed to create
|
|
71
|
-
// the directory. See: https://github.com/permaweb/aos/issues/342
|
|
72
|
-
if (!FS.analyzePath("/data/").exists) {
|
|
73
|
-
FS.mkdir("/data/")
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
var node = FS.createFile("/", "data/" + id, properties, true, false)
|
|
77
|
-
// Set initial parameters
|
|
78
|
-
/*
|
|
79
|
-
var bytesLength = await this.customFetch(`/${id}`, {
|
|
80
|
-
method: "HEAD",
|
|
81
|
-
}).then(res => res.headers.get("Content-Length"))
|
|
82
|
-
*/
|
|
83
|
-
const bytesLength = _txs[id]
|
|
84
|
-
? new TextEncoder().encode(_txs[id]).length
|
|
85
|
-
: 100
|
|
86
|
-
node.total_size = Number(bytesLength)
|
|
87
|
-
node.cache = new Uint8Array(0)
|
|
88
|
-
node.position = 0
|
|
89
|
-
|
|
90
|
-
// Add a function that defers querying the file size until it is asked the first time.
|
|
91
|
-
Object.defineProperties(node, {
|
|
92
|
-
usedBytes: {
|
|
93
|
-
get: function () {
|
|
94
|
-
return bytesLength
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
// Now we have created the file in the emscripten FS, we can open it as a stream
|
|
100
|
-
var stream = FS.open("/data/" + id, "r")
|
|
101
|
-
|
|
102
|
-
//console.log("JS: Created file: ", id, " fd: ", stream.fd);
|
|
103
|
-
return stream
|
|
104
|
-
},
|
|
105
|
-
async createBlockHeader(id) {
|
|
106
|
-
const customFetch = this.customFetch
|
|
107
|
-
// todo: add a bunch of retries
|
|
108
|
-
async function retry(x) {
|
|
109
|
-
return new Promise(r => {
|
|
110
|
-
setTimeout(function () {
|
|
111
|
-
r(customFetch(`/block/height/${id}`))
|
|
112
|
-
}, x * 10000)
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
var result = await this.customFetch(`/block/height/${id}`)
|
|
116
|
-
.then(res => (!res.ok ? retry(1) : res))
|
|
117
|
-
.then(res => (!res.ok ? retry(2) : res))
|
|
118
|
-
.then(res => (!res.ok ? retry(3) : res))
|
|
119
|
-
.then(res => (!res.ok ? retry(4) : res))
|
|
120
|
-
.then(res => res.text())
|
|
121
|
-
|
|
122
|
-
var bytesLength = result.length
|
|
123
|
-
|
|
124
|
-
var node = FS.createDataFile(
|
|
125
|
-
"/",
|
|
126
|
-
"block/" + id,
|
|
127
|
-
Buffer.from(result, "utf-8"),
|
|
128
|
-
true,
|
|
129
|
-
false,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
var stream = FS.open("/block/" + id, "r")
|
|
133
|
-
return stream
|
|
134
|
-
},
|
|
135
|
-
async createTxHeader(id) {
|
|
136
|
-
const customFetch = this.customFetch
|
|
137
|
-
async function toAddress(owner) {
|
|
138
|
-
return Arweave.utils.bufferTob64Url(
|
|
139
|
-
await Arweave.crypto.hash(Arweave.utils.b64UrlToBuffer(owner)),
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
async function retry(x) {
|
|
143
|
-
return new Promise(r => {
|
|
144
|
-
setTimeout(function () {
|
|
145
|
-
r(customFetch(`/tx/${id}`))
|
|
146
|
-
}, x * 10000)
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
// todo: add a bunch of retries
|
|
150
|
-
var result = await this.customFetch(`/tx/${id}`)
|
|
151
|
-
.then(res => (!res.ok ? retry(1) : res))
|
|
152
|
-
.then(res => (!res.ok ? retry(2) : res))
|
|
153
|
-
.then(res => (!res.ok ? retry(3) : res))
|
|
154
|
-
.then(res => (!res.ok ? retry(4) : res))
|
|
155
|
-
.then(res => res.json())
|
|
156
|
-
.then(async entry => ({
|
|
157
|
-
...entry,
|
|
158
|
-
ownerAddress: await toAddress(entry.owner),
|
|
159
|
-
}))
|
|
160
|
-
//.then(x => (console.error(x), x))
|
|
161
|
-
.then(x => JSON.stringify(x))
|
|
162
|
-
|
|
163
|
-
var node = FS.createDataFile(
|
|
164
|
-
"/",
|
|
165
|
-
"tx/" + id,
|
|
166
|
-
Buffer.from(result, "utf-8"),
|
|
167
|
-
true,
|
|
168
|
-
false,
|
|
169
|
-
)
|
|
170
|
-
var stream = FS.open("/tx/" + id, "r")
|
|
171
|
-
return stream
|
|
172
|
-
},
|
|
173
|
-
async createDataItemTxHeader(id) {
|
|
174
|
-
const gqlQuery = this.gqlQuery
|
|
175
|
-
var GET_TRANSACTION_QUERY = `
|
|
176
|
-
query GetTransactions ($transactionIds: [ID!]!) {
|
|
177
|
-
transactions(ids: $transactionIds) {
|
|
178
|
-
edges {
|
|
179
|
-
node {
|
|
180
|
-
id
|
|
181
|
-
anchor
|
|
182
|
-
data {
|
|
183
|
-
size
|
|
184
|
-
}
|
|
185
|
-
signature
|
|
186
|
-
recipient
|
|
187
|
-
owner {
|
|
188
|
-
address
|
|
189
|
-
key
|
|
190
|
-
}
|
|
191
|
-
fee {
|
|
192
|
-
ar
|
|
193
|
-
winston
|
|
194
|
-
}
|
|
195
|
-
quantity {
|
|
196
|
-
winston
|
|
197
|
-
ar
|
|
198
|
-
}
|
|
199
|
-
tags {
|
|
200
|
-
name
|
|
201
|
-
value
|
|
202
|
-
}
|
|
203
|
-
bundledIn {
|
|
204
|
-
id
|
|
205
|
-
}
|
|
206
|
-
block {
|
|
207
|
-
id
|
|
208
|
-
timestamp
|
|
209
|
-
height
|
|
210
|
-
previous
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}`
|
|
216
|
-
var variables = { transactionIds: [id] }
|
|
217
|
-
async function retry(x) {
|
|
218
|
-
return new Promise(r => {
|
|
219
|
-
setTimeout(function () {
|
|
220
|
-
r(gqlQuery(GET_TRANSACTION_QUERY, variables))
|
|
221
|
-
}, x * 10000)
|
|
222
|
-
})
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const gqlExists = await this.gqlExists()
|
|
226
|
-
if (!gqlExists) {
|
|
227
|
-
return "GQL Not Found!"
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// todo: add a bunch of retries
|
|
231
|
-
var result = await this.gqlQuery(GET_TRANSACTION_QUERY, variables)
|
|
232
|
-
.then(res => (!res.ok ? retry(1) : res))
|
|
233
|
-
.then(res => (!res.ok ? retry(2) : res))
|
|
234
|
-
.then(res => (!res.ok ? retry(3) : res))
|
|
235
|
-
.then(res => (!res.ok ? retry(4) : res))
|
|
236
|
-
.then(res => res.json())
|
|
237
|
-
.then(res => {
|
|
238
|
-
return res?.data?.transactions?.edges?.[0]?.node
|
|
239
|
-
? res.data.transactions.edges[0].node
|
|
240
|
-
: "No results"
|
|
241
|
-
})
|
|
242
|
-
.then(async entry => {
|
|
243
|
-
return typeof entry == "string"
|
|
244
|
-
? entry
|
|
245
|
-
: {
|
|
246
|
-
format: 3,
|
|
247
|
-
...entry,
|
|
248
|
-
}
|
|
249
|
-
})
|
|
250
|
-
.then(x => {
|
|
251
|
-
return typeof x == "string" ? x : JSON.stringify(x)
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
if (result === "No results") {
|
|
255
|
-
return result
|
|
256
|
-
}
|
|
257
|
-
FS.createDataFile(
|
|
258
|
-
"/",
|
|
259
|
-
"tx2/" + id,
|
|
260
|
-
Buffer.from(result, "utf-8"),
|
|
261
|
-
true,
|
|
262
|
-
false,
|
|
263
|
-
)
|
|
264
|
-
var stream = FS.open("/tx2/" + id, "r")
|
|
265
|
-
|
|
266
|
-
return stream
|
|
267
|
-
},
|
|
268
|
-
async open(filename) {
|
|
269
|
-
const pathCategory = filename.split("/")[1]
|
|
270
|
-
const id = filename.split("/")[2]
|
|
271
|
-
console.log("JS: Opening ID: ", id)
|
|
272
|
-
if (pathCategory === "tx") {
|
|
273
|
-
FS.createPath("/", "tx", true, false)
|
|
274
|
-
if (FS.analyzePath(filename).exists) {
|
|
275
|
-
var stream = FS.open(filename, "r")
|
|
276
|
-
if (stream.fd) return stream.fd
|
|
277
|
-
return 0
|
|
278
|
-
} else {
|
|
279
|
-
const stream = await this.createTxHeader(id)
|
|
280
|
-
return stream.fd
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (pathCategory === "tx2") {
|
|
284
|
-
FS.createPath("/", "tx2", true, false)
|
|
285
|
-
if (FS.analyzePath(filename).exists) {
|
|
286
|
-
var stream = FS.open(filename, "r")
|
|
287
|
-
if (stream.fd) return stream.fd
|
|
288
|
-
return 0
|
|
289
|
-
} else {
|
|
290
|
-
const stream = await this.createDataItemTxHeader(id)
|
|
291
|
-
if (stream.fd) return stream.fd
|
|
292
|
-
return 0
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
if (pathCategory === "block") {
|
|
296
|
-
FS.createPath("/", "block", true, false)
|
|
297
|
-
if (FS.analyzePath(filename).exists) {
|
|
298
|
-
var stream = FS.open(filename, "r")
|
|
299
|
-
if (stream.fd) return stream.fd
|
|
300
|
-
return 0
|
|
301
|
-
} else {
|
|
302
|
-
const stream = await this.createBlockHeader(id)
|
|
303
|
-
return stream.fd
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (pathCategory === "data") {
|
|
307
|
-
if (FS.analyzePath(filename).exists) {
|
|
308
|
-
var stream = FS.open(filename, "r")
|
|
309
|
-
if (stream.fd) return stream.fd
|
|
310
|
-
console.log("JS: File not found: ", filename)
|
|
311
|
-
return 0
|
|
312
|
-
} else {
|
|
313
|
-
//console.log("JS: Open => Creating file: ", id);
|
|
314
|
-
const stream = await this.create(id)
|
|
315
|
-
//console.log("JS: Open => Created file: ", id, " fd: ", stream.fd);
|
|
316
|
-
return stream.fd
|
|
317
|
-
}
|
|
318
|
-
} else if (pathCategory === "headers") {
|
|
319
|
-
console.log("Header access not implemented yet.")
|
|
320
|
-
return 0
|
|
321
|
-
} else {
|
|
322
|
-
console.log("JS: Invalid path category: ", pathCategory)
|
|
323
|
-
return 0
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
async read(fd, raw_dst_ptr, raw_length) {
|
|
327
|
-
// Note: The length and dst_ptr are 53 bit integers in JS, so this _should_ be ok into a large memspace.
|
|
328
|
-
var to_read = Number(raw_length)
|
|
329
|
-
var dst_ptr = Number(raw_dst_ptr)
|
|
330
|
-
|
|
331
|
-
var stream = 0
|
|
332
|
-
for (var i = 0; i < FS.streams.length; i++) {
|
|
333
|
-
if (FS.streams[i].fd === fd) {
|
|
334
|
-
stream = FS.streams[i]
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// read block headers
|
|
338
|
-
if (stream.path.includes("/block")) {
|
|
339
|
-
mod.HEAP8.set(stream.node.contents.subarray(0, to_read), dst_ptr)
|
|
340
|
-
return to_read
|
|
341
|
-
}
|
|
342
|
-
// read tx headers
|
|
343
|
-
if (stream.path.includes("/tx")) {
|
|
344
|
-
mod.HEAP8.set(stream.node.contents.subarray(0, to_read), dst_ptr)
|
|
345
|
-
return to_read
|
|
346
|
-
}
|
|
347
|
-
// Satisfy what we can with the cache first
|
|
348
|
-
var bytes_read = this.readFromCache(stream, dst_ptr, to_read)
|
|
349
|
-
stream.position += bytes_read
|
|
350
|
-
stream.lastReadPosition = stream.position
|
|
351
|
-
dst_ptr += bytes_read
|
|
352
|
-
to_read -= bytes_read
|
|
353
|
-
|
|
354
|
-
// Return if we have satisfied the request
|
|
355
|
-
if (to_read === 0) {
|
|
356
|
-
//console.log("WeaveDrive: Satisfied request with cache. Returning...")
|
|
357
|
-
return bytes_read
|
|
358
|
-
}
|
|
359
|
-
//console.log("WeaveDrive: Read from cache: ", bytes_read, " Remaining to read: ", to_read)
|
|
360
|
-
|
|
361
|
-
const chunk_download_sz = Math.max(to_read, CACHE_SZ)
|
|
362
|
-
const to = Math.min(
|
|
363
|
-
stream.node.total_size,
|
|
364
|
-
stream.position + chunk_download_sz,
|
|
365
|
-
)
|
|
366
|
-
//console.log("WeaveDrive: fd: ", fd, " Read length: ", to_read, " Reading ahead:", to - to_read - stream.position)
|
|
367
|
-
|
|
368
|
-
// Fetch with streaming
|
|
369
|
-
/*
|
|
370
|
-
const response = await this.customFetch(`/${stream.node.name}`, {
|
|
371
|
-
method: "GET",
|
|
372
|
-
redirect: "follow",
|
|
373
|
-
headers: { Range: `bytes=${stream.position}-${to}` },
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
const reader = response.body.getReader()
|
|
377
|
-
*/
|
|
378
|
-
const data = new TextEncoder().encode(_txs[stream.node.name] ?? "")
|
|
379
|
-
|
|
380
|
-
// Extract the Range header to determine the start and end of the requested chunk
|
|
381
|
-
const start = 0
|
|
382
|
-
const end = data.length
|
|
383
|
-
|
|
384
|
-
// Create a ReadableStream for the requested chunk
|
|
385
|
-
const chunk = data.subarray(start, end)
|
|
386
|
-
const response = new Response(
|
|
387
|
-
new ReadableStream({
|
|
388
|
-
start(controller) {
|
|
389
|
-
controller.enqueue(chunk) // Push the chunk to the stream
|
|
390
|
-
controller.close() // Close the stream when done
|
|
391
|
-
},
|
|
392
|
-
}),
|
|
393
|
-
{
|
|
394
|
-
headers: { "Content-Length": chunk.length.toString() },
|
|
395
|
-
},
|
|
396
|
-
)
|
|
397
|
-
const reader = response.body.getReader()
|
|
398
|
-
var bytes_until_cache = CHUNK_SZ
|
|
399
|
-
var bytes_until_notify = NOTIFY_SZ
|
|
400
|
-
var downloaded_bytes = 0
|
|
401
|
-
var cache_chunks = []
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
while (true) {
|
|
405
|
-
const { done, value: chunk_bytes } = await reader.read()
|
|
406
|
-
if (done) break
|
|
407
|
-
// Update the number of downloaded bytes to be _all_, not just the write length
|
|
408
|
-
downloaded_bytes += chunk_bytes.length
|
|
409
|
-
bytes_until_cache -= chunk_bytes.length
|
|
410
|
-
bytes_until_notify -= chunk_bytes.length
|
|
411
|
-
|
|
412
|
-
// Write bytes from the chunk and update the pointer if necessary
|
|
413
|
-
const write_length = Math.min(chunk_bytes.length, to_read)
|
|
414
|
-
if (write_length > 0) {
|
|
415
|
-
//console.log("WeaveDrive: Writing: ", write_length, " bytes to: ", dst_ptr)
|
|
416
|
-
mod.HEAP8.set(chunk_bytes.subarray(0, write_length), dst_ptr)
|
|
417
|
-
dst_ptr += write_length
|
|
418
|
-
bytes_read += write_length
|
|
419
|
-
stream.position += write_length
|
|
420
|
-
to_read -= write_length
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (to_read == 0) {
|
|
424
|
-
// Add excess bytes to our cache
|
|
425
|
-
const chunk_to_cache = chunk_bytes.subarray(write_length)
|
|
426
|
-
//console.log("WeaveDrive: Cacheing excess: ", chunk_to_cache.length)
|
|
427
|
-
cache_chunks.push(chunk_to_cache)
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (bytes_until_cache <= 0) {
|
|
431
|
-
console.log("WeaveDrive: Chunk size reached. Compressing cache...")
|
|
432
|
-
stream.node.cache = this.addChunksToCache(
|
|
433
|
-
stream.node.cache,
|
|
434
|
-
cache_chunks,
|
|
435
|
-
)
|
|
436
|
-
cache_chunks = []
|
|
437
|
-
bytes_until_cache = CHUNK_SZ
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (bytes_until_notify <= 0) {
|
|
441
|
-
console.log(
|
|
442
|
-
"WeaveDrive: Downloaded: ",
|
|
443
|
-
(downloaded_bytes / stream.node.total_size) * 100,
|
|
444
|
-
"%",
|
|
445
|
-
)
|
|
446
|
-
bytes_until_notify = NOTIFY_SZ
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
} catch (error) {
|
|
450
|
-
console.error("WeaveDrive: Error reading the stream: ", error)
|
|
451
|
-
} finally {
|
|
452
|
-
reader.releaseLock()
|
|
453
|
-
}
|
|
454
|
-
// If we have no cache, or we have not satisfied the full request, we need to download the rest
|
|
455
|
-
// Rebuild the cache from the new cache chunks
|
|
456
|
-
stream.node.cache = this.addChunksToCache(stream.node.cache, cache_chunks)
|
|
457
|
-
|
|
458
|
-
// Update the last read position
|
|
459
|
-
stream.lastReadPosition = stream.position
|
|
460
|
-
return bytes_read
|
|
461
|
-
},
|
|
462
|
-
close(fd) {
|
|
463
|
-
var stream = 0
|
|
464
|
-
for (var i = 0; i < FS.streams.length; i++) {
|
|
465
|
-
if (FS.streams[i].fd === fd) {
|
|
466
|
-
stream = FS.streams[i]
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
FS.close(stream)
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
// Readahead cache functions
|
|
473
|
-
readFromCache(stream, dst_ptr, length) {
|
|
474
|
-
// Check if the cache has been invalidated by a seek
|
|
475
|
-
if (stream.lastReadPosition !== stream.position) {
|
|
476
|
-
//console.log("WeaveDrive: Invalidating cache for fd: ", stream.fd, " Current pos: ", stream.position, " Last read pos: ", stream.lastReadPosition)
|
|
477
|
-
stream.node.cache = new Uint8Array(0)
|
|
478
|
-
return 0
|
|
479
|
-
}
|
|
480
|
-
// Calculate the bytes of the request that can be satisfied with the cache
|
|
481
|
-
var cache_part_length = Math.min(length, stream.node.cache.length)
|
|
482
|
-
var cache_part = stream.node.cache.subarray(0, cache_part_length)
|
|
483
|
-
mod.HEAP8.set(cache_part, dst_ptr)
|
|
484
|
-
// Set the new cache to the remainder of the unused cache and update pointers
|
|
485
|
-
stream.node.cache = stream.node.cache.subarray(cache_part_length)
|
|
486
|
-
|
|
487
|
-
return cache_part_length
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
addChunksToCache(old_cache, chunks) {
|
|
491
|
-
// Make a new cache array of the old cache length + the sum of the chunk lengths, capped by the max cache size
|
|
492
|
-
var new_cache_length = Math.min(
|
|
493
|
-
old_cache.length + chunks.reduce((acc, chunk) => acc + chunk.length, 0),
|
|
494
|
-
CACHE_SZ,
|
|
495
|
-
)
|
|
496
|
-
var new_cache = new Uint8Array(new_cache_length)
|
|
497
|
-
// Copy the old cache to the new cache
|
|
498
|
-
new_cache.set(old_cache, 0)
|
|
499
|
-
// Load the cache chunks into the new cache
|
|
500
|
-
var current_offset = old_cache.length
|
|
501
|
-
for (let chunk of chunks) {
|
|
502
|
-
if (current_offset < new_cache_length) {
|
|
503
|
-
new_cache.set(
|
|
504
|
-
chunk.subarray(0, new_cache_length - current_offset),
|
|
505
|
-
current_offset,
|
|
506
|
-
)
|
|
507
|
-
current_offset += chunk.length
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
return new_cache
|
|
511
|
-
},
|
|
512
|
-
|
|
513
|
-
// General helpder functions
|
|
514
|
-
async checkAdmissible(ID) {
|
|
515
|
-
if (mod.mode && mod.mode == "test") {
|
|
516
|
-
// CAUTION: If the module is initiated with `mode = test` we don't check availability.
|
|
517
|
-
return true
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// Check if we are attempting to load the On-Boot id, if so allow it
|
|
521
|
-
// this was added for AOP 6 Boot loader See: https://github.com/permaweb/aos/issues/342
|
|
522
|
-
const bootTag = this.getTagValue("On-Boot", mod.spawn.tags)
|
|
523
|
-
if (bootTag && bootTag === ID) return true
|
|
524
|
-
|
|
525
|
-
// Check that this module or process set the WeaveDrive tag on spawn
|
|
526
|
-
const blockHeight = mod.blockHeight
|
|
527
|
-
const moduleExtensions = this.getTagValues("Extension", mod.module.tags)
|
|
528
|
-
const moduleHasWeaveDrive = moduleExtensions.includes("WeaveDrive")
|
|
529
|
-
const processExtensions = this.getTagValues("Extension", mod.spawn.tags)
|
|
530
|
-
const processHasWeaveDrive =
|
|
531
|
-
moduleHasWeaveDrive || processExtensions.includes("WeaveDrive")
|
|
532
|
-
|
|
533
|
-
if (!processHasWeaveDrive) {
|
|
534
|
-
console.log(
|
|
535
|
-
"WeaveDrive: Process tried to call WeaveDrive, but extension not set!",
|
|
536
|
-
)
|
|
537
|
-
return false
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const modes = ["Assignments", "Individual", "Library"]
|
|
541
|
-
// Get the Availability-Type from the spawned process's Module or Process item
|
|
542
|
-
// First check the module for its defaults
|
|
543
|
-
const moduleAvailabilityType = this.getTagValue(
|
|
544
|
-
"Availability-Type",
|
|
545
|
-
mod.module.tags,
|
|
546
|
-
)
|
|
547
|
-
const moduleMode = moduleAvailabilityType
|
|
548
|
-
? moduleAvailabilityType
|
|
549
|
-
: "Assignments" // Default to assignments
|
|
550
|
-
|
|
551
|
-
// Now check the process's spawn item. These settings override Module item settings.
|
|
552
|
-
const processAvailabilityType = this.getTagValue(
|
|
553
|
-
"Availability-Type",
|
|
554
|
-
mod.spawn.tags,
|
|
555
|
-
)
|
|
556
|
-
const processMode = processAvailabilityType
|
|
557
|
-
? processAvailabilityType
|
|
558
|
-
: moduleMode
|
|
559
|
-
|
|
560
|
-
if (!modes.includes(processMode)) {
|
|
561
|
-
throw `Unsupported WeaveDrive mode: ${processMode}`
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const attestors = this.serializeStringArr(
|
|
565
|
-
[
|
|
566
|
-
this.getTagValue("Scheduler", mod.spawn.tags),
|
|
567
|
-
...this.getTagValues("Attestor", mod.spawn.tags),
|
|
568
|
-
].filter(t => !!t),
|
|
569
|
-
)
|
|
570
|
-
|
|
571
|
-
// Init a set of GraphQL queries to run in order to find a valid attestation
|
|
572
|
-
// Every WeaveDrive process has at least the "Assignments" availability check form.
|
|
573
|
-
const assignmentsHaveID = await this.queryHasResult(
|
|
574
|
-
`query {
|
|
575
|
-
transactions(
|
|
576
|
-
owners: ${attestors},
|
|
577
|
-
block: {min: 0, max: ${blockHeight}},
|
|
578
|
-
tags: [
|
|
579
|
-
{ name: "Type", values: ["Attestation"] },
|
|
580
|
-
{ name: "Message", values: ["${ID}"]}
|
|
581
|
-
{ name: "Data-Protocol", values: ["ao"] },
|
|
582
|
-
]
|
|
583
|
-
)
|
|
584
|
-
{
|
|
585
|
-
edges {
|
|
586
|
-
node {
|
|
587
|
-
tags {
|
|
588
|
-
name
|
|
589
|
-
value
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}`,
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
if (assignmentsHaveID) {
|
|
598
|
-
return true
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
if (processMode == "Individual") {
|
|
602
|
-
const individualsHaveID = await this.queryHasResult(
|
|
603
|
-
`query {
|
|
604
|
-
transactions(
|
|
605
|
-
owners: ${attestors},
|
|
606
|
-
block: {min: 0, max: ${blockHeight}},
|
|
607
|
-
tags: [
|
|
608
|
-
{ name: "Type", values: ["Available"]},
|
|
609
|
-
{ name: "ID", values: ["${ID}"]}
|
|
610
|
-
{ name: "Data-Protocol", values: ["WeaveDrive"] },
|
|
611
|
-
]
|
|
612
|
-
)
|
|
613
|
-
{
|
|
614
|
-
edges {
|
|
615
|
-
node {
|
|
616
|
-
tags {
|
|
617
|
-
name
|
|
618
|
-
value
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
}`,
|
|
624
|
-
)
|
|
625
|
-
|
|
626
|
-
if (individualsHaveID) {
|
|
627
|
-
return true
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// Halt message processing if the process requires Library mode.
|
|
632
|
-
// This should signal 'Cannot Process' to the CU, not that the message itself is
|
|
633
|
-
// invalid. Subsequently, the CU should not be slashable for saying that the process
|
|
634
|
-
// execution failed on this message. The CU must also not continue to execute further
|
|
635
|
-
// messages on this process. Attesting to them would be slashable, as the state would
|
|
636
|
-
// be incorrect.
|
|
637
|
-
if (processMode == "Library") {
|
|
638
|
-
throw "This WeaveDrive implementation does not support Library attestations yet!"
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
return false
|
|
642
|
-
},
|
|
643
|
-
|
|
644
|
-
serializeStringArr(arr = []) {
|
|
645
|
-
return `[${arr.map(s => `"${s}"`).join(", ")}]`
|
|
646
|
-
},
|
|
647
|
-
|
|
648
|
-
getTagValues(key, tags) {
|
|
649
|
-
var values = []
|
|
650
|
-
for (i = 0; i < tags.length; i++) {
|
|
651
|
-
if (tags[i].name == key) {
|
|
652
|
-
values.push(tags[i].value)
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return values
|
|
656
|
-
},
|
|
657
|
-
|
|
658
|
-
getTagValue(key, tags) {
|
|
659
|
-
const values = this.getTagValues(key, tags)
|
|
660
|
-
return values.pop()
|
|
661
|
-
},
|
|
662
|
-
|
|
663
|
-
async queryHasResult(query, variables) {
|
|
664
|
-
const json = await this.gqlQuery(query, variables).then(res => res.json())
|
|
665
|
-
|
|
666
|
-
return !!json?.data?.transactions?.edges?.length
|
|
667
|
-
},
|
|
668
|
-
|
|
669
|
-
async gqlExists() {
|
|
670
|
-
const query = `query {
|
|
671
|
-
transactions(
|
|
672
|
-
first: 1
|
|
673
|
-
) {
|
|
674
|
-
pageInfo {
|
|
675
|
-
hasNextPage
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
`
|
|
680
|
-
|
|
681
|
-
const gqlExists = await this.gqlQuery(query, {}).then(res => res.ok)
|
|
682
|
-
return gqlExists
|
|
683
|
-
},
|
|
684
|
-
|
|
685
|
-
async gqlQuery(query, variables) {
|
|
686
|
-
const options = {
|
|
687
|
-
method: "POST",
|
|
688
|
-
body: JSON.stringify({ query, variables }),
|
|
689
|
-
headers: { "Content-Type": "application/json" },
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
return this.customFetch("graphql", options)
|
|
693
|
-
},
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
1
|
import { DataItem } from "warp-arbundles"
|
|
698
2
|
import base64url from "base64url"
|
|
3
|
+
import {
|
|
4
|
+
tags,
|
|
5
|
+
action,
|
|
6
|
+
tag,
|
|
7
|
+
buildTags,
|
|
8
|
+
isJSON,
|
|
9
|
+
jsonToStr,
|
|
10
|
+
dirname,
|
|
11
|
+
} from "./utils.js"
|
|
12
|
+
import ArMem from "./armem.js"
|
|
13
|
+
import weavedrive from "./weavedrive.js"
|
|
699
14
|
import AoLoader from "@permaweb/ao-loader"
|
|
700
15
|
import { readFileSync } from "fs"
|
|
701
16
|
import { resolve } from "path"
|
|
17
|
+
import { scheduler, mu, su, cu, acc } from "./test.js"
|
|
702
18
|
import { is, clone, fromPairs, map, mergeLeft, isNil } from "ramda"
|
|
703
|
-
import
|
|
704
|
-
import { tags, action, tag, buildTags } from "./utils.js"
|
|
705
|
-
|
|
706
|
-
function isJSON(obj) {
|
|
707
|
-
if (obj === null || obj === undefined) return false
|
|
708
|
-
if (
|
|
709
|
-
typeof obj !== "object" ||
|
|
710
|
-
obj instanceof Buffer ||
|
|
711
|
-
obj instanceof ArrayBuffer ||
|
|
712
|
-
Array.isArray(obj)
|
|
713
|
-
) {
|
|
714
|
-
return false
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
try {
|
|
718
|
-
const str = JSON.stringify(obj)
|
|
719
|
-
const parsed = JSON.parse(str)
|
|
720
|
-
const isjson = typeof parsed === "object" && parsed !== null
|
|
721
|
-
return isjson ? str : false
|
|
722
|
-
} catch (e) {
|
|
723
|
-
return false
|
|
724
|
-
}
|
|
725
|
-
}
|
|
19
|
+
import AR from "./tar.js"
|
|
726
20
|
|
|
727
|
-
const
|
|
728
|
-
|
|
21
|
+
export const connect = mem => {
|
|
22
|
+
mem ??= new ArMem()
|
|
23
|
+
const ar = new AR({ mem })
|
|
24
|
+
const WeaveDrive = new weavedrive(ar).drive
|
|
729
25
|
|
|
730
|
-
const dirname = async () =>
|
|
731
|
-
typeof __dirname != "undefined"
|
|
732
|
-
? __dirname
|
|
733
|
-
: (await import("./dirname.js")).default
|
|
734
|
-
|
|
735
|
-
export const acc = accounts.users
|
|
736
|
-
export const mu = accounts.mu
|
|
737
|
-
const scheduler = "GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA"
|
|
738
|
-
let env = {}
|
|
739
|
-
|
|
740
|
-
export const connect = () => {
|
|
741
|
-
let wasms = {
|
|
742
|
-
"Do_Uc2Sju_ffp6Ev0AnLVdPtot15rvMjP-a9VVaA5fM": {
|
|
743
|
-
file: "aos2_0_1",
|
|
744
|
-
format: "wasm64-unknown-emscripten-draft_2024_02_15",
|
|
745
|
-
},
|
|
746
|
-
cNlipBptaF9JeFAf4wUmpi43EojNanIBos3EfNrEOWo: {
|
|
747
|
-
file: "aos_1",
|
|
748
|
-
format: "wasm64-unknown-emscripten-draft_2024_02_15",
|
|
749
|
-
},
|
|
750
|
-
ghSkge2sIUD_F00ym5sEimC63BDBuBrq4b5OcwxOjiw: {
|
|
751
|
-
file: "sqlite",
|
|
752
|
-
format: "wasm64-unknown-emscripten-draft_2024_02_15",
|
|
753
|
-
},
|
|
754
|
-
}
|
|
755
|
-
let modules = {
|
|
756
|
-
aos2_0_1: "Do_Uc2Sju_ffp6Ev0AnLVdPtot15rvMjP-a9VVaA5fM",
|
|
757
|
-
aos1: "cNlipBptaF9JeFAf4wUmpi43EojNanIBos3EfNrEOWo",
|
|
758
|
-
sqlite: "ghSkge2sIUD_F00ym5sEimC63BDBuBrq4b5OcwxOjiw",
|
|
759
|
-
}
|
|
760
|
-
let modmap = {}
|
|
761
|
-
let msgs = {}
|
|
762
26
|
const transform = input => {
|
|
763
27
|
const output = { Tags: [] }
|
|
764
28
|
if (input.Data) output.Data = input.Data
|
|
@@ -817,16 +81,6 @@ export const connect = () => {
|
|
|
817
81
|
}
|
|
818
82
|
}
|
|
819
83
|
|
|
820
|
-
const parse = async opt => {
|
|
821
|
-
const item = await opt.signer({ data: opt.data ?? "", tags: opt.tags })
|
|
822
|
-
const rowner = new DataItem(item.raw).rawOwner
|
|
823
|
-
const hashBuffer = Buffer.from(
|
|
824
|
-
await crypto.subtle.digest("SHA-256", rowner),
|
|
825
|
-
)
|
|
826
|
-
const owner = base64url.encode(hashBuffer)
|
|
827
|
-
return { id: item.id, owner }
|
|
828
|
-
}
|
|
829
|
-
|
|
830
84
|
const postModule = async ({ data, tags = {}, signer }) => {
|
|
831
85
|
const t = mergeLeft(tags, {
|
|
832
86
|
"Data-Protocol": "ao",
|
|
@@ -838,42 +92,47 @@ export const connect = () => {
|
|
|
838
92
|
"Memory-Limit": "1-gb",
|
|
839
93
|
"Compute-Limit": "9000000000000",
|
|
840
94
|
})
|
|
841
|
-
const _tags = buildTags(t)
|
|
842
|
-
const { id, owner } = await
|
|
95
|
+
const _tags = buildTags(null, t)
|
|
96
|
+
const { id, owner } = await ar.dataitem({ tags: _tags, data, signer })
|
|
97
|
+
await ar.post({ data, signer, tags: t })
|
|
843
98
|
const handle = await AoLoader(data, {
|
|
844
99
|
format: t["Module-Format"],
|
|
845
100
|
mode: "test",
|
|
846
101
|
WeaveDrive,
|
|
847
102
|
})
|
|
848
|
-
modmap[id] = { handle, id }
|
|
103
|
+
mem.modmap[id] = { handle, id }
|
|
849
104
|
return id
|
|
850
105
|
}
|
|
851
106
|
|
|
852
107
|
const spawn = async (opt = {}) => {
|
|
853
108
|
if (!opt.module) throw Error("module missing")
|
|
854
109
|
if (!opt.scheduler) throw Error("scheduler missing")
|
|
855
|
-
let mod = opt.module ?? modules["aos2_0_1"]
|
|
856
|
-
if (!modmap[mod] && wasms[mod]) {
|
|
110
|
+
let mod = opt.module ?? mem.modules["aos2_0_1"]
|
|
111
|
+
if (!mem.modmap[mod] && mem.wasms[mod]) {
|
|
857
112
|
const __dirname = await dirname()
|
|
858
113
|
const wasm = readFileSync(
|
|
859
|
-
resolve(__dirname, `lua/${wasms[mod].file}.wasm`),
|
|
114
|
+
resolve(__dirname, `lua/${mem.wasms[mod].file}.wasm`),
|
|
860
115
|
)
|
|
861
116
|
const handle = await AoLoader(wasm, {
|
|
862
|
-
format: wasms[mod].format,
|
|
117
|
+
format: mem.wasms[mod].format,
|
|
863
118
|
mode: "test",
|
|
864
119
|
WeaveDrive,
|
|
865
120
|
})
|
|
866
|
-
modmap[mod] = { handle, id: mod }
|
|
121
|
+
mem.modmap[mod] = { handle, id: mod }
|
|
867
122
|
}
|
|
868
123
|
if (!mod) throw Error("module not found")
|
|
869
|
-
const _module = modmap[mod]
|
|
124
|
+
const _module = mem.modmap[mod]
|
|
870
125
|
let ex = false
|
|
871
126
|
opt.tags ??= []
|
|
872
127
|
for (let v of opt.tags) if (v.name === "Type") ex = true
|
|
873
128
|
if (!ex) opt.tags.push({ name: "Type", value: "Process" })
|
|
874
|
-
const { id, owner } = await
|
|
129
|
+
const { id, owner, item } = await ar.dataitem({
|
|
130
|
+
data: opt.data,
|
|
131
|
+
signer: opt.signer,
|
|
132
|
+
tags: tags(opt.tags),
|
|
133
|
+
})
|
|
134
|
+
await ar.postItem(item, su.jwk)
|
|
875
135
|
const _tags = tags(opt.tags)
|
|
876
|
-
_txs[id] = opt.data ?? null
|
|
877
136
|
let res = null
|
|
878
137
|
let memory = null
|
|
879
138
|
let p = {
|
|
@@ -891,7 +150,7 @@ export const connect = () => {
|
|
|
891
150
|
if (_tags["On-Boot"]) {
|
|
892
151
|
let data = ""
|
|
893
152
|
if (_tags["On-Boot"] === "Data") data = opt.data ?? ""
|
|
894
|
-
else data = msgs[_tags["On-Boot"]]?.data ?? ""
|
|
153
|
+
else data = mem.msgs[_tags["On-Boot"]]?.data ?? ""
|
|
895
154
|
let msg = genMsg(p, data, opt.tags, owner, mu.addr, true)
|
|
896
155
|
const _env = genEnv({
|
|
897
156
|
pid: p.id,
|
|
@@ -908,8 +167,8 @@ export const connect = () => {
|
|
|
908
167
|
} else {
|
|
909
168
|
p.height += 1
|
|
910
169
|
}
|
|
911
|
-
msgs[id] = opt
|
|
912
|
-
env[id] = p
|
|
170
|
+
mem.msgs[id] = opt
|
|
171
|
+
mem.env[id] = p
|
|
913
172
|
if (_tags["Cron-Interval"]) {
|
|
914
173
|
let [num, unit] = _tags["Cron-Interval"].split("-")
|
|
915
174
|
let int = 0
|
|
@@ -942,16 +201,21 @@ export const connect = () => {
|
|
|
942
201
|
cronTags.push({ name: k.replace(/Cron-Tag-/, ""), value: _tags[k] })
|
|
943
202
|
}
|
|
944
203
|
}
|
|
945
|
-
env[id].cronTags = cronTags
|
|
946
|
-
env[id].span = int
|
|
204
|
+
mem.env[id].cronTags = cronTags
|
|
205
|
+
mem.env[id].span = int
|
|
947
206
|
}
|
|
948
207
|
return id
|
|
949
208
|
}
|
|
950
209
|
|
|
951
210
|
const assign = async opt => {
|
|
952
|
-
const p = env[opt.process]
|
|
953
|
-
let _opt = clone(msgs[opt.message])
|
|
954
|
-
const { id, owner } = await
|
|
211
|
+
const p = mem.env[opt.process]
|
|
212
|
+
let _opt = clone(mem.msgs[opt.message])
|
|
213
|
+
const { id, owner, item } = await ar.dataitem({
|
|
214
|
+
data: _opt.data,
|
|
215
|
+
signer: _opt.signer,
|
|
216
|
+
tags: tags(_opt.tags),
|
|
217
|
+
})
|
|
218
|
+
await ar.postItem(item, su.jwk)
|
|
955
219
|
try {
|
|
956
220
|
const msg = genMsg(
|
|
957
221
|
p,
|
|
@@ -972,9 +236,9 @@ export const connect = () => {
|
|
|
972
236
|
p.res[id] = res
|
|
973
237
|
p.results.push(id)
|
|
974
238
|
p.txs.unshift({ id: id, ..._opt })
|
|
975
|
-
msgs[id] = _opt
|
|
239
|
+
mem.msgs[id] = _opt
|
|
976
240
|
for (const v of res.Messages ?? []) {
|
|
977
|
-
if (env[v.Target]) {
|
|
241
|
+
if (mem.env[v.Target]) {
|
|
978
242
|
await message({
|
|
979
243
|
process: v.Target,
|
|
980
244
|
tags: v.Tags,
|
|
@@ -992,12 +256,18 @@ export const connect = () => {
|
|
|
992
256
|
}
|
|
993
257
|
|
|
994
258
|
const message = async opt => {
|
|
995
|
-
const p = env[opt.process]
|
|
259
|
+
const p = mem.env[opt.process]
|
|
996
260
|
let ex = false
|
|
997
261
|
for (let v of opt.tags) if (v.name === "Type") ex = true
|
|
998
262
|
|
|
999
263
|
if (!ex) opt.tags.push({ name: "Type", value: "Message" })
|
|
1000
|
-
const { id, owner } = await
|
|
264
|
+
const { item, id, owner } = await ar.dataitem({
|
|
265
|
+
data: opt.data,
|
|
266
|
+
signer: opt.signer,
|
|
267
|
+
tags: tags(opt.tags),
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
await ar.postItem(item, su.jwk)
|
|
1001
271
|
try {
|
|
1002
272
|
const msg = genMsg(
|
|
1003
273
|
p,
|
|
@@ -1013,15 +283,14 @@ export const connect = () => {
|
|
|
1013
283
|
auth: mu.addr,
|
|
1014
284
|
})
|
|
1015
285
|
const res = await p.handle(p.memory, msg, _env)
|
|
1016
|
-
_txs[id] = opt.data ?? null
|
|
1017
286
|
p.memory = res.Memory
|
|
1018
287
|
delete res.Memory
|
|
1019
288
|
p.res[id] = res
|
|
1020
289
|
p.results.push(id)
|
|
1021
290
|
p.txs.unshift({ id: id, ...opt })
|
|
1022
|
-
msgs[id] = opt
|
|
291
|
+
mem.msgs[id] = opt
|
|
1023
292
|
for (const v of res.Messages ?? []) {
|
|
1024
|
-
if (env[v.Target]) {
|
|
293
|
+
if (mem.env[v.Target]) {
|
|
1025
294
|
await message({
|
|
1026
295
|
process: v.Target,
|
|
1027
296
|
tags: v.Tags,
|
|
@@ -1060,20 +329,16 @@ export const connect = () => {
|
|
|
1060
329
|
}
|
|
1061
330
|
|
|
1062
331
|
return {
|
|
1063
|
-
scheduler,
|
|
1064
|
-
modules,
|
|
1065
|
-
accounts: acc,
|
|
1066
|
-
mu,
|
|
1067
332
|
message,
|
|
1068
333
|
unmonitor: async opt => {
|
|
1069
|
-
const p = env[opt.process]
|
|
334
|
+
const p = mem.env[opt.process]
|
|
1070
335
|
try {
|
|
1071
336
|
clearInterval(p.cron)
|
|
1072
337
|
p.cron = null
|
|
1073
338
|
} catch (e) {}
|
|
1074
339
|
},
|
|
1075
340
|
monitor: async opt => {
|
|
1076
|
-
const p = env[opt.process]
|
|
341
|
+
const p = mem.env[opt.process]
|
|
1077
342
|
if (isNil(p.cron)) {
|
|
1078
343
|
p.cron = setInterval(async () => {
|
|
1079
344
|
await message({
|
|
@@ -1085,16 +350,11 @@ export const connect = () => {
|
|
|
1085
350
|
}, p.span)
|
|
1086
351
|
}
|
|
1087
352
|
},
|
|
1088
|
-
txs: async pid => {
|
|
1089
|
-
let _txs = []
|
|
1090
|
-
for (let v of env[pid].txs) _txs.push({ tags: v.tags, id: v.id })
|
|
1091
|
-
return _txs
|
|
1092
|
-
},
|
|
1093
353
|
spawn,
|
|
1094
354
|
assign,
|
|
1095
|
-
result: async opt => env[opt.process].res[opt.message],
|
|
355
|
+
result: async opt => mem.env[opt.process].res[opt.message],
|
|
1096
356
|
results: async opt => {
|
|
1097
|
-
const p = env[opt.process]
|
|
357
|
+
const p = mem.env[opt.process]
|
|
1098
358
|
let results = []
|
|
1099
359
|
const limit = opt.limit ?? 25
|
|
1100
360
|
if (opt.sort === "DESC") {
|
|
@@ -1111,8 +371,8 @@ export const connect = () => {
|
|
|
1111
371
|
return { edges: results }
|
|
1112
372
|
},
|
|
1113
373
|
dryrun: async opt => {
|
|
1114
|
-
const p = env[opt.process]
|
|
1115
|
-
const { id, owner } = await
|
|
374
|
+
const p = mem.env[opt.process]
|
|
375
|
+
const { id, owner } = await ar.dataitem(opt)
|
|
1116
376
|
try {
|
|
1117
377
|
const msg = genMsg(p, opt.data ?? "", opt.tags, owner, mu.addr, true)
|
|
1118
378
|
const _env = genEnv({
|
|
@@ -1128,9 +388,6 @@ export const connect = () => {
|
|
|
1128
388
|
}
|
|
1129
389
|
return null
|
|
1130
390
|
},
|
|
1131
|
-
|
|
1132
|
-
blueprint: async pkg => {
|
|
1133
|
-
return readFileSync(resolve(await dirname(), `lua/${pkg}.lua`), "utf8")
|
|
1134
|
-
},
|
|
391
|
+
mem,
|
|
1135
392
|
}
|
|
1136
393
|
}
|