@muze-nl/simplystore 0.6.29 → 0.7.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/package.json +3 -3
- package/src/command-worker-module.mjs +5 -3
- package/src/load-worker.mjs +12 -6
- package/src/server.mjs +129 -116
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muze-nl/simplystore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"main": "src/server.mjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"bugs": "https://github.com/simplyedit/simplystore/issues",
|
|
17
17
|
"homepage": "https://github.com/simplyedit/simplystore#readme",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@muze-nl/jsontag": "^0.9.
|
|
19
|
+
"@muze-nl/jsontag": "^0.9.11",
|
|
20
20
|
"@muze-nl/od-jsontag": "^0.3.3",
|
|
21
21
|
"codemirror": "^6.0.1",
|
|
22
22
|
"express": "^4.18.1",
|
|
23
|
-
"@muze-nl/jaqt": "^0.9.
|
|
23
|
+
"@muze-nl/jaqt": "^0.9.8",
|
|
24
24
|
"json-pointer": "^0.6.2",
|
|
25
25
|
"jsonpath-plus": "^7.2.0",
|
|
26
26
|
"vm2": "^3.9.13",
|
|
@@ -7,7 +7,7 @@ import writeFileAtomic from 'write-file-atomic'
|
|
|
7
7
|
let commands = {}
|
|
8
8
|
let resultArr = []
|
|
9
9
|
let dataspace
|
|
10
|
-
let datafile
|
|
10
|
+
let datafile, basefile, extension
|
|
11
11
|
let meta = {}
|
|
12
12
|
let metaProxy = {
|
|
13
13
|
index: {
|
|
@@ -69,6 +69,8 @@ export async function initialize(task) {
|
|
|
69
69
|
metaProxy.schema = meta.schema
|
|
70
70
|
}
|
|
71
71
|
datafile = task.datafile
|
|
72
|
+
extension = datafile.split('.').pop()
|
|
73
|
+
basefile = datafile.substring(0, datafile.length - (extension.length + 1)) //+1 for . character
|
|
72
74
|
commands = await import(task.commandsFile).then(mod => {
|
|
73
75
|
return mod.default
|
|
74
76
|
})
|
|
@@ -95,9 +97,9 @@ export default async function runCommand(commandStr, request) {
|
|
|
95
97
|
id: meta.index.id
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
|
-
//TODO: write data every x commands or x minutes, in seperate thread
|
|
100
|
+
//TODO: write data every x commands or x minutes, in seperate thread?
|
|
99
101
|
|
|
100
|
-
let newfilename =
|
|
102
|
+
let newfilename = basefile + '.' + task.id + '.' + extension
|
|
101
103
|
await writeFileAtomic(newfilename, uint8sab)
|
|
102
104
|
meta.parts++
|
|
103
105
|
response.meta.parts = meta.parts
|
package/src/load-worker.mjs
CHANGED
|
@@ -11,18 +11,24 @@ parentPort.on('message', (files) => {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const extension = files.dataFile.split('.').pop()
|
|
15
|
+
const basefile = files.dataFile.substring(0, files.dataFile.length - (extension.length + 1)) //+1 for . character
|
|
16
|
+
|
|
14
17
|
let count = 0
|
|
15
|
-
let basefile = files.dataFile
|
|
16
18
|
let data
|
|
17
19
|
let jsontag
|
|
18
20
|
let tempMeta = {}
|
|
19
21
|
let datafile = files.dataFile
|
|
22
|
+
let commands = files.commands
|
|
23
|
+
commands.push('done')
|
|
20
24
|
do {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
if (fs.existsSync(datafile)) {
|
|
26
|
+
jsontag = fs.readFileSync(datafile)
|
|
27
|
+
data = parse(jsontag, tempMeta) // tempMeta is needed to combine the resultArray, using meta conflicts with meta.index.id
|
|
28
|
+
count++
|
|
29
|
+
}
|
|
30
|
+
datafile = basefile + '.' + commands.shift() + '.' + extension
|
|
31
|
+
} while(commands.length)
|
|
26
32
|
meta.parts = count
|
|
27
33
|
if (files.schemaFile) {
|
|
28
34
|
jsontag = fs.readFileSync(files.schemaFile, 'utf-8')
|
package/src/server.mjs
CHANGED
|
@@ -39,22 +39,11 @@ async function main(options) {
|
|
|
39
39
|
limit: '50MB'
|
|
40
40
|
}))
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
worker.on('message', result => {
|
|
46
|
-
resolve(result)
|
|
47
|
-
worker.terminate()
|
|
48
|
-
})
|
|
49
|
-
worker.on('error', error => {
|
|
50
|
-
reject(error)
|
|
51
|
-
worker.terminate()
|
|
52
|
-
})
|
|
53
|
-
worker.postMessage({dataFile:datafile,schemaFile})
|
|
54
|
-
})
|
|
55
|
-
}
|
|
42
|
+
let status = loadCommandStatus(commandStatus)
|
|
43
|
+
let commandQueue = loadCommandLog(status, commandLog)
|
|
44
|
+
|
|
56
45
|
try {
|
|
57
|
-
let data = await loadData()
|
|
46
|
+
let data = await loadData(Array.from(status.keys())) // command id's (keys) are used to generate filenames of changes
|
|
58
47
|
jsontagBuffers = [data.data]
|
|
59
48
|
meta = data.meta
|
|
60
49
|
} catch(err) {
|
|
@@ -73,11 +62,90 @@ async function main(options) {
|
|
|
73
62
|
}
|
|
74
63
|
}
|
|
75
64
|
|
|
76
|
-
|
|
77
65
|
let queryWorkerPool = new WorkerPool(maxWorkers, queryWorker, queryWorkerInitTask())
|
|
66
|
+
let commandWorkerInstance
|
|
67
|
+
|
|
68
|
+
server.get('/query/*', handleGetQuery)
|
|
69
|
+
server.post('/query/*', handlePostQuery)
|
|
70
|
+
server.post('/command', handlePostCommand)
|
|
71
|
+
server.get('/command/:id', handleGetCommand)
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(`http://localhost:${port}`, {
|
|
75
|
+
signal: AbortSignal.timeout(2000)
|
|
76
|
+
})
|
|
77
|
+
console.error(`Port ${port} is already occupied, aborting.`)
|
|
78
|
+
process.exit()
|
|
79
|
+
} catch(error) {
|
|
80
|
+
server.listen(port, () => {
|
|
81
|
+
console.log('SimplyStore listening on port '+port)
|
|
82
|
+
let used = Math.round(process.memoryUsage().rss / 1024 / 1024);
|
|
83
|
+
console.log(`(${used} MB)`);
|
|
84
|
+
})
|
|
85
|
+
}
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
/* ------ */
|
|
88
|
+
|
|
89
|
+
function loadCommandStatus(commandStatusFile) {
|
|
90
|
+
let status = new Map()
|
|
91
|
+
if (fs.existsSync(commandStatusFile)) {
|
|
92
|
+
let file = fs.readFileSync(commandStatusFile, 'utf-8')
|
|
93
|
+
if (file) {
|
|
94
|
+
let lines = file.split("\n").filter(Boolean) //filter clears empty lines
|
|
95
|
+
for(let line of lines) {
|
|
96
|
+
let command = JSONTag.parse(line)
|
|
97
|
+
status.set(command.command, command)
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
console.error('Could not open command status',commandStatusFile)
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
console.log('no command status', commandStatusFile)
|
|
104
|
+
}
|
|
105
|
+
return status
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function loadCommandLog(status, commandLog) {
|
|
109
|
+
let commands = []
|
|
110
|
+
if (!fs.existsSync(commandLog)) {
|
|
111
|
+
return commands
|
|
112
|
+
}
|
|
113
|
+
let log = fs.readFileSync(commandLog, 'utf-8')
|
|
114
|
+
if (log) {
|
|
115
|
+
let lines = log.split("\n").filter(Boolean)
|
|
116
|
+
for(let line of lines) {
|
|
117
|
+
let command = JSONTag.parse(line)
|
|
118
|
+
let state = status.get(command.id)
|
|
119
|
+
switch(state) {
|
|
120
|
+
case 'accepted': // enqueue
|
|
121
|
+
commands.push(command)
|
|
122
|
+
break;
|
|
123
|
+
case 'done': // do nothing
|
|
124
|
+
break;
|
|
125
|
+
default: // error, do nothing
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return commands
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function loadData(commands) {
|
|
134
|
+
return new Promise((resolve,reject) => {
|
|
135
|
+
let worker = new Worker(loadWorker)
|
|
136
|
+
worker.on('message', result => {
|
|
137
|
+
resolve(result)
|
|
138
|
+
worker.terminate()
|
|
139
|
+
})
|
|
140
|
+
worker.on('error', error => {
|
|
141
|
+
reject(error)
|
|
142
|
+
worker.terminate()
|
|
143
|
+
})
|
|
144
|
+
worker.postMessage({dataFile:datafile,schemaFile,commands})
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function handleGetQuery(req, res, next) {
|
|
81
149
|
let start = Date.now()
|
|
82
150
|
if ( !accept(req,res,
|
|
83
151
|
['application/jsontag','application/json','text/html','text/javascript','image/*'],
|
|
@@ -115,9 +183,9 @@ async function main(options) {
|
|
|
115
183
|
}
|
|
116
184
|
let end = Date.now()
|
|
117
185
|
console.log(path, (end-start), process.memoryUsage())
|
|
118
|
-
}
|
|
186
|
+
}
|
|
119
187
|
|
|
120
|
-
|
|
188
|
+
async function handlePostQuery(req,res) {
|
|
121
189
|
let start = Date.now()
|
|
122
190
|
if ( !accept(req,res,
|
|
123
191
|
['application/jsontag','application/json'])
|
|
@@ -145,57 +213,55 @@ async function main(options) {
|
|
|
145
213
|
let end = Date.now()
|
|
146
214
|
console.log(path, (end-start), process.memoryUsage())
|
|
147
215
|
// queryWorkerPool.memoryUsage()
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
let status = loadCommandStatus(commandStatus)
|
|
152
|
-
|
|
153
|
-
function loadCommandStatus(commandStatusFile) {
|
|
154
|
-
let status = new Map()
|
|
155
|
-
if (fs.existsSync(commandStatusFile)) {
|
|
156
|
-
let file = fs.readFileSync(commandStatusFile, 'utf-8')
|
|
157
|
-
if (file) {
|
|
158
|
-
let lines = file.split("\n").filter(Boolean) //filter clears empty lines
|
|
159
|
-
for(let line of lines) {
|
|
160
|
-
let command = JSONTag.parse(line)
|
|
161
|
-
status.set(command.command, command)
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
console.error('Could not open command status',commandStatusFile)
|
|
165
|
-
}
|
|
166
|
-
} else {
|
|
167
|
-
console.log('no command status', commandStatusFile)
|
|
168
|
-
}
|
|
169
|
-
return status
|
|
170
216
|
}
|
|
171
217
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!fs.existsSync(commandLog)) {
|
|
218
|
+
async function handlePostCommand(req, res) {
|
|
219
|
+
let commandId = checkCommand(req, res)
|
|
220
|
+
if (!commandId) {
|
|
176
221
|
return
|
|
177
222
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
let
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
switch(state) {
|
|
185
|
-
case 'accepted': // enqueue
|
|
186
|
-
commandQueue.push(command)
|
|
187
|
-
break;
|
|
188
|
-
case 'done': // do nothing
|
|
189
|
-
break;
|
|
190
|
-
default: // error, do nothing
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
223
|
+
try {
|
|
224
|
+
let commandStr = req.body.toString()
|
|
225
|
+
let request = {
|
|
226
|
+
method: req.method,
|
|
227
|
+
url: req.originalUrl,
|
|
228
|
+
query: req.query
|
|
193
229
|
}
|
|
230
|
+
|
|
231
|
+
commandQueue.push({
|
|
232
|
+
id:commandId,
|
|
233
|
+
command:commandStr,
|
|
234
|
+
request,
|
|
235
|
+
meta,
|
|
236
|
+
data:jsontagBuffers,
|
|
237
|
+
commandsFile,
|
|
238
|
+
datafile
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
runNextCommand()
|
|
242
|
+
} catch(err) {
|
|
243
|
+
let s = {code:err.code||500, status:'failed', message:err.message, details:err.details}
|
|
244
|
+
status.set(commandId, s)
|
|
245
|
+
appendFile(commandStatus, JSONTag.stringify(Object.assign({command:commandId}, s)))
|
|
246
|
+
console.error('ERROR: SimplyStore cannot run command ', commandId, err)
|
|
194
247
|
}
|
|
195
248
|
}
|
|
196
249
|
|
|
197
|
-
|
|
198
|
-
|
|
250
|
+
function handleGetCommand(req, res) {
|
|
251
|
+
if (status.has(req.params.id)) {
|
|
252
|
+
let result = status.get(req.params.id)
|
|
253
|
+
sendResponse({
|
|
254
|
+
jsontag: false,
|
|
255
|
+
body: JSON.stringify(result)
|
|
256
|
+
},res)
|
|
257
|
+
} else {
|
|
258
|
+
sendResponse({
|
|
259
|
+
code: 404,
|
|
260
|
+
jsontag: false,
|
|
261
|
+
body: JSON.stringify({code: 404, message: "Command not found", details: req.params.id})
|
|
262
|
+
}, res)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
199
265
|
|
|
200
266
|
async function runNextCommand() {
|
|
201
267
|
let command = commandQueue.shift()
|
|
@@ -262,38 +328,6 @@ async function main(options) {
|
|
|
262
328
|
}
|
|
263
329
|
}
|
|
264
330
|
|
|
265
|
-
server.post('/command', async (req, res) => {
|
|
266
|
-
let commandId = checkCommand(req, res)
|
|
267
|
-
if (!commandId) {
|
|
268
|
-
return
|
|
269
|
-
}
|
|
270
|
-
try {
|
|
271
|
-
let commandStr = req.body.toString()
|
|
272
|
-
let request = {
|
|
273
|
-
method: req.method,
|
|
274
|
-
url: req.originalUrl,
|
|
275
|
-
query: req.query
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
commandQueue.push({
|
|
279
|
-
id:commandId,
|
|
280
|
-
command:commandStr,
|
|
281
|
-
request,
|
|
282
|
-
meta,
|
|
283
|
-
data:jsontagBuffers,
|
|
284
|
-
commandsFile,
|
|
285
|
-
datafile
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
runNextCommand()
|
|
289
|
-
} catch(err) {
|
|
290
|
-
let s = {code:err.code||500, status:'failed', message:err.message, details:err.details}
|
|
291
|
-
status.set(commandId, s)
|
|
292
|
-
appendFile(commandStatus, JSONTag.stringify(Object.assign({command:commandId}, s)))
|
|
293
|
-
console.error('ERROR: SimplyStore cannot run command ', commandId, err)
|
|
294
|
-
}
|
|
295
|
-
})
|
|
296
|
-
|
|
297
331
|
function checkCommand(req, res) {
|
|
298
332
|
let error, command, commandOK
|
|
299
333
|
let commandStr = req.body.toString() // raw body through express.raw()
|
|
@@ -341,27 +375,6 @@ async function main(options) {
|
|
|
341
375
|
return command.id
|
|
342
376
|
}
|
|
343
377
|
|
|
344
|
-
server.get('/command/:id', (req, res) => {
|
|
345
|
-
if (status.has(req.params.id)) {
|
|
346
|
-
let result = status.get(req.params.id)
|
|
347
|
-
sendResponse({
|
|
348
|
-
jsontag: false,
|
|
349
|
-
body: JSON.stringify(result)
|
|
350
|
-
},res)
|
|
351
|
-
} else {
|
|
352
|
-
sendResponse({
|
|
353
|
-
code: 404,
|
|
354
|
-
jsontag: false,
|
|
355
|
-
body: JSON.stringify({code: 404, message: "Command not found", details: req.params.id})
|
|
356
|
-
}, res)
|
|
357
|
-
}
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
server.listen(port, () => {
|
|
361
|
-
console.log('SimplyStore listening on port '+port)
|
|
362
|
-
let used = Math.round(process.memoryUsage().rss / 1024 / 1024);
|
|
363
|
-
console.log(`(${used} MB)`);
|
|
364
|
-
})
|
|
365
378
|
}
|
|
366
379
|
|
|
367
380
|
function sendResponse(response, res) {
|