presidium-db-client-server 4.0.0 → 4.1.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/DatabaseServer.js CHANGED
@@ -6,7 +6,7 @@ require("rubico/global")
6
6
  const HTTP = require("presidium/HTTP")
7
7
  const DiskHashTable = require("presidium/DiskHashTable")
8
8
  const DiskSortedHashTable = require("presidium/DiskSortedHashTable")
9
- const DatabaseHandler = require("./DatabaseHandler")
9
+ const databaseHandler = require("./databaseHandler")
10
10
  const healthCheckHandler = require("./healthCheckHandler")
11
11
  const notFoundHandler = require("./notFoundHandler")
12
12
  const errorHandler = require("./errorHandler")
@@ -63,25 +63,13 @@ class DatabaseServer {
63
63
  await manifestHt.init()
64
64
  this.manifestHt = manifestHt
65
65
 
66
- const databaseHandler = DatabaseHandler({
67
- databasePath: this.databasePath,
68
- manifestTableName: this.manifestTableName,
69
- manifestTableInitialLength: this.manifestTableInitialLength,
70
- manifestTableItemSize: this.manifestTableItemSize,
71
- defaultTableInitialLength: this.defaultTableInitialLength,
72
- defaultTableItemSize: this.defaultTableItemSize,
73
- defaultDiskSortedHashTableDegree: this.defaultDiskSortedHashTableDegree,
74
- manifestHt: this.manifestHt,
75
- hts: this.hts,
76
- })
77
-
78
66
  const router = tryCatch(
79
67
  switchCase(
80
68
  request => request.path == "/health",
81
69
  healthCheckHandler,
82
70
 
83
71
  request => request.pathDepth == 2,
84
- databaseHandler,
72
+ curry.call(databaseHandler, this),
85
73
 
86
74
  notFoundHandler,
87
75
  ),
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Presidium DB Client and Server may be freely distributed under the CFOSS license.
3
+ */
4
+
5
+ require("rubico/global")
6
+ const DiskHashTable = require("presidium/DiskHashTable")
7
+ const DiskSortedHashTable = require("presidium/DiskSortedHashTable")
8
+ const Readable = require("presidium/Readable")
9
+
10
+ /**
11
+ * @name getHt
12
+ *
13
+ * @docs
14
+ * ```specscript
15
+ * module HTTP "https://presidium.services/docs/HTTP"
16
+ *
17
+ * getHt(tableName string, request HTTP.Request) -> ht DiskHashTable|DiskSortedHashTable
18
+ * ```
19
+ */
20
+ async function getHt(tableName, request) {
21
+ const {
22
+ databasePath,
23
+ defaultTableInitialLength,
24
+ defaultTableItemSize,
25
+ manifestHt,
26
+ hts,
27
+ } = this
28
+
29
+ const htConfigString = await manifestHt.get(tableName)
30
+ let ht
31
+ if (htConfigString) {
32
+ const config = JSON.parse(htConfigString)
33
+ if (request.headers["client-name"] == "DiskHashTableClient") {
34
+ ht = new DiskHashTable(config)
35
+ await ht.init()
36
+ hts.set(tableName, ht)
37
+ } else if (request.headers["client-name"] == "DiskSortedHashTableClient") {
38
+ ht = new DiskSortedHashTable(config)
39
+ await ht.init()
40
+ hts.set(tableName, ht)
41
+ } else {
42
+ const error = new Error("Forbidden: Client-Name")
43
+ error.code = 403
44
+ throw error
45
+ }
46
+ } else {
47
+ if (request.headers["client-name"] == "DiskHashTableClient") {
48
+ const config = {
49
+ storagePath: `${databasePath}/${tableName}/storage`,
50
+ headerPath: `${databasePath}/${tableName}/header`,
51
+ initialLength: defaultTableInitialLength,
52
+ itemSize: defaultTableItemSize,
53
+ }
54
+ ht = new DiskHashTable(config)
55
+ await manifestHt.set(tableName, JSON.stringify(config))
56
+ await ht.init()
57
+ hts.set(tableName, ht)
58
+ } else if (request.headers["client-name"] == "DiskSortedHashTableClient") {
59
+ const config = {
60
+ storagePath: `${databasePath}/${tableName}/storage`,
61
+ headerPath: `${databasePath}/${tableName}/header`,
62
+ initialLength: defaultTableInitialLength,
63
+ itemSize: defaultTableItemSize,
64
+ sortValueType: request.headers["sort-value-type"],
65
+ degree: Number(request.headers["degree"]),
66
+ }
67
+ ht = new DiskSortedHashTable(config)
68
+ await manifestHt.set(tableName, JSON.stringify(config))
69
+ await ht.init()
70
+ hts.set(tableName, ht)
71
+ } else {
72
+ const error = new Error("Forbidden: Client-Name")
73
+ error.code = 403
74
+ throw error
75
+ }
76
+ }
77
+ return ht
78
+ }
79
+
80
+ /**
81
+ * @name databaseHandler
82
+ *
83
+ * @docs
84
+ * ```specscript
85
+ * module DiskHashTable "https://presidium.services/docs/DiskHashTable"
86
+ * module HTTP "https://presidium.services/docs/HTTP"
87
+ *
88
+ * databaseHandler(HTTP.Request, HTTP.Response) -> ()
89
+ * ```
90
+ */
91
+ async function databaseHandler(request, response) {
92
+ const { pathname } = new URL(`http://*${request.url}`)
93
+ request.path = decodeURIComponent(
94
+ pathname == "/" ? pathname
95
+ : pathname.endsWith("/") ? pathname.slice(0, -1)
96
+ : pathname
97
+ )
98
+ request.pathSegments = request.path.slice(1).split("/")
99
+ request.pathDepth = request.pathSegments.length
100
+
101
+ const tableName = request.pathSegments[0]
102
+ const fname = request.pathSegments[1]
103
+ const ht = this.hts.get(tableName) ?? await getHt.call(this, tableName, request)
104
+
105
+ await switchCase(
106
+ fname,
107
+
108
+ eq("clear"), async () => {
109
+ await ht.clear()
110
+ response.writeHead(200, {
111
+ "Content-Type": "text/plain",
112
+ })
113
+ response.end("OK")
114
+ },
115
+
116
+ eq("set"), async () => {
117
+ const key = request.headers["key"]
118
+ const sortValue = request.headers["sort-value"]
119
+ const value = request.headers["content-type"] == "text/plain"
120
+ ? await Readable.Text(request)
121
+ : await Readable.Buffer(request)
122
+ await ht.set(key, value, sortValue)
123
+ response.writeHead(200, {
124
+ "Content-Type": "text/plain",
125
+ })
126
+ response.end("OK")
127
+ },
128
+
129
+ eq("get"), async () => {
130
+ const key = request.headers["key"]
131
+ const value = await ht.get(key)
132
+ if (value === undefined) {
133
+ response.writeHead(499, {
134
+ "Content-Type": "text/plain",
135
+ })
136
+ response.end("Resource Not Found")
137
+ } else {
138
+ response.writeHead(200, {
139
+ "Content-Type": "text/plain",
140
+ })
141
+ response.end(value)
142
+ }
143
+ },
144
+
145
+ eq("getBinary"), async () => {
146
+ const key = request.headers["key"]
147
+ const value = await ht.getBinary(key)
148
+ response.writeHead(200, {
149
+ "Content-Type": "application/octet-stream",
150
+ })
151
+ response.end(value)
152
+ },
153
+
154
+ eq("delete"), async () => {
155
+ const key = request.headers["key"]
156
+ const didDelete = await ht.delete(key)
157
+ response.writeHead(200, {
158
+ "Content-Type": "text/plain",
159
+ })
160
+ response.end(String(didDelete))
161
+ },
162
+
163
+ eq("count"), async () => {
164
+ const count = ht.count()
165
+ response.writeHead(200, {
166
+ "Content-Type": "text/plain",
167
+ })
168
+ response.end(String(count))
169
+ },
170
+
171
+ eq("iterator"), async () => {
172
+ const valueType = request.headers["value-type"]
173
+ const options = filter({ valueType }, __)
174
+ response.writeHead(200, {
175
+ "Content-Type": "application/octet-stream",
176
+ "Content-Encoding": "utf8",
177
+ })
178
+ const count = ht.count()
179
+ for await (const value of ht.iterator(options)) {
180
+ response.write(value)
181
+ response.write("")
182
+ }
183
+ response.end()
184
+ },
185
+
186
+ eq("entriesIterator"), async () => {
187
+ const valueType = request.headers["value-type"]
188
+ const options = filter({ valueType }, __)
189
+ response.writeHead(200, {
190
+ "Content-Type": "application/octet-stream",
191
+ "Content-Encoding": "utf8",
192
+ })
193
+ const count = ht.count()
194
+ for await (const [key, value] of ht.entriesIterator(options)) {
195
+ response.write(key)
196
+ response.write("")
197
+ response.write(value)
198
+ response.write("")
199
+ }
200
+ response.end()
201
+ },
202
+
203
+ eq("forwardIterator"), async () => {
204
+ const valueType = request.headers["value-type"]
205
+ const exclusiveStartKey = request.headers["exclusive-start-key"]
206
+ const startingSortValue = request.headers["starting-sort-value"]
207
+ const endingSortValue = request.headers["ending-sort-value"]
208
+ const options = filter({
209
+ valueType,
210
+ exclusiveStartKey,
211
+ startingSortValue,
212
+ endingSortValue,
213
+ }, __)
214
+
215
+ response.writeHead(200, {
216
+ "Content-Type": "application/octet-stream",
217
+ "Content-Encoding": "utf8",
218
+ })
219
+ const count = ht.count()
220
+ for await (const value of ht.forwardIterator(options)) {
221
+ response.write(value)
222
+ response.write("")
223
+ }
224
+ response.end()
225
+ },
226
+
227
+ eq("reverseIterator"), async () => {
228
+ const valueType = request.headers["value-type"]
229
+ const exclusiveStartKey = request.headers["exclusive-start-key"]
230
+ const startingSortValue = request.headers["starting-sort-value"]
231
+ const endingSortValue = request.headers["ending-sort-value"]
232
+ const options = filter({
233
+ valueType,
234
+ exclusiveStartKey,
235
+ startingSortValue,
236
+ endingSortValue,
237
+ }, __)
238
+
239
+ response.writeHead(200, {
240
+ "Content-Type": "application/octet-stream",
241
+ "Content-Encoding": "utf8",
242
+ })
243
+ const count = ht.count()
244
+ for await (const value of ht.reverseIterator(options)) {
245
+ response.write(value)
246
+ response.write("")
247
+ }
248
+ response.end()
249
+ },
250
+
251
+ eq("forwardEntriesIterator"), async () => {
252
+ const valueType = request.headers["value-type"]
253
+ const exclusiveStartKey = request.headers["exclusive-start-key"]
254
+ const startingSortValue = request.headers["starting-sort-value"]
255
+ const endingSortValue = request.headers["ending-sort-value"]
256
+ const options = filter({
257
+ valueType,
258
+ exclusiveStartKey,
259
+ startingSortValue,
260
+ endingSortValue,
261
+ }, __)
262
+
263
+ response.writeHead(200, {
264
+ "Content-Type": "application/octet-stream",
265
+ "Content-Encoding": "utf8",
266
+ })
267
+ const count = ht.count()
268
+ for await (const [key, value, sortValue] of ht.forwardEntriesIterator(options)) {
269
+ response.write(key)
270
+ response.write("")
271
+ response.write(value)
272
+ response.write("")
273
+ response.write(String(sortValue))
274
+ response.write("")
275
+ }
276
+ response.end()
277
+ },
278
+
279
+ eq("reverseEntriesIterator"), async () => {
280
+ const valueType = request.headers["value-type"]
281
+ const exclusiveStartKey = request.headers["exclusive-start-key"]
282
+ const startingSortValue = request.headers["starting-sort-value"]
283
+ const endingSortValue = request.headers["ending-sort-value"]
284
+ const options = filter({
285
+ valueType,
286
+ exclusiveStartKey,
287
+ startingSortValue,
288
+ endingSortValue,
289
+ }, __)
290
+
291
+ response.writeHead(200, {
292
+ "Content-Type": "application/octet-stream",
293
+ "Content-Encoding": "utf8",
294
+ })
295
+ const count = ht.count()
296
+ for await (const [key, value, sortValue] of ht.reverseEntriesIterator(options)) {
297
+ response.write(key)
298
+ response.write("")
299
+ response.write(value)
300
+ response.write("")
301
+ response.write(String(sortValue))
302
+ response.write("")
303
+ }
304
+ response.end()
305
+ },
306
+
307
+ async () => {
308
+ const error = new Error("Forbidden: Hash Table Method")
309
+ error.code = "403"
310
+ throw error
311
+ },
312
+ )
313
+
314
+ }
315
+
316
+ module.exports = databaseHandler
@@ -50,7 +50,19 @@ async function loadBalancerHandler(request, response) {
50
50
  passthroughStreams.push(new stream.PassThrough())
51
51
  }
52
52
 
53
- serverIpOrIps.forEach(async (serverIp, index) => {
53
+ request.on("data", chunk => {
54
+ passthroughStreams.forEach(stream => {
55
+ stream.write(chunk)
56
+ })
57
+ })
58
+
59
+ request.on("end", () => {
60
+ passthroughStreams.forEach(stream => {
61
+ stream.end()
62
+ })
63
+ })
64
+
65
+ await forEach(serverIpOrIps, async (serverIp, index) => {
54
66
  const client = getClient.call(this, serverIp)
55
67
 
56
68
  const serverResponse = await client[request.method](request.url, {
@@ -62,22 +74,14 @@ async function loadBalancerHandler(request, response) {
62
74
  response.writeHead(serverResponse.status, serverResponse.headers)
63
75
  serverResponse.pipe(response)
64
76
  } else {
65
- await Readable.Text(serverResponse)
77
+ const text = await Readable.Text(serverResponse)
78
+ if (serverResponse.ok) {
79
+ } else {
80
+ console.error(new Error(text))
81
+ }
66
82
  }
67
83
  })
68
84
 
69
- request.on("data", chunk => {
70
- passthroughStreams.forEach(stream => {
71
- stream.write(chunk)
72
- })
73
- })
74
-
75
- request.on("end", () => {
76
- passthroughStreams.forEach(stream => {
77
- stream.end()
78
- })
79
- })
80
-
81
85
  } else {
82
86
  const client = getClient.call(this, serverIpOrIps)
83
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "presidium-db-client-server",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Presidium DB client and server library",
5
5
  "author": "Richard Tong",
6
6
  "license": "CFOSS",
@@ -15,7 +15,7 @@
15
15
  "BinaryEntriesStream.js",
16
16
  "BinaryStream.js",
17
17
  "DatabaseServer.js",
18
- "DatabaseHandler.js",
18
+ "databaseHandler.js",
19
19
  "DatabaseLoadBalancer.js",
20
20
  "loadBalancerHandler.js",
21
21
  "DiskHashTableClient.js",
@@ -1,330 +0,0 @@
1
- /**
2
- * Presidium DB Client and Server may be freely distributed under the CFOSS license.
3
- */
4
-
5
- require("rubico/global")
6
- const DiskHashTable = require("presidium/DiskHashTable")
7
- const DiskSortedHashTable = require("presidium/DiskSortedHashTable")
8
- const Readable = require("presidium/Readable")
9
-
10
- /**
11
- * @name DatabaseHandler
12
- *
13
- * @docs
14
- * ```specscript
15
- * module DiskHashTable "https://presidium.services/docs/DiskHashTable"
16
- * module HTTP "https://presidium.services/docs/HTTP"
17
- *
18
- * DatabaseHandler(options {
19
- * databasePath: string,
20
- * manifestTableName: string,
21
- * manifestTableInitialLength: number,
22
- * manifestTableItemSize: number,
23
- * defaultTableInitialLength: number,
24
- * defaultTableItemSize: number,
25
- * manifestHt: DiskHashTable,
26
- * hts: Map<tableName string, DiskHashTable>,
27
- * }) -> databaseHandler HTTP.AsyncHandler
28
- * ```
29
- */
30
- function DatabaseHandler(options) {
31
- const {
32
- databasePath,
33
- manifestTableName,
34
- manifestTableInitialLength,
35
- manifestTableItemSize,
36
- defaultTableInitialLength,
37
- defaultTableItemSize,
38
- manifestHt,
39
- hts,
40
- } = options
41
-
42
- /**
43
- * @name getHt
44
- *
45
- * @docs
46
- * ```specscript
47
- * module HTTP "https://presidium.services/docs/HTTP"
48
- *
49
- * getHt(tableName string, request HTTP.Request) -> ht DiskHashTable|DiskSortedHashTable
50
- * ```
51
- */
52
- async function getHt(tableName, request, manifestHt) {
53
- const htConfigString = await manifestHt.get(tableName)
54
- let ht
55
- if (htConfigString) {
56
- const config = JSON.parse(htConfigString)
57
- if (request.headers["client-name"] == "DiskHashTableClient") {
58
- ht = new DiskHashTable(config)
59
- await ht.init()
60
- hts.set(tableName, ht)
61
- } else if (request.headers["client-name"] == "DiskSortedHashTableClient") {
62
- ht = new DiskSortedHashTable(config)
63
- await ht.init()
64
- hts.set(tableName, ht)
65
- } else {
66
- const error = new Error("Forbidden: Client-Name")
67
- error.code = 403
68
- throw error
69
- }
70
- } else {
71
- if (request.headers["client-name"] == "DiskHashTableClient") {
72
- const config = {
73
- storagePath: `${databasePath}/${tableName}/storage`,
74
- headerPath: `${databasePath}/${tableName}/header`,
75
- initialLength: defaultTableInitialLength,
76
- itemSize: defaultTableItemSize,
77
- }
78
- ht = new DiskHashTable(config)
79
- await manifestHt.set(tableName, JSON.stringify(config))
80
- await ht.init()
81
- hts.set(tableName, ht)
82
- } else if (request.headers["client-name"] == "DiskSortedHashTableClient") {
83
- const config = {
84
- storagePath: `${databasePath}/${tableName}/storage`,
85
- headerPath: `${databasePath}/${tableName}/header`,
86
- initialLength: defaultTableInitialLength,
87
- itemSize: defaultTableItemSize,
88
- sortValueType: request.headers["sort-value-type"],
89
- degree: Number(request.headers["degree"]),
90
- }
91
- ht = new DiskSortedHashTable(config)
92
- await manifestHt.set(tableName, JSON.stringify(config))
93
- await ht.init()
94
- hts.set(tableName, ht)
95
- } else {
96
- const error = new Error("Forbidden: Client-Name")
97
- error.code = 403
98
- throw error
99
- }
100
- }
101
- return ht
102
- }
103
-
104
- return async function databaseHandler(request, response) {
105
- const { pathname } = new URL(`http://*${request.url}`)
106
- request.path = decodeURIComponent(
107
- pathname == "/" ? pathname
108
- : pathname.endsWith("/") ? pathname.slice(0, -1)
109
- : pathname
110
- )
111
- request.pathSegments = request.path.slice(1).split("/")
112
- request.pathDepth = request.pathSegments.length
113
-
114
- const tableName = request.pathSegments[0]
115
- const fname = request.pathSegments[1]
116
- const ht = hts.get(tableName) ?? await getHt(tableName, request, manifestHt)
117
-
118
- await switchCase(
119
- fname,
120
-
121
- eq("clear"), async () => {
122
- await ht.clear()
123
- response.writeHead(200, {
124
- "Content-Type": "text/plain",
125
- })
126
- response.end("OK")
127
- },
128
-
129
- eq("set"), async () => {
130
- const key = request.headers["key"]
131
- const sortValue = request.headers["sort-value"]
132
- const value = request.headers["content-type"] == "text/plain"
133
- ? await Readable.Text(request)
134
- : await Readable.Buffer(request)
135
- await ht.set(key, value, sortValue)
136
- response.writeHead(200, {
137
- "Content-Type": "text/plain",
138
- })
139
- response.end("OK")
140
- },
141
-
142
- eq("get"), async () => {
143
- const key = request.headers["key"]
144
- const value = await ht.get(key)
145
- if (value === undefined) {
146
- response.writeHead(499, {
147
- "Content-Type": "text/plain",
148
- })
149
- response.end("Resource Not Found")
150
- } else {
151
- response.writeHead(200, {
152
- "Content-Type": "text/plain",
153
- })
154
- response.end(value)
155
- }
156
- },
157
-
158
- eq("getBinary"), async () => {
159
- const key = request.headers["key"]
160
- const value = await ht.getBinary(key)
161
- response.writeHead(200, {
162
- "Content-Type": "application/octet-stream",
163
- })
164
- response.end(value)
165
- },
166
-
167
- eq("delete"), async () => {
168
- const key = request.headers["key"]
169
- const didDelete = await ht.delete(key)
170
- response.writeHead(200, {
171
- "Content-Type": "text/plain",
172
- })
173
- response.end(String(didDelete))
174
- },
175
-
176
- eq("count"), async () => {
177
- const count = ht.count()
178
- response.writeHead(200, {
179
- "Content-Type": "text/plain",
180
- })
181
- response.end(String(count))
182
- },
183
-
184
- eq("iterator"), async () => {
185
- const valueType = request.headers["value-type"]
186
- const options = filter({ valueType }, __)
187
- response.writeHead(200, {
188
- "Content-Type": "application/octet-stream",
189
- "Content-Encoding": "utf8",
190
- })
191
- const count = ht.count()
192
- for await (const value of ht.iterator(options)) {
193
- response.write(value)
194
- response.write("")
195
- }
196
- response.end()
197
- },
198
-
199
- eq("entriesIterator"), async () => {
200
- const valueType = request.headers["value-type"]
201
- const options = filter({ valueType }, __)
202
- response.writeHead(200, {
203
- "Content-Type": "application/octet-stream",
204
- "Content-Encoding": "utf8",
205
- })
206
- const count = ht.count()
207
- for await (const [key, value] of ht.entriesIterator(options)) {
208
- response.write(key)
209
- response.write("")
210
- response.write(value)
211
- response.write("")
212
- }
213
- response.end()
214
- },
215
-
216
- eq("forwardIterator"), async () => {
217
- const valueType = request.headers["value-type"]
218
- const exclusiveStartKey = request.headers["exclusive-start-key"]
219
- const startingSortValue = request.headers["starting-sort-value"]
220
- const endingSortValue = request.headers["ending-sort-value"]
221
- const options = filter({
222
- valueType,
223
- exclusiveStartKey,
224
- startingSortValue,
225
- endingSortValue,
226
- }, __)
227
-
228
- response.writeHead(200, {
229
- "Content-Type": "application/octet-stream",
230
- "Content-Encoding": "utf8",
231
- })
232
- const count = ht.count()
233
- for await (const value of ht.forwardIterator(options)) {
234
- response.write(value)
235
- response.write("")
236
- }
237
- response.end()
238
- },
239
-
240
- eq("reverseIterator"), async () => {
241
- const valueType = request.headers["value-type"]
242
- const exclusiveStartKey = request.headers["exclusive-start-key"]
243
- const startingSortValue = request.headers["starting-sort-value"]
244
- const endingSortValue = request.headers["ending-sort-value"]
245
- const options = filter({
246
- valueType,
247
- exclusiveStartKey,
248
- startingSortValue,
249
- endingSortValue,
250
- }, __)
251
-
252
- response.writeHead(200, {
253
- "Content-Type": "application/octet-stream",
254
- "Content-Encoding": "utf8",
255
- })
256
- const count = ht.count()
257
- for await (const value of ht.reverseIterator(options)) {
258
- response.write(value)
259
- response.write("")
260
- }
261
- response.end()
262
- },
263
-
264
- eq("forwardEntriesIterator"), async () => {
265
- const valueType = request.headers["value-type"]
266
- const exclusiveStartKey = request.headers["exclusive-start-key"]
267
- const startingSortValue = request.headers["starting-sort-value"]
268
- const endingSortValue = request.headers["ending-sort-value"]
269
- const options = filter({
270
- valueType,
271
- exclusiveStartKey,
272
- startingSortValue,
273
- endingSortValue,
274
- }, __)
275
-
276
- response.writeHead(200, {
277
- "Content-Type": "application/octet-stream",
278
- "Content-Encoding": "utf8",
279
- })
280
- const count = ht.count()
281
- for await (const [key, value, sortValue] of ht.forwardEntriesIterator(options)) {
282
- response.write(key)
283
- response.write("")
284
- response.write(value)
285
- response.write("")
286
- response.write(String(sortValue))
287
- response.write("")
288
- }
289
- response.end()
290
- },
291
-
292
- eq("reverseEntriesIterator"), async () => {
293
- const valueType = request.headers["value-type"]
294
- const exclusiveStartKey = request.headers["exclusive-start-key"]
295
- const startingSortValue = request.headers["starting-sort-value"]
296
- const endingSortValue = request.headers["ending-sort-value"]
297
- const options = filter({
298
- valueType,
299
- exclusiveStartKey,
300
- startingSortValue,
301
- endingSortValue,
302
- }, __)
303
-
304
- response.writeHead(200, {
305
- "Content-Type": "application/octet-stream",
306
- "Content-Encoding": "utf8",
307
- })
308
- const count = ht.count()
309
- for await (const [key, value, sortValue] of ht.reverseEntriesIterator(options)) {
310
- response.write(key)
311
- response.write("")
312
- response.write(value)
313
- response.write("")
314
- response.write(String(sortValue))
315
- response.write("")
316
- }
317
- response.end()
318
- },
319
-
320
- async () => {
321
- const error = new Error("Forbidden: Hash Table Method")
322
- error.code = "403"
323
- throw error
324
- },
325
- )
326
-
327
- }
328
- }
329
-
330
- module.exports = DatabaseHandler