wao 0.3.1 → 0.4.1
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/ao.js +6 -1
- package/cjs/aoconnect.js +414 -1475
- package/cjs/ar.js +39 -65
- package/cjs/armem.js +54 -0
- package/cjs/gql.js +393 -0
- package/cjs/index.js +7 -0
- package/cjs/tao.js +9 -9
- package/cjs/tar.js +280 -0
- package/cjs/test.js +57 -3
- package/cjs/tgql.js +733 -0
- package/cjs/utils.js +42 -8
- package/cjs/weavedrive.js +979 -0
- package/esm/accounts.js +36 -30
- package/esm/ao.js +4 -1
- package/esm/aoconnect.js +66 -808
- package/esm/ar.js +8 -24
- package/esm/armem.js +42 -0
- package/esm/gql.js +219 -0
- package/esm/index.js +2 -1
- package/esm/tao.js +7 -9
- package/esm/tar.js +106 -0
- package/esm/test.js +13 -2
- package/esm/tgql.js +282 -0
- package/esm/utils.js +10 -14
- 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
|
-
}
|
|
726
|
-
|
|
727
|
-
const jsonToStr = obj =>
|
|
728
|
-
isJSON(obj) || (is(Number, obj) ? Number(obj).toString() : obj)
|
|
729
|
-
|
|
730
|
-
const dirname = async () =>
|
|
731
|
-
typeof __dirname != "undefined"
|
|
732
|
-
? __dirname
|
|
733
|
-
: (await import("./dirname.js")).default
|
|
19
|
+
import AR from "./tar.js"
|
|
734
20
|
|
|
735
|
-
export const
|
|
736
|
-
|
|
737
|
-
const
|
|
738
|
-
|
|
21
|
+
export const connect = mem => {
|
|
22
|
+
mem ??= new ArMem()
|
|
23
|
+
const ar = new AR({ mem })
|
|
24
|
+
const WeaveDrive = new weavedrive(ar).drive
|
|
739
25
|
|
|
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,22 @@ 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
|
+
target: opt.process,
|
|
218
|
+
})
|
|
219
|
+
await ar.postItem(item, su.jwk)
|
|
955
220
|
try {
|
|
956
221
|
const msg = genMsg(
|
|
957
222
|
p,
|
|
@@ -972,9 +237,9 @@ export const connect = () => {
|
|
|
972
237
|
p.res[id] = res
|
|
973
238
|
p.results.push(id)
|
|
974
239
|
p.txs.unshift({ id: id, ..._opt })
|
|
975
|
-
msgs[id] = _opt
|
|
240
|
+
mem.msgs[id] = _opt
|
|
976
241
|
for (const v of res.Messages ?? []) {
|
|
977
|
-
if (env[v.Target]) {
|
|
242
|
+
if (mem.env[v.Target]) {
|
|
978
243
|
await message({
|
|
979
244
|
process: v.Target,
|
|
980
245
|
tags: v.Tags,
|
|
@@ -992,12 +257,18 @@ export const connect = () => {
|
|
|
992
257
|
}
|
|
993
258
|
|
|
994
259
|
const message = async opt => {
|
|
995
|
-
const p = env[opt.process]
|
|
260
|
+
const p = mem.env[opt.process]
|
|
996
261
|
let ex = false
|
|
997
262
|
for (let v of opt.tags) if (v.name === "Type") ex = true
|
|
998
263
|
|
|
999
264
|
if (!ex) opt.tags.push({ name: "Type", value: "Message" })
|
|
1000
|
-
const { id, owner } = await
|
|
265
|
+
const { item, id, owner } = await ar.dataitem({
|
|
266
|
+
data: opt.data,
|
|
267
|
+
signer: opt.signer,
|
|
268
|
+
tags: tags(opt.tags),
|
|
269
|
+
target: opt.process,
|
|
270
|
+
})
|
|
271
|
+
await ar.postItem(item, su.jwk)
|
|
1001
272
|
try {
|
|
1002
273
|
const msg = genMsg(
|
|
1003
274
|
p,
|
|
@@ -1013,15 +284,14 @@ export const connect = () => {
|
|
|
1013
284
|
auth: mu.addr,
|
|
1014
285
|
})
|
|
1015
286
|
const res = await p.handle(p.memory, msg, _env)
|
|
1016
|
-
_txs[id] = opt.data ?? null
|
|
1017
287
|
p.memory = res.Memory
|
|
1018
288
|
delete res.Memory
|
|
1019
289
|
p.res[id] = res
|
|
1020
290
|
p.results.push(id)
|
|
1021
291
|
p.txs.unshift({ id: id, ...opt })
|
|
1022
|
-
msgs[id] = opt
|
|
292
|
+
mem.msgs[id] = opt
|
|
1023
293
|
for (const v of res.Messages ?? []) {
|
|
1024
|
-
if (env[v.Target]) {
|
|
294
|
+
if (mem.env[v.Target]) {
|
|
1025
295
|
await message({
|
|
1026
296
|
process: v.Target,
|
|
1027
297
|
tags: v.Tags,
|
|
@@ -1060,20 +330,16 @@ export const connect = () => {
|
|
|
1060
330
|
}
|
|
1061
331
|
|
|
1062
332
|
return {
|
|
1063
|
-
scheduler,
|
|
1064
|
-
modules,
|
|
1065
|
-
accounts: acc,
|
|
1066
|
-
mu,
|
|
1067
333
|
message,
|
|
1068
334
|
unmonitor: async opt => {
|
|
1069
|
-
const p = env[opt.process]
|
|
335
|
+
const p = mem.env[opt.process]
|
|
1070
336
|
try {
|
|
1071
337
|
clearInterval(p.cron)
|
|
1072
338
|
p.cron = null
|
|
1073
339
|
} catch (e) {}
|
|
1074
340
|
},
|
|
1075
341
|
monitor: async opt => {
|
|
1076
|
-
const p = env[opt.process]
|
|
342
|
+
const p = mem.env[opt.process]
|
|
1077
343
|
if (isNil(p.cron)) {
|
|
1078
344
|
p.cron = setInterval(async () => {
|
|
1079
345
|
await message({
|
|
@@ -1085,16 +351,11 @@ export const connect = () => {
|
|
|
1085
351
|
}, p.span)
|
|
1086
352
|
}
|
|
1087
353
|
},
|
|
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
354
|
spawn,
|
|
1094
355
|
assign,
|
|
1095
|
-
result: async opt => env[opt.process].res[opt.message],
|
|
356
|
+
result: async opt => mem.env[opt.process].res[opt.message],
|
|
1096
357
|
results: async opt => {
|
|
1097
|
-
const p = env[opt.process]
|
|
358
|
+
const p = mem.env[opt.process]
|
|
1098
359
|
let results = []
|
|
1099
360
|
const limit = opt.limit ?? 25
|
|
1100
361
|
if (opt.sort === "DESC") {
|
|
@@ -1111,8 +372,8 @@ export const connect = () => {
|
|
|
1111
372
|
return { edges: results }
|
|
1112
373
|
},
|
|
1113
374
|
dryrun: async opt => {
|
|
1114
|
-
const p = env[opt.process]
|
|
1115
|
-
const { id, owner } = await
|
|
375
|
+
const p = mem.env[opt.process]
|
|
376
|
+
const { id, owner } = await ar.dataitem({ ...opt, target: opt.process })
|
|
1116
377
|
try {
|
|
1117
378
|
const msg = genMsg(p, opt.data ?? "", opt.tags, owner, mu.addr, true)
|
|
1118
379
|
const _env = genEnv({
|
|
@@ -1128,9 +389,6 @@ export const connect = () => {
|
|
|
1128
389
|
}
|
|
1129
390
|
return null
|
|
1130
391
|
},
|
|
1131
|
-
|
|
1132
|
-
blueprint: async pkg => {
|
|
1133
|
-
return readFileSync(resolve(await dirname(), `lua/${pkg}.lua`), "utf8")
|
|
1134
|
-
},
|
|
392
|
+
mem,
|
|
1135
393
|
}
|
|
1136
394
|
}
|