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.
@@ -1,46 +1,89 @@
1
- import Arweave from "arweave"
2
- import { toGraphObj } from "./utils.js"
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 KV {
13
- constructor(ar) {
14
- this.kv = function WeaveDrive(mod, FS) {
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
- let node = FS.createFile("/", "data/" + id, properties, true, false)
20
- // Set initial parameters
21
- const bytesLength = (await ar.data(id))?.length ?? 0
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/" + id, "r")
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
- const id = filename.split("/")[2]
42
- //log("JS: Opening ID: ", id)
43
- if (pathCategory === "data") {
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
- if (to_read === 0) {
77
- //console.log("WeaveDrive: Satisfied request with cache. Returning...")
78
- return bytes_read
79
- }
80
- //console.log("WeaveDrive: Read from cache: ", bytes_read, " Remaining to read: ", to_read)
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
- const data = await ar.data(stream.node.name)
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("WeaveDrive: Writing: ", write_length, " bytes to: ", dst_ptr)
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("WeaveDrive: Cacheing excess: ", chunk_to_cache.length)
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
- "WeaveDrive: Downloaded: ",
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("WeaveDrive: Error reading the stream: ", 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("WeaveDrive: Invalidating cache for fd: ", stream.fd, " Current pos: ", stream.position, " Last read pos: ", stream.lastReadPosition)
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.drive = function WeaveDrive(mod, FS) {
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
- if (!(await this.checkAdmissible(id))) {
22
- //console.log("WeaveDrive: Arweave ID is not admissable! ", id)
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
- if (to_read === 0) {
224
- //console.log("WeaveDrive: Satisfied request with cache. Returning...")
225
- return bytes_read
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wao",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",