wao 0.6.1 → 0.6.3
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 +1 -1
- package/cjs/aoconnect.js +60 -60
- package/cjs/lua/weavedb_mock.lua +43 -0
- package/cjs/server.js +3 -1
- package/cjs/tao.js +3 -1
- package/cjs/{kv.js → weavedb.js} +227 -115
- package/cjs/weavedrive.js +6 -5
- package/esm/ao.js +1 -1
- package/esm/aoconnect.js +4 -6
- package/esm/lua/weavedb_mock.lua +43 -0
- package/esm/server.js +1 -1
- package/esm/tao.js +1 -1
- package/esm/{kv.js → weavedb.js} +119 -36
- package/esm/weavedrive.js +8 -16
- package/package.json +1 -1
package/esm/{kv.js → weavedb.js}
RENAMED
|
@@ -1,46 +1,89 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { map } from "ramda"
|
|
4
|
-
|
|
1
|
+
import { resolve } from "path"
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"
|
|
5
3
|
const KB = 1024
|
|
6
4
|
const MB = KB * 1024
|
|
7
5
|
const CACHE_SZ = 32 * KB
|
|
8
6
|
const CHUNK_SZ = 128 * MB
|
|
9
7
|
const NOTIFY_SZ = 512 * MB
|
|
10
8
|
const log = console.log
|
|
9
|
+
const rand = Math.floor(Math.random() * 1000000).toString()
|
|
11
10
|
|
|
12
|
-
export default class
|
|
13
|
-
constructor(ar) {
|
|
14
|
-
|
|
11
|
+
export default class WeaveDB {
|
|
12
|
+
constructor(ar, dir) {
|
|
13
|
+
dir ??= resolve(import.meta.dirname, ".db")
|
|
14
|
+
const kv_dir = resolve(dir, rand)
|
|
15
|
+
const data_dir = resolve(kv_dir, "data")
|
|
16
|
+
const rollup_dir = resolve(kv_dir, "rollup")
|
|
17
|
+
for (const v of [dir, kv_dir, rollup_dir, data_dir]) {
|
|
18
|
+
if (!existsSync(v)) mkdirSync(v)
|
|
19
|
+
}
|
|
20
|
+
this.ext = (mod, FS) => {
|
|
21
|
+
let cache = { data: {}, rollup: {} }
|
|
15
22
|
return {
|
|
16
23
|
async create(id) {
|
|
24
|
+
let properties = { isDevice: false, contents: null }
|
|
25
|
+
if (!FS.analyzePath("/rollup/").exists) FS.mkdir("/rollup/")
|
|
26
|
+
let node = FS.createFile("/", "rollup/" + id, properties, true, false)
|
|
27
|
+
|
|
28
|
+
// Set initial parame
|
|
29
|
+
let data = await ar.data(id)
|
|
30
|
+
const bytesLength = data?.length ?? 0
|
|
31
|
+
node.total_size = Number(bytesLength)
|
|
32
|
+
node.cache = new Uint8Array(0)
|
|
33
|
+
node.position = 0
|
|
34
|
+
|
|
35
|
+
// Add a function that defers querying the file size until it is asked the first time.
|
|
36
|
+
Object.defineProperties(node, {
|
|
37
|
+
usedBytes: { get: () => bytesLength },
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Now we have created the file in the emscripten FS, we can open it as a stream
|
|
41
|
+
let stream = FS.open("/rollup/" + id, "r")
|
|
42
|
+
|
|
43
|
+
//console.log("JS: Created file: ", id, " fd: ", stream.fd);
|
|
44
|
+
return stream
|
|
45
|
+
},
|
|
46
|
+
async createData(col, doc, val) {
|
|
17
47
|
let properties = { isDevice: false, contents: null }
|
|
18
48
|
if (!FS.analyzePath("/data/").exists) FS.mkdir("/data/")
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
if (!FS.analyzePath(`/data/${col}`).exists) FS.mkdir(`/data/${col}`)
|
|
50
|
+
let node = FS.createFile(
|
|
51
|
+
"/",
|
|
52
|
+
`data/${col}/${doc}`,
|
|
53
|
+
properties,
|
|
54
|
+
true,
|
|
55
|
+
false,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// Set initial parame
|
|
59
|
+
let data = val
|
|
60
|
+
if (!val) {
|
|
61
|
+
const col_dir = resolve(data_dir, col)
|
|
62
|
+
const _data =
|
|
63
|
+
readFileSync(resolve(col_dir, `${doc}.json`), "utf8") ?? ""
|
|
64
|
+
data = Buffer.from(_data, "utf8")
|
|
65
|
+
}
|
|
66
|
+
const bytesLength = data?.length ?? 0
|
|
22
67
|
node.total_size = Number(bytesLength)
|
|
23
68
|
node.cache = new Uint8Array(0)
|
|
24
69
|
node.position = 0
|
|
25
70
|
|
|
26
71
|
// Add a function that defers querying the file size until it is asked the first time.
|
|
27
72
|
Object.defineProperties(node, {
|
|
28
|
-
usedBytes: {
|
|
29
|
-
get: () => bytesLength,
|
|
30
|
-
},
|
|
73
|
+
usedBytes: { get: () => bytesLength },
|
|
31
74
|
})
|
|
32
75
|
|
|
33
76
|
// Now we have created the file in the emscripten FS, we can open it as a stream
|
|
34
|
-
let stream = FS.open("/data/" +
|
|
77
|
+
let stream = FS.open("/data/" + `${col}/${doc}`, "r")
|
|
35
78
|
|
|
36
79
|
//console.log("JS: Created file: ", id, " fd: ", stream.fd);
|
|
37
80
|
return stream
|
|
38
81
|
},
|
|
39
|
-
async open(filename) {
|
|
82
|
+
async open(filename, val) {
|
|
40
83
|
const pathCategory = filename.split("/")[1]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
84
|
+
if (pathCategory === "rollup") {
|
|
85
|
+
//log("JS: Opening ID: ", id)
|
|
86
|
+
const id = filename.split("/")[2]
|
|
44
87
|
if (FS.analyzePath(filename).exists) {
|
|
45
88
|
let stream = FS.open(filename, "r")
|
|
46
89
|
if (stream.fd) return stream.fd
|
|
@@ -52,19 +95,33 @@ export default class KV {
|
|
|
52
95
|
//console.log("JS: Open => Created file: ", id, " fd: ", stream.fd);
|
|
53
96
|
return stream.fd
|
|
54
97
|
}
|
|
98
|
+
} else if (pathCategory === "data") {
|
|
99
|
+
//log("JS: Opening ID: ", id)
|
|
100
|
+
const col = filename.split("/")[2]
|
|
101
|
+
const doc = filename.split("/")[3]
|
|
102
|
+
if (FS.analyzePath(filename).exists) {
|
|
103
|
+
let stream = FS.open(filename, "r")
|
|
104
|
+
if (stream.fd) return stream.fd
|
|
105
|
+
console.log("JS: File not found: ", filename)
|
|
106
|
+
return 0
|
|
107
|
+
} else {
|
|
108
|
+
//console.log("JS: Open => Creating file: ", id);
|
|
109
|
+
const stream = await this.createData(col, doc, val)
|
|
110
|
+
//console.log("JS: Open => Created file: ", id, " fd: ", stream.fd);
|
|
111
|
+
return stream.fd
|
|
112
|
+
}
|
|
55
113
|
} else {
|
|
56
114
|
console.log("JS: Invalid path category: ", pathCategory)
|
|
57
115
|
return 0
|
|
58
116
|
}
|
|
59
117
|
},
|
|
60
|
-
async read(fd, raw_dst_ptr, raw_length) {
|
|
118
|
+
async read(fd, raw_dst_ptr, raw_length, val) {
|
|
61
119
|
let to_read = Number(raw_length)
|
|
62
120
|
let dst_ptr = Number(raw_dst_ptr)
|
|
63
121
|
let stream = 0
|
|
64
122
|
for (let i = 0; i < FS.streams.length; i++) {
|
|
65
123
|
if (FS.streams[i].fd === fd) stream = FS.streams[i]
|
|
66
124
|
}
|
|
67
|
-
|
|
68
125
|
// Satisfy what we can with the cache first
|
|
69
126
|
let bytes_read = this.readFromCache(stream, dst_ptr, to_read)
|
|
70
127
|
stream.position += bytes_read
|
|
@@ -73,22 +130,51 @@ export default class KV {
|
|
|
73
130
|
to_read -= bytes_read
|
|
74
131
|
|
|
75
132
|
// Return if we have satisfied the request
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//console.log("
|
|
133
|
+
|
|
134
|
+
//console.log("KV: Satisfied request with cache. Returning...")
|
|
135
|
+
if (to_read === 0) return bytes_read
|
|
136
|
+
|
|
137
|
+
//console.log("KV: Read from cache: ", bytes_read, " Remaining to read: ", to_read)
|
|
81
138
|
|
|
82
139
|
const chunk_download_sz = Math.max(to_read, CACHE_SZ)
|
|
83
140
|
const to = Math.min(
|
|
84
141
|
stream.node.total_size,
|
|
85
142
|
stream.position + chunk_download_sz,
|
|
86
143
|
)
|
|
87
|
-
|
|
144
|
+
let data = val
|
|
145
|
+
if (!data) {
|
|
146
|
+
const sp = stream.path.split("/")
|
|
147
|
+
if (sp[1] === "data") {
|
|
148
|
+
const col_dir = resolve(data_dir, sp[2])
|
|
149
|
+
const _data =
|
|
150
|
+
readFileSync(resolve(col_dir, `${sp[3]}.json`), "utf8") ?? ""
|
|
151
|
+
data = Buffer.from(_data, "utf8")
|
|
152
|
+
} else {
|
|
153
|
+
data = await ar.data(stream.node.name)
|
|
154
|
+
try {
|
|
155
|
+
const json = JSON.parse(Buffer.from(data).toString())
|
|
156
|
+
for (const v of json.diffs) {
|
|
157
|
+
const val = Buffer.from(JSON.stringify(v.data))
|
|
158
|
+
const _fd = await this.open(
|
|
159
|
+
`/data/${v.collection}/${v.doc}`,
|
|
160
|
+
val,
|
|
161
|
+
)
|
|
162
|
+
const col_dir = resolve(data_dir, v.collection)
|
|
163
|
+
if (!existsSync(col_dir)) mkdirSync(col_dir)
|
|
164
|
+
writeFileSync(
|
|
165
|
+
resolve(col_dir, `${v.doc}.json`),
|
|
166
|
+
JSON.stringify(v.data),
|
|
167
|
+
)
|
|
168
|
+
await this.read(_fd, _fd, val.length, val)
|
|
169
|
+
}
|
|
170
|
+
} catch (e) {
|
|
171
|
+
log(e)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
88
175
|
// Extract the Range header to determine the start and end of the requested chunk
|
|
89
176
|
const start = 0
|
|
90
177
|
const end = data.length
|
|
91
|
-
|
|
92
178
|
// Create a ReadableStream for the requested chunk
|
|
93
179
|
const chunk = data.subarray(start, end)
|
|
94
180
|
const response = new Response(
|
|
@@ -120,7 +206,7 @@ export default class KV {
|
|
|
120
206
|
// Write bytes from the chunk and update the pointer if necessary
|
|
121
207
|
const write_length = Math.min(chunk_bytes.length, to_read)
|
|
122
208
|
if (write_length > 0) {
|
|
123
|
-
//console.log("
|
|
209
|
+
//console.log("KV: Writing: ", write_length, " bytes to: ", dst_ptr)
|
|
124
210
|
mod.HEAP8.set(chunk_bytes.subarray(0, write_length), dst_ptr)
|
|
125
211
|
dst_ptr += write_length
|
|
126
212
|
bytes_read += write_length
|
|
@@ -131,14 +217,11 @@ export default class KV {
|
|
|
131
217
|
if (to_read == 0) {
|
|
132
218
|
// Add excess bytes to our cache
|
|
133
219
|
const chunk_to_cache = chunk_bytes.subarray(write_length)
|
|
134
|
-
//console.log("
|
|
220
|
+
//console.log("KV: Cacheing excess: ", chunk_to_cache.length)
|
|
135
221
|
cache_chunks.push(chunk_to_cache)
|
|
136
222
|
}
|
|
137
|
-
|
|
138
223
|
if (bytes_until_cache <= 0) {
|
|
139
|
-
console.log(
|
|
140
|
-
"WeaveDrive: Chunk size reached. Compressing cache...",
|
|
141
|
-
)
|
|
224
|
+
console.log("KV: Chunk size reached. Compressing cache...")
|
|
142
225
|
stream.node.cache = this.addChunksToCache(
|
|
143
226
|
stream.node.cache,
|
|
144
227
|
cache_chunks,
|
|
@@ -149,7 +232,7 @@ export default class KV {
|
|
|
149
232
|
|
|
150
233
|
if (bytes_until_notify <= 0) {
|
|
151
234
|
console.log(
|
|
152
|
-
"
|
|
235
|
+
"KV: Downloaded: ",
|
|
153
236
|
(downloaded_bytes / stream.node.total_size) * 100,
|
|
154
237
|
"%",
|
|
155
238
|
)
|
|
@@ -157,7 +240,7 @@ export default class KV {
|
|
|
157
240
|
}
|
|
158
241
|
}
|
|
159
242
|
} catch (error) {
|
|
160
|
-
console.error("
|
|
243
|
+
console.error("KV: Error reading the stream: ", error)
|
|
161
244
|
} finally {
|
|
162
245
|
reader.releaseLock()
|
|
163
246
|
}
|
|
@@ -183,7 +266,7 @@ export default class KV {
|
|
|
183
266
|
readFromCache(stream, dst_ptr, length) {
|
|
184
267
|
// Check if the cache has been invalidated by a seek
|
|
185
268
|
if (stream.lastReadPosition !== stream.position) {
|
|
186
|
-
//console.log("
|
|
269
|
+
//console.log("KV: Invalidating cache for fd: ", stream.fd, " Current pos: ", stream.position, " Last read pos: ", stream.lastReadPosition)
|
|
187
270
|
stream.node.cache = new Uint8Array(0)
|
|
188
271
|
return 0
|
|
189
272
|
}
|
package/esm/weavedrive.js
CHANGED
|
@@ -7,7 +7,7 @@ const log = console.log
|
|
|
7
7
|
|
|
8
8
|
export default class WeaveDrive {
|
|
9
9
|
constructor(ar) {
|
|
10
|
-
this.
|
|
10
|
+
this.ext = (mod, FS) => {
|
|
11
11
|
return {
|
|
12
12
|
reset(fd) {
|
|
13
13
|
//console.log("WeaveDrive: Resetting fd: ", fd)
|
|
@@ -18,10 +18,8 @@ export default class WeaveDrive {
|
|
|
18
18
|
async create(id) {
|
|
19
19
|
var properties = { isDevice: false, contents: null }
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return 0
|
|
24
|
-
}
|
|
21
|
+
//console.log("WeaveDrive: Arweave ID is not admissable! ", id)
|
|
22
|
+
if (!(await this.checkAdmissible(id))) return 0
|
|
25
23
|
|
|
26
24
|
// Create the file in the emscripten FS
|
|
27
25
|
|
|
@@ -42,11 +40,7 @@ export default class WeaveDrive {
|
|
|
42
40
|
|
|
43
41
|
// Add a function that defers querying the file size until it is asked the first time.
|
|
44
42
|
Object.defineProperties(node, {
|
|
45
|
-
usedBytes: {
|
|
46
|
-
get: function () {
|
|
47
|
-
return bytesLength
|
|
48
|
-
},
|
|
49
|
-
},
|
|
43
|
+
usedBytes: { get: () => bytesLength },
|
|
50
44
|
})
|
|
51
45
|
|
|
52
46
|
// Now we have created the file in the emscripten FS, we can open it as a stream
|
|
@@ -72,8 +66,6 @@ export default class WeaveDrive {
|
|
|
72
66
|
}
|
|
73
67
|
} catch (e) {}
|
|
74
68
|
|
|
75
|
-
var bytesLength = result.length
|
|
76
|
-
|
|
77
69
|
var node = FS.createDataFile(
|
|
78
70
|
"/",
|
|
79
71
|
"block/" + id,
|
|
@@ -220,10 +212,10 @@ export default class WeaveDrive {
|
|
|
220
212
|
to_read -= bytes_read
|
|
221
213
|
|
|
222
214
|
// Return if we have satisfied the request
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
215
|
+
|
|
216
|
+
//console.log("WeaveDrive: Satisfied request with cache. Returning...")
|
|
217
|
+
if (to_read === 0) return bytes_read
|
|
218
|
+
|
|
227
219
|
//console.log("WeaveDrive: Read from cache: ", bytes_read, " Remaining to read: ", to_read)
|
|
228
220
|
|
|
229
221
|
const chunk_download_sz = Math.max(to_read, CACHE_SZ)
|