@muze-nl/simplystore 0.6.30 → 0.7.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muze-nl/simplystore",
3
- "version": "0.6.30",
3
+ "version": "0.7.1",
4
4
  "main": "src/server.mjs",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -16,7 +16,7 @@
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.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",
@@ -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 = datafile + (meta.parts ? '.'+meta.parts : '')
102
+ let newfilename = basefile + '.' + task.id + '.' + extension
101
103
  await writeFileAtomic(newfilename, uint8sab)
102
104
  meta.parts++
103
105
  response.meta.parts = meta.parts
@@ -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
- jsontag = fs.readFileSync(datafile)
22
- data = parse(jsontag, tempMeta) // tempMeta is needed to combine the resultArray, using meta conflicts with meta.index.id
23
- count++
24
- datafile = basefile + '.' + count
25
- } while(fs.existsSync(datafile))
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')
@@ -5,7 +5,7 @@ import JSONTag from '@muze-nl/jsontag'
5
5
  import * as odJSONTag from '@muze-nl/od-jsontag/src/jsontag.mjs'
6
6
  import {source, isProxy, resultSet} from '@muze-nl/od-jsontag/src/symbols.mjs'
7
7
  import parse from '@muze-nl/od-jsontag/src/parse.mjs'
8
- import {_,from,not,anyOf,allOf,asc,desc,sum,count,avg,max,min,distinct} from '@muze-nl/jaqt'
8
+ import {_,from,not,anyOf,allOf,asc,desc,sum,count,avg,max,min,many,one,distinct} from '@muze-nl/jaqt'
9
9
 
10
10
  let dataspace
11
11
  let meta = {}
@@ -134,6 +134,8 @@ export function runQuery(pointer, request, query) {
134
134
  avg,
135
135
  max,
136
136
  min,
137
+ many,
138
+ one,
137
139
  distinct,
138
140
  // console: connectConsole(res),
139
141
  JSONTag: myJSONTag,
package/src/server.mjs CHANGED
@@ -39,22 +39,11 @@ async function main(options) {
39
39
  limit: '50MB'
40
40
  }))
41
41
 
42
- function loadData() {
43
- return new Promise((resolve,reject) => {
44
- let worker = new Worker(loadWorker)
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
- server.get('/query/*', async (req, res, next) =>
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
- server.post('/query/*', async (req,res) => {
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
- let commandQueue = []
173
-
174
- function loadCommandLog(commandLog) {
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
- let log = fs.readFileSync(commandLog)
179
- if (log) {
180
- let lines = log.split("\n")
181
- for(let line of lines) {
182
- let command = JSONTag.parse(line)
183
- let state = status.get(command.id)
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
- loadCommandLog()
198
- let commandWorkerInstance
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) {