presidium-db-client-server 0.4.0 → 0.5.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/DatabaseHandler.js +149 -162
- package/DatabaseServer.js +34 -4
- package/healthCheckHandler.js +18 -0
- package/notFoundHandler.js +18 -0
- package/package.json +4 -2
package/DatabaseHandler.js
CHANGED
|
@@ -111,186 +111,173 @@ function DatabaseHandler(options) {
|
|
|
111
111
|
request.pathSegments = request.path.slice(1).split("/")
|
|
112
112
|
request.pathDepth = request.pathSegments.length
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
})
|
|
118
|
-
response.end("OK")
|
|
119
|
-
} else if (request.pathDepth == 2) {
|
|
120
|
-
const tableName = request.pathSegments[0]
|
|
121
|
-
const fname = request.pathSegments[1]
|
|
122
|
-
const ht = hts.get(tableName)
|
|
123
|
-
?? await getHt(tableName, request, manifestHt)
|
|
114
|
+
const tableName = request.pathSegments[0]
|
|
115
|
+
const fname = request.pathSegments[1]
|
|
116
|
+
const ht = hts.get(tableName) ?? await getHt(tableName, request, manifestHt)
|
|
124
117
|
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
await switchCase(
|
|
119
|
+
fname,
|
|
127
120
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
121
|
+
eq("clear"), async () => {
|
|
122
|
+
await ht.clear()
|
|
123
|
+
response.writeHead(200, {
|
|
124
|
+
"Content-Type": "text/plain",
|
|
125
|
+
})
|
|
126
|
+
response.end("OK")
|
|
127
|
+
},
|
|
135
128
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
eq("set"), async () => {
|
|
130
|
+
const { key, value, sortValue } = await Readable.JSON(request)
|
|
131
|
+
await ht.set(key, value, sortValue)
|
|
132
|
+
response.writeHead(200, {
|
|
133
|
+
"Content-Type": "text/plain",
|
|
134
|
+
})
|
|
135
|
+
response.end("OK")
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
eq("get"), async () => {
|
|
139
|
+
const { key } = await Readable.JSON(request)
|
|
140
|
+
const value = await ht.get(key)
|
|
141
|
+
if (value === undefined) {
|
|
142
|
+
response.writeHead(499, {
|
|
140
143
|
"Content-Type": "text/plain",
|
|
141
144
|
})
|
|
142
|
-
response.end("
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
eq("get"), async () => {
|
|
146
|
-
const { key } = await Readable.JSON(request)
|
|
147
|
-
const value = await ht.get(key)
|
|
148
|
-
if (value === undefined) {
|
|
149
|
-
response.writeHead(499, {
|
|
150
|
-
"Content-Type": "text/plain",
|
|
151
|
-
})
|
|
152
|
-
response.end("Resource Not Found")
|
|
153
|
-
} else {
|
|
154
|
-
response.writeHead(200, {
|
|
155
|
-
"Content-Type": "text/plain",
|
|
156
|
-
})
|
|
157
|
-
response.end(value)
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
eq("getBinary"), async () => {
|
|
162
|
-
const { key } = await Readable.JSON(request)
|
|
163
|
-
const value = await ht.getBinary(key)
|
|
145
|
+
response.end("Resource Not Found")
|
|
146
|
+
} else {
|
|
164
147
|
response.writeHead(200, {
|
|
165
|
-
"Content-Type": "
|
|
148
|
+
"Content-Type": "text/plain",
|
|
166
149
|
})
|
|
167
150
|
response.end(value)
|
|
168
|
-
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
169
153
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
154
|
+
eq("getBinary"), async () => {
|
|
155
|
+
const { key } = await Readable.JSON(request)
|
|
156
|
+
const value = await ht.getBinary(key)
|
|
157
|
+
response.writeHead(200, {
|
|
158
|
+
"Content-Type": "application/octet-stream",
|
|
159
|
+
})
|
|
160
|
+
response.end(value)
|
|
161
|
+
},
|
|
178
162
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
163
|
+
eq("delete"), async () => {
|
|
164
|
+
const { key } = await Readable.JSON(request)
|
|
165
|
+
const didDelete = await ht.delete(key)
|
|
166
|
+
response.writeHead(200, {
|
|
167
|
+
"Content-Type": "text/plain",
|
|
168
|
+
})
|
|
169
|
+
response.end(String(didDelete))
|
|
170
|
+
},
|
|
186
171
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
for await (const value of ht.iterator(options)) {
|
|
195
|
-
response.write(value)
|
|
196
|
-
response.write("")
|
|
197
|
-
}
|
|
198
|
-
response.end()
|
|
199
|
-
},
|
|
172
|
+
eq("count"), async () => {
|
|
173
|
+
const count = ht.count()
|
|
174
|
+
response.writeHead(200, {
|
|
175
|
+
"Content-Type": "text/plain",
|
|
176
|
+
})
|
|
177
|
+
response.end(String(count))
|
|
178
|
+
},
|
|
200
179
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
response.end()
|
|
215
|
-
},
|
|
180
|
+
eq("iterator"), async () => {
|
|
181
|
+
const options = await Readable.JSON(request)
|
|
182
|
+
response.writeHead(200, {
|
|
183
|
+
"Content-Type": "application/octet-stream",
|
|
184
|
+
"Content-Encoding": "utf8",
|
|
185
|
+
})
|
|
186
|
+
const count = ht.count()
|
|
187
|
+
for await (const value of ht.iterator(options)) {
|
|
188
|
+
response.write(value)
|
|
189
|
+
response.write("")
|
|
190
|
+
}
|
|
191
|
+
response.end()
|
|
192
|
+
},
|
|
216
193
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
response.
|
|
229
|
-
}
|
|
194
|
+
eq("entriesIterator"), async () => {
|
|
195
|
+
const options = await Readable.JSON(request)
|
|
196
|
+
response.writeHead(200, {
|
|
197
|
+
"Content-Type": "application/octet-stream",
|
|
198
|
+
"Content-Encoding": "utf8",
|
|
199
|
+
})
|
|
200
|
+
const count = ht.count()
|
|
201
|
+
for await (const [key, value] of ht.entriesIterator(options)) {
|
|
202
|
+
response.write(key)
|
|
203
|
+
response.write("")
|
|
204
|
+
response.write(value)
|
|
205
|
+
response.write("")
|
|
206
|
+
}
|
|
207
|
+
response.end()
|
|
208
|
+
},
|
|
230
209
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
210
|
+
eq("forwardIterator"), async () => {
|
|
211
|
+
const options = await Readable.JSON(request)
|
|
212
|
+
response.writeHead(200, {
|
|
213
|
+
"Content-Type": "application/octet-stream",
|
|
214
|
+
"Content-Encoding": "utf8",
|
|
215
|
+
})
|
|
216
|
+
const count = ht.count()
|
|
217
|
+
for await (const value of ht.forwardIterator(options)) {
|
|
218
|
+
response.write(value)
|
|
219
|
+
response.write("")
|
|
220
|
+
}
|
|
221
|
+
response.end()
|
|
222
|
+
},
|
|
244
223
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
response.write("")
|
|
259
|
-
}
|
|
260
|
-
response.end()
|
|
261
|
-
},
|
|
224
|
+
eq("reverseIterator"), async () => {
|
|
225
|
+
const options = await Readable.JSON(request)
|
|
226
|
+
response.writeHead(200, {
|
|
227
|
+
"Content-Type": "application/octet-stream",
|
|
228
|
+
"Content-Encoding": "utf8",
|
|
229
|
+
})
|
|
230
|
+
const count = ht.count()
|
|
231
|
+
for await (const value of ht.reverseIterator(options)) {
|
|
232
|
+
response.write(value)
|
|
233
|
+
response.write("")
|
|
234
|
+
}
|
|
235
|
+
response.end()
|
|
236
|
+
},
|
|
262
237
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
238
|
+
eq("forwardEntriesIterator"), async () => {
|
|
239
|
+
const options = await Readable.JSON(request)
|
|
240
|
+
response.writeHead(200, {
|
|
241
|
+
"Content-Type": "application/octet-stream",
|
|
242
|
+
"Content-Encoding": "utf8",
|
|
243
|
+
})
|
|
244
|
+
const count = ht.count()
|
|
245
|
+
for await (const [key, value, sortValue] of ht.forwardEntriesIterator(options)) {
|
|
246
|
+
response.write(key)
|
|
247
|
+
response.write("")
|
|
248
|
+
response.write(value)
|
|
249
|
+
response.write("")
|
|
250
|
+
response.write(String(sortValue))
|
|
251
|
+
response.write("")
|
|
252
|
+
}
|
|
253
|
+
response.end()
|
|
254
|
+
},
|
|
280
255
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
256
|
+
eq("reverseEntriesIterator"), async () => {
|
|
257
|
+
const options = await Readable.JSON(request)
|
|
258
|
+
response.writeHead(200, {
|
|
259
|
+
"Content-Type": "application/octet-stream",
|
|
260
|
+
"Content-Encoding": "utf8",
|
|
261
|
+
})
|
|
262
|
+
const count = ht.count()
|
|
263
|
+
for await (const [key, value, sortValue] of ht.reverseEntriesIterator(options)) {
|
|
264
|
+
response.write(key)
|
|
265
|
+
response.write("")
|
|
266
|
+
response.write(value)
|
|
267
|
+
response.write("")
|
|
268
|
+
response.write(String(sortValue))
|
|
269
|
+
response.write("")
|
|
270
|
+
}
|
|
271
|
+
response.end()
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
async () => {
|
|
275
|
+
const error = new Error("Forbidden: Hash Table Method")
|
|
276
|
+
error.code = "403"
|
|
277
|
+
throw error
|
|
278
|
+
},
|
|
279
|
+
)
|
|
287
280
|
|
|
288
|
-
} else {
|
|
289
|
-
response.writeHead(404, {
|
|
290
|
-
"Content-Type": "text/plain",
|
|
291
|
-
})
|
|
292
|
-
response.end("Not Found")
|
|
293
|
-
}
|
|
294
281
|
}
|
|
295
282
|
}
|
|
296
283
|
|
package/DatabaseServer.js
CHANGED
|
@@ -7,12 +7,18 @@ const HTTP = require("presidium/HTTP")
|
|
|
7
7
|
const DiskHashTable = require("presidium/DiskHashTable")
|
|
8
8
|
const DiskSortedHashTable = require("presidium/DiskSortedHashTable")
|
|
9
9
|
const DatabaseHandler = require("./DatabaseHandler")
|
|
10
|
+
const healthCheckHandler = require("./healthCheckHandler")
|
|
11
|
+
const notFoundHandler = require("./notFoundHandler")
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* @name DatabaseServer
|
|
13
15
|
*
|
|
14
16
|
* @docs
|
|
15
17
|
* ```specscript
|
|
18
|
+
* module HTTP "https://presidium.services/docs/HTTP"
|
|
19
|
+
*
|
|
20
|
+
* HTTP.Handler(request HTTP.Request, response HTTP.Response) -> ()
|
|
21
|
+
*
|
|
16
22
|
* new DatabaseServer(options {
|
|
17
23
|
* databasePath: string,
|
|
18
24
|
* manifestTableName: string,
|
|
@@ -21,11 +27,11 @@ const DatabaseHandler = require("./DatabaseHandler")
|
|
|
21
27
|
* defaultTableInitialLength: number,
|
|
22
28
|
* defaultTableItemSize: number,
|
|
23
29
|
* defaultDiskSortedHashTableDegree: number,
|
|
24
|
-
* }) -> server DatabaseServer
|
|
30
|
+
* }, ...handlers Arguments<HTTP.Handler>) -> server DatabaseServer
|
|
25
31
|
* ```
|
|
26
32
|
*/
|
|
27
33
|
class DatabaseServer {
|
|
28
|
-
constructor(options) {
|
|
34
|
+
constructor(options, ...handlers) {
|
|
29
35
|
this.databasePath = options.databasePath
|
|
30
36
|
this.manifestTableName = options.manifestTableName ?? "Manifest"
|
|
31
37
|
this.manifestTableInitialLength = options.manifestTableInitialLength ?? 1048576
|
|
@@ -33,6 +39,7 @@ class DatabaseServer {
|
|
|
33
39
|
this.defaultTableInitialLength = options.defaultTableInitialLength ?? 1048576
|
|
34
40
|
this.defaultTableItemSize = options.defaultTableItemSize ?? 1024
|
|
35
41
|
this.defaultDiskSortedHashTableDegree = options.defaultDiskSortedHashTableDegree ?? 2
|
|
42
|
+
this.handlers = handlers
|
|
36
43
|
this.server = null
|
|
37
44
|
this.hts = new Map()
|
|
38
45
|
}
|
|
@@ -67,8 +74,16 @@ class DatabaseServer {
|
|
|
67
74
|
hts: this.hts,
|
|
68
75
|
})
|
|
69
76
|
|
|
70
|
-
const
|
|
71
|
-
|
|
77
|
+
const router = tryCatch(
|
|
78
|
+
switchCase(
|
|
79
|
+
request => request.path == "/health",
|
|
80
|
+
healthCheckHandler,
|
|
81
|
+
|
|
82
|
+
request => request.pathDepth == 2,
|
|
83
|
+
databaseHandler,
|
|
84
|
+
|
|
85
|
+
notFoundHandler,
|
|
86
|
+
),
|
|
72
87
|
function errorHandler(error, request, response) {
|
|
73
88
|
response.writeHead(error.code ?? 500, {
|
|
74
89
|
"Content-Type": "text/plain",
|
|
@@ -77,6 +92,21 @@ class DatabaseServer {
|
|
|
77
92
|
}
|
|
78
93
|
)
|
|
79
94
|
|
|
95
|
+
const handler = all.series([
|
|
96
|
+
...this.handlers,
|
|
97
|
+
request => {
|
|
98
|
+
const { pathname } = new URL(`http://*${request.url}`)
|
|
99
|
+
request.path = decodeURIComponent(
|
|
100
|
+
pathname == "/" ? pathname
|
|
101
|
+
: pathname.endsWith("/") ? pathname.slice(0, -1)
|
|
102
|
+
: pathname
|
|
103
|
+
)
|
|
104
|
+
request.pathSegments = request.path.slice(1).split("/")
|
|
105
|
+
request.pathDepth = request.pathSegments.length
|
|
106
|
+
},
|
|
107
|
+
router,
|
|
108
|
+
])
|
|
109
|
+
|
|
80
110
|
this.server = HTTP.Server(handler)
|
|
81
111
|
}
|
|
82
112
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name healthCheckHandler
|
|
3
|
+
*
|
|
4
|
+
* @docs
|
|
5
|
+
* ```specscript
|
|
6
|
+
* module HTTP "https://presidium.services/docs/HTTP"
|
|
7
|
+
*
|
|
8
|
+
* healthCheckHandler(request HTTP.Request, response HTTP.Response) -> ()
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
function healthCheckHandler(request, response) {
|
|
12
|
+
response.writeHead(200, {
|
|
13
|
+
'Content-Type': 'text/plain',
|
|
14
|
+
})
|
|
15
|
+
response.end('OK')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = healthCheckHandler
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name notFoundHandler
|
|
3
|
+
*
|
|
4
|
+
* @docs
|
|
5
|
+
* ```specscript
|
|
6
|
+
* module HTTP "https://presidium.services/docs/HTTP"
|
|
7
|
+
*
|
|
8
|
+
* notFoundHandler(request HTTP.Request, response HTTP.Response) -> ()
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
function notFoundHandler(request, response) {
|
|
12
|
+
response.writeHead(404, {
|
|
13
|
+
"Content-Type": "text/plain",
|
|
14
|
+
})
|
|
15
|
+
response.end("Not Found")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = notFoundHandler
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "presidium-db-client-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Presidium DB client and server library",
|
|
5
5
|
"author": "Richard Tong",
|
|
6
6
|
"license": "CFOSS",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"TextEntriesStream.js",
|
|
22
22
|
"TextStream.js",
|
|
23
23
|
"buffersToEntry.js",
|
|
24
|
-
"handleServerResponse.js"
|
|
24
|
+
"handleServerResponse.js",
|
|
25
|
+
"healthCheckHandler.js",
|
|
26
|
+
"notFoundHandler.js"
|
|
25
27
|
],
|
|
26
28
|
"keywords": [
|
|
27
29
|
"presidium",
|