@jsreport/jsreport-core 3.0.0 → 3.1.2-test.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/LICENSE +166 -166
- package/README.md +298 -284
- package/index.js +29 -27
- package/lib/main/blobStorage/blobStorage.js +52 -47
- package/lib/main/blobStorage/inMemoryProvider.js +27 -27
- package/lib/main/blobStorage/mainActions.js +24 -24
- package/lib/main/createDefaultLoggerFormat.js +17 -17
- package/lib/main/defaults.js +14 -14
- package/lib/main/extensions/discover.js +20 -20
- package/lib/main/extensions/extensionsManager.js +264 -265
- package/lib/main/extensions/fileUtils.js +56 -55
- package/lib/main/extensions/findVersion.js +49 -53
- package/lib/main/extensions/locationCache.js +103 -97
- package/lib/main/extensions/sorter.js +10 -10
- package/lib/main/extensions/validateMinimalVersion.js +50 -50
- package/lib/main/folders/cascadeFolderRemove.js +25 -25
- package/lib/main/folders/getEntitiesInFolder.js +53 -53
- package/lib/main/folders/index.js +42 -42
- package/lib/main/folders/moveBetweenFolders.js +354 -354
- package/lib/main/folders/validateDuplicatedName.js +107 -107
- package/lib/main/folders/validateReservedName.js +53 -53
- package/lib/main/logger.js +244 -244
- package/lib/main/migration/resourcesToAssets.js +230 -210
- package/lib/main/migration/xlsxTemplatesToAssets.js +128 -118
- package/lib/main/monitoring.js +91 -91
- package/lib/main/optionsLoad.js +237 -237
- package/lib/main/optionsSchema.js +237 -237
- package/lib/main/profiler.js +2 -1
- package/lib/main/reporter.js +575 -578
- package/lib/main/schemaValidator.js +252 -252
- package/lib/main/settings.js +154 -154
- package/lib/main/store/checkDuplicatedId.js +27 -27
- package/lib/main/store/collection.js +329 -329
- package/lib/main/store/documentStore.js +469 -469
- package/lib/main/store/mainActions.js +28 -28
- package/lib/main/store/memoryStoreProvider.js +99 -99
- package/lib/main/store/queue.js +48 -48
- package/lib/main/store/referenceUtils.js +251 -251
- package/lib/main/store/setupValidateId.js +43 -43
- package/lib/main/store/setupValidateShortid.js +71 -71
- package/lib/main/store/transaction.js +69 -69
- package/lib/main/store/typeUtils.js +180 -180
- package/lib/main/templates.js +34 -34
- package/lib/main/validateEntityName.js +62 -62
- package/lib/shared/createError.js +36 -36
- package/lib/shared/encryption.js +114 -114
- package/lib/shared/folders/index.js +11 -11
- package/lib/shared/folders/normalizeEntityPath.js +15 -15
- package/lib/shared/folders/resolveEntityFromPath.js +88 -88
- package/lib/shared/folders/resolveEntityPath.js +46 -46
- package/lib/shared/folders/resolveFolderFromPath.js +38 -38
- package/lib/shared/generateRequestId.js +4 -4
- package/lib/shared/listenerCollection.js +169 -0
- package/lib/shared/normalizeMetaFromLogs.js +30 -30
- package/lib/shared/reporter.js +128 -123
- package/lib/shared/request.js +64 -64
- package/lib/shared/tempFilesHandler.js +81 -81
- package/lib/shared/templates.js +82 -82
- package/lib/static/helpers.js +33 -33
- package/lib/worker/blobStorage.js +34 -34
- package/lib/worker/defaultProxyExtend.js +46 -46
- package/lib/worker/documentStore.js +49 -49
- package/lib/worker/extensionsManager.js +17 -17
- package/lib/worker/logger.js +48 -48
- package/lib/worker/render/diff.js +138 -138
- package/lib/worker/render/executeEngine.js +227 -190
- package/lib/worker/render/htmlRecipe.js +10 -10
- package/lib/worker/render/moduleHelper.js +45 -43
- package/lib/worker/render/noneEngine.js +12 -12
- package/lib/worker/render/profiler.js +158 -158
- package/lib/worker/render/render.js +213 -209
- package/lib/worker/render/resolveReferences.js +60 -60
- package/lib/worker/reporter.js +192 -187
- package/lib/worker/sandbox/runInSandbox.js +13 -4
- package/lib/worker/sandbox/safeSandbox.js +828 -822
- package/lib/worker/templates.js +78 -78
- package/lib/worker/workerHandler.js +54 -54
- package/package.json +92 -92
- package/test/blobStorage/common.js +21 -21
- package/test/store/common.js +1449 -1449
package/lib/main/reporter.js
CHANGED
|
@@ -1,578 +1,575 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright(c) 2018 Jan Blaha
|
|
3
|
-
*
|
|
4
|
-
* Reporter main class including all methods jsreport-core exposes.
|
|
5
|
-
*/
|
|
6
|
-
const path = require('path')
|
|
7
|
-
const { Readable } = require('stream')
|
|
8
|
-
const Reaper = require('reap2')
|
|
9
|
-
const optionsLoad = require('./optionsLoad')
|
|
10
|
-
const { createLogger, configureLogger, silentLogs } = require('./logger')
|
|
11
|
-
const checkEntityName = require('./validateEntityName')
|
|
12
|
-
const DocumentStore = require('./store/documentStore')
|
|
13
|
-
const BlobStorage = require('./blobStorage/blobStorage')
|
|
14
|
-
const ExtensionsManager = require('./extensions/extensionsManager')
|
|
15
|
-
const Settings = require('./settings')
|
|
16
|
-
const SchemaValidator = require('./schemaValidator')
|
|
17
|
-
const { getRootSchemaOptions, extendRootSchemaOptions } = require('./optionsSchema')
|
|
18
|
-
const Templates = require('./templates')
|
|
19
|
-
const Folders = require('./folders')
|
|
20
|
-
const WorkersManager = require('@jsreport/advanced-workers')
|
|
21
|
-
const { validateDuplicatedName } = require('./folders/validateDuplicatedName')
|
|
22
|
-
const { validateReservedName } = require('./folders/validateReservedName')
|
|
23
|
-
const setupValidateId = require('./store/setupValidateId')
|
|
24
|
-
const setupValidateShortid = require('./store/setupValidateShortid')
|
|
25
|
-
const documentStoreActions = require('./store/mainActions')
|
|
26
|
-
const blobStorageActions = require('./blobStorage/mainActions')
|
|
27
|
-
const Reporter = require('../shared/reporter')
|
|
28
|
-
const Request = require('../shared/request')
|
|
29
|
-
const generateRequestId = require('../shared/generateRequestId')
|
|
30
|
-
const Profiler = require('./profiler')
|
|
31
|
-
const Monitoring = require('./monitoring')
|
|
32
|
-
const migrateXlsxTemplatesToAssets = require('./migration/xlsxTemplatesToAssets')
|
|
33
|
-
const migrateResourcesToAssets = require('./migration/resourcesToAssets')
|
|
34
|
-
const semver = require('semver')
|
|
35
|
-
|
|
36
|
-
class MainReporter extends Reporter {
|
|
37
|
-
constructor (options, defaults) {
|
|
38
|
-
super(options)
|
|
39
|
-
|
|
40
|
-
if (!semver.satisfies(process.versions.node, '>=16.11.0')) {
|
|
41
|
-
throw this.createError('jsreport needs at least node 16.11.0 to run.')
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.defaults = defaults || {}
|
|
45
|
-
this._fnAfterConfigLoaded = () => {}
|
|
46
|
-
this._reaperTimerRef = null
|
|
47
|
-
this._extraPathsToCleanupCollection = new Set()
|
|
48
|
-
|
|
49
|
-
this._initialized = false
|
|
50
|
-
this._initializing = false
|
|
51
|
-
|
|
52
|
-
this._initExecution = {}
|
|
53
|
-
|
|
54
|
-
this._initExecution.promise = new Promise((resolve, reject) => {
|
|
55
|
-
this._initExecution.resolve = resolve
|
|
56
|
-
this._initExecution.reject = resolve
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
this._mainActions = new Map()
|
|
60
|
-
|
|
61
|
-
this.settings = new Settings()
|
|
62
|
-
this.extensionsManager = ExtensionsManager(this)
|
|
63
|
-
|
|
64
|
-
this.optionsValidator = new SchemaValidator({
|
|
65
|
-
rootSchema: getRootSchemaOptions()
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
this.entityTypeValidator = new SchemaValidator()
|
|
69
|
-
|
|
70
|
-
this.logger = createLogger()
|
|
71
|
-
this.beforeMainActionListeners = this.createListenerCollection()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
discover () {
|
|
75
|
-
this.options.discover = true
|
|
76
|
-
return this
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Manual registration of the extension. Once calling `use` the auto discovery of extensions is turned off if not explicitly
|
|
81
|
-
* turned on.
|
|
82
|
-
* jsreport.use(require('@jsreport/jsreport-jsrender')())
|
|
83
|
-
* @param {Object || Function} extensions
|
|
84
|
-
* @return {Reporter} for chaining
|
|
85
|
-
* @public
|
|
86
|
-
*/
|
|
87
|
-
use (extension) {
|
|
88
|
-
this.extensionsManager.use(extension)
|
|
89
|
-
return this
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async extensionsLoad (opts) {
|
|
93
|
-
const appliedConfigFile = await optionsLoad({
|
|
94
|
-
defaults: this.defaults,
|
|
95
|
-
options: this.options,
|
|
96
|
-
validator: this.optionsValidator,
|
|
97
|
-
onConfigLoaded: async () => {
|
|
98
|
-
await this._fnAfterConfigLoaded(this)
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
configureLogger(this.logger, this.options.logger)
|
|
103
|
-
|
|
104
|
-
if (this.options.logger && this.options.logger.silent === true) {
|
|
105
|
-
silentLogs(this.logger)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.logger.info(`Initializing jsreport (version: ${this.version}, configuration file: ${appliedConfigFile || 'none'}, nodejs: ${process.versions.node})`)
|
|
109
|
-
|
|
110
|
-
await this.extensionsManager.load(opts)
|
|
111
|
-
|
|
112
|
-
const newRootSchema = extendRootSchemaOptions(
|
|
113
|
-
getRootSchemaOptions(),
|
|
114
|
-
this.extensionsManager.availableExtensions.map(ex => ({
|
|
115
|
-
name: ex.name,
|
|
116
|
-
schema: ex.optionsSchema
|
|
117
|
-
}))
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
this.optionsValidator.setRootSchema(newRootSchema)
|
|
121
|
-
|
|
122
|
-
const rootOptionsValidation = this.optionsValidator.validateRoot(this.options, {
|
|
123
|
-
rootPrefix: 'rootOptions',
|
|
124
|
-
// extensions was validated already in extensions load
|
|
125
|
-
ignore: ['properties.extensions']
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
if (!rootOptionsValidation.valid) {
|
|
129
|
-
throw new Error(`options contain values that does not match the defined full root schema. ${rootOptionsValidation.fullErrorMessage}`)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return this
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Hook to alter configuration after it was loaded and merged
|
|
137
|
-
* jsreport.afterConfigLoaded(function(reporter) { .. do your stuff ..})
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* @public
|
|
141
|
-
*/
|
|
142
|
-
afterConfigLoaded (fn) {
|
|
143
|
-
this._fnAfterConfigLoaded = fn
|
|
144
|
-
return this
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async waitForInit () {
|
|
148
|
-
await this._initExecution.promise
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Required async method to be called before rendering.
|
|
153
|
-
*
|
|
154
|
-
* @return {Promise} initialization is done, promise value is Reporter instance for chaining
|
|
155
|
-
* @public
|
|
156
|
-
*/
|
|
157
|
-
async init () {
|
|
158
|
-
this.closing = this.closed = false
|
|
159
|
-
if (this._initialized || this._initializing) {
|
|
160
|
-
throw new Error('jsreport already initialized or just initializing. Make sure init is called only once')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
super.init()
|
|
164
|
-
|
|
165
|
-
this._initializing = true
|
|
166
|
-
|
|
167
|
-
if (this.compilation) {
|
|
168
|
-
this.compilation.resource('sandbox.js', require.resolve('vm2/lib/sandbox.js'))
|
|
169
|
-
this.compilation.resource('contextify.js', require.resolve('vm2/lib/contextify.js'))
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
await this.
|
|
210
|
-
await this.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
this.initializeListeners.insert(0, 'core-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
this.
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
this.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* @
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
req
|
|
324
|
-
req.context
|
|
325
|
-
req.context.
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
req.options
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
err.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
err.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
logFn
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
this
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
module.exports = MainReporter
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright(c) 2018 Jan Blaha
|
|
3
|
+
*
|
|
4
|
+
* Reporter main class including all methods jsreport-core exposes.
|
|
5
|
+
*/
|
|
6
|
+
const path = require('path')
|
|
7
|
+
const { Readable } = require('stream')
|
|
8
|
+
const Reaper = require('reap2')
|
|
9
|
+
const optionsLoad = require('./optionsLoad')
|
|
10
|
+
const { createLogger, configureLogger, silentLogs } = require('./logger')
|
|
11
|
+
const checkEntityName = require('./validateEntityName')
|
|
12
|
+
const DocumentStore = require('./store/documentStore')
|
|
13
|
+
const BlobStorage = require('./blobStorage/blobStorage')
|
|
14
|
+
const ExtensionsManager = require('./extensions/extensionsManager')
|
|
15
|
+
const Settings = require('./settings')
|
|
16
|
+
const SchemaValidator = require('./schemaValidator')
|
|
17
|
+
const { getRootSchemaOptions, extendRootSchemaOptions } = require('./optionsSchema')
|
|
18
|
+
const Templates = require('./templates')
|
|
19
|
+
const Folders = require('./folders')
|
|
20
|
+
const WorkersManager = require('@jsreport/advanced-workers')
|
|
21
|
+
const { validateDuplicatedName } = require('./folders/validateDuplicatedName')
|
|
22
|
+
const { validateReservedName } = require('./folders/validateReservedName')
|
|
23
|
+
const setupValidateId = require('./store/setupValidateId')
|
|
24
|
+
const setupValidateShortid = require('./store/setupValidateShortid')
|
|
25
|
+
const documentStoreActions = require('./store/mainActions')
|
|
26
|
+
const blobStorageActions = require('./blobStorage/mainActions')
|
|
27
|
+
const Reporter = require('../shared/reporter')
|
|
28
|
+
const Request = require('../shared/request')
|
|
29
|
+
const generateRequestId = require('../shared/generateRequestId')
|
|
30
|
+
const Profiler = require('./profiler')
|
|
31
|
+
const Monitoring = require('./monitoring')
|
|
32
|
+
const migrateXlsxTemplatesToAssets = require('./migration/xlsxTemplatesToAssets')
|
|
33
|
+
const migrateResourcesToAssets = require('./migration/resourcesToAssets')
|
|
34
|
+
const semver = require('semver')
|
|
35
|
+
|
|
36
|
+
class MainReporter extends Reporter {
|
|
37
|
+
constructor (options, defaults) {
|
|
38
|
+
super(options)
|
|
39
|
+
|
|
40
|
+
if (!semver.satisfies(process.versions.node, '>=16.11.0')) {
|
|
41
|
+
throw this.createError('jsreport needs at least node 16.11.0 to run.')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.defaults = defaults || {}
|
|
45
|
+
this._fnAfterConfigLoaded = () => {}
|
|
46
|
+
this._reaperTimerRef = null
|
|
47
|
+
this._extraPathsToCleanupCollection = new Set()
|
|
48
|
+
|
|
49
|
+
this._initialized = false
|
|
50
|
+
this._initializing = false
|
|
51
|
+
|
|
52
|
+
this._initExecution = {}
|
|
53
|
+
|
|
54
|
+
this._initExecution.promise = new Promise((resolve, reject) => {
|
|
55
|
+
this._initExecution.resolve = resolve
|
|
56
|
+
this._initExecution.reject = resolve
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
this._mainActions = new Map()
|
|
60
|
+
|
|
61
|
+
this.settings = new Settings()
|
|
62
|
+
this.extensionsManager = ExtensionsManager(this)
|
|
63
|
+
|
|
64
|
+
this.optionsValidator = new SchemaValidator({
|
|
65
|
+
rootSchema: getRootSchemaOptions()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
this.entityTypeValidator = new SchemaValidator()
|
|
69
|
+
|
|
70
|
+
this.logger = createLogger()
|
|
71
|
+
this.beforeMainActionListeners = this.createListenerCollection('beforeMainAction')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
discover () {
|
|
75
|
+
this.options.discover = true
|
|
76
|
+
return this
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Manual registration of the extension. Once calling `use` the auto discovery of extensions is turned off if not explicitly
|
|
81
|
+
* turned on.
|
|
82
|
+
* jsreport.use(require('@jsreport/jsreport-jsrender')())
|
|
83
|
+
* @param {Object || Function} extensions
|
|
84
|
+
* @return {Reporter} for chaining
|
|
85
|
+
* @public
|
|
86
|
+
*/
|
|
87
|
+
use (extension) {
|
|
88
|
+
this.extensionsManager.use(extension)
|
|
89
|
+
return this
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async extensionsLoad (opts) {
|
|
93
|
+
const appliedConfigFile = await optionsLoad({
|
|
94
|
+
defaults: this.defaults,
|
|
95
|
+
options: this.options,
|
|
96
|
+
validator: this.optionsValidator,
|
|
97
|
+
onConfigLoaded: async () => {
|
|
98
|
+
await this._fnAfterConfigLoaded(this)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
configureLogger(this.logger, this.options.logger)
|
|
103
|
+
|
|
104
|
+
if (this.options.logger && this.options.logger.silent === true) {
|
|
105
|
+
silentLogs(this.logger)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.logger.info(`Initializing jsreport (version: ${this.version}, configuration file: ${appliedConfigFile || 'none'}, nodejs: ${process.versions.node})`)
|
|
109
|
+
|
|
110
|
+
await this.extensionsManager.load(opts)
|
|
111
|
+
|
|
112
|
+
const newRootSchema = extendRootSchemaOptions(
|
|
113
|
+
getRootSchemaOptions(),
|
|
114
|
+
this.extensionsManager.availableExtensions.map(ex => ({
|
|
115
|
+
name: ex.name,
|
|
116
|
+
schema: ex.optionsSchema
|
|
117
|
+
}))
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
this.optionsValidator.setRootSchema(newRootSchema)
|
|
121
|
+
|
|
122
|
+
const rootOptionsValidation = this.optionsValidator.validateRoot(this.options, {
|
|
123
|
+
rootPrefix: 'rootOptions',
|
|
124
|
+
// extensions was validated already in extensions load
|
|
125
|
+
ignore: ['properties.extensions']
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
if (!rootOptionsValidation.valid) {
|
|
129
|
+
throw new Error(`options contain values that does not match the defined full root schema. ${rootOptionsValidation.fullErrorMessage}`)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return this
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Hook to alter configuration after it was loaded and merged
|
|
137
|
+
* jsreport.afterConfigLoaded(function(reporter) { .. do your stuff ..})
|
|
138
|
+
*
|
|
139
|
+
*
|
|
140
|
+
* @public
|
|
141
|
+
*/
|
|
142
|
+
afterConfigLoaded (fn) {
|
|
143
|
+
this._fnAfterConfigLoaded = fn
|
|
144
|
+
return this
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async waitForInit () {
|
|
148
|
+
await this._initExecution.promise
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Required async method to be called before rendering.
|
|
153
|
+
*
|
|
154
|
+
* @return {Promise} initialization is done, promise value is Reporter instance for chaining
|
|
155
|
+
* @public
|
|
156
|
+
*/
|
|
157
|
+
async init () {
|
|
158
|
+
this.closing = this.closed = false
|
|
159
|
+
if (this._initialized || this._initializing) {
|
|
160
|
+
throw new Error('jsreport already initialized or just initializing. Make sure init is called only once')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
super.init()
|
|
164
|
+
|
|
165
|
+
this._initializing = true
|
|
166
|
+
|
|
167
|
+
if (this.compilation) {
|
|
168
|
+
this.compilation.resource('sandbox.js', require.resolve('vm2/lib/sandbox.js'))
|
|
169
|
+
this.compilation.resource('contextify.js', require.resolve('vm2/lib/contextify.js'))
|
|
170
|
+
this.compilation.resource('fixasync.js', require.resolve('vm2/lib/fixasync.js'))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
this._registerLogMainAction()
|
|
175
|
+
await this.extensionsLoad()
|
|
176
|
+
|
|
177
|
+
this.documentStore = DocumentStore(Object.assign({}, this.options, { logger: this.logger }), this.entityTypeValidator, this.encryption)
|
|
178
|
+
documentStoreActions(this)
|
|
179
|
+
this.blobStorage = BlobStorage(this, this.options)
|
|
180
|
+
blobStorageActions(this)
|
|
181
|
+
Templates(this)
|
|
182
|
+
Profiler(this)
|
|
183
|
+
Monitoring(this)
|
|
184
|
+
|
|
185
|
+
this.folders = Object.assign(this.folders, Folders(this))
|
|
186
|
+
|
|
187
|
+
this.settings.registerEntity(this.documentStore)
|
|
188
|
+
|
|
189
|
+
this.options.blobStorage = this.options.blobStorage || {}
|
|
190
|
+
|
|
191
|
+
if (this.options.blobStorage.provider == null) {
|
|
192
|
+
this.options.blobStorage.provider = this.options.store.provider
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (this.options.blobStorage.provider === 'memory') {
|
|
196
|
+
this.blobStorage.registerProvider(require('./blobStorage/inMemoryProvider.js')(this.options))
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
await this.extensionsManager.init()
|
|
200
|
+
|
|
201
|
+
this.logger.info(`Using general timeout for rendering (reportTimeout: ${this.options.reportTimeout})`)
|
|
202
|
+
|
|
203
|
+
if (this.options.store.provider === 'memory') {
|
|
204
|
+
this.logger.info(`Using ${this.options.store.provider} provider for template store. The saved templates will be lost after restart`)
|
|
205
|
+
} else {
|
|
206
|
+
this.logger.info(`Using ${this.options.store.provider} provider for template store.`)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
await this.documentStore.init()
|
|
210
|
+
await this.blobStorage.init()
|
|
211
|
+
await this.settings.init(this.documentStore, this.authorization)
|
|
212
|
+
|
|
213
|
+
const extensionsForWorkers = this.extensionsManager.extensions.filter(e => e.worker)
|
|
214
|
+
|
|
215
|
+
const workersManagerOptions = {
|
|
216
|
+
...this.options.sandbox,
|
|
217
|
+
options: { ...this.options },
|
|
218
|
+
// we do map and copy to unproxy the value
|
|
219
|
+
extensionsDefs: extensionsForWorkers.map(e => Object.assign({}, e)),
|
|
220
|
+
documentStore: {
|
|
221
|
+
// we do copy to unproxy the value of entityTypes
|
|
222
|
+
model: {
|
|
223
|
+
...this.documentStore.model,
|
|
224
|
+
entityTypes: { ...this.documentStore.model.entityTypes }
|
|
225
|
+
},
|
|
226
|
+
collections: Object.keys(this.documentStore.collections)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const workersManagerSystemOptions = {
|
|
231
|
+
initTimeout: this.options.workers.initTimeout,
|
|
232
|
+
numberOfWorkers: this.options.workers.numberOfWorkers,
|
|
233
|
+
workerModule: path.join(__dirname, '../worker', 'workerHandler.js'),
|
|
234
|
+
resourceLimits: this.options.workers.resourceLimits
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// adding the validation of shortid after extensions has been loaded
|
|
238
|
+
setupValidateId(this)
|
|
239
|
+
setupValidateShortid(this)
|
|
240
|
+
|
|
241
|
+
this.initializeListeners.insert(0, 'core-resources-migration', () => migrateResourcesToAssets(this))
|
|
242
|
+
this.initializeListeners.insert(0, 'core-xlsxTemplates-migration', () => migrateXlsxTemplatesToAssets(this))
|
|
243
|
+
|
|
244
|
+
await this.initializeListeners.fire()
|
|
245
|
+
|
|
246
|
+
this._workersManager = this._workersManagerFactory
|
|
247
|
+
? this._workersManagerFactory(workersManagerOptions, workersManagerSystemOptions)
|
|
248
|
+
: WorkersManager(workersManagerOptions, workersManagerSystemOptions, this.logger)
|
|
249
|
+
|
|
250
|
+
const workersStart = new Date().getTime()
|
|
251
|
+
|
|
252
|
+
this.logger.info('Initializing worker threads')
|
|
253
|
+
|
|
254
|
+
this.logger.debug(`Extensions in workers: ${extensionsForWorkers.map((e) => e.name).join(', ')}`)
|
|
255
|
+
|
|
256
|
+
await this._workersManager.init(workersManagerOptions)
|
|
257
|
+
|
|
258
|
+
this.logger.info(`${this.options.workers.numberOfWorkers} worker threads initialized in ${new Date().getTime() - workersStart}ms`)
|
|
259
|
+
|
|
260
|
+
this._startReaper(this.getPathsToWatchForAutoCleanup())
|
|
261
|
+
|
|
262
|
+
this.extensionsManager.recipes.push({
|
|
263
|
+
name: 'html'
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
this.extensionsManager.engines.push({
|
|
267
|
+
name: 'none'
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
this.monitoring.init()
|
|
271
|
+
|
|
272
|
+
this.logger.info('reporter initialized')
|
|
273
|
+
this._initialized = true
|
|
274
|
+
this._initExecution.resolve()
|
|
275
|
+
return this
|
|
276
|
+
} catch (e) {
|
|
277
|
+
this.logger.error(`Error occurred during reporter init: ${e.stack}`)
|
|
278
|
+
this._initExecution.reject(new Error(`Reporter initialization failed. ${e.message}`))
|
|
279
|
+
throw e
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* @public
|
|
285
|
+
*/
|
|
286
|
+
addPathToWatchForAutoCleanup (customPath) {
|
|
287
|
+
this._extraPathsToCleanupCollection.add(customPath)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @public
|
|
292
|
+
*/
|
|
293
|
+
getPathsToWatchForAutoCleanup () {
|
|
294
|
+
return [this.options.tempAutoCleanupDirectory].concat(Array.from(this._extraPathsToCleanupCollection.values()))
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async checkValidEntityName (c, doc, req) {
|
|
298
|
+
if (!this.documentStore.model.entitySets[c].entityTypeDef.name) {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
checkEntityName(doc.name)
|
|
303
|
+
|
|
304
|
+
await validateDuplicatedName(this, c, doc, undefined, req)
|
|
305
|
+
|
|
306
|
+
await validateReservedName(this, c, doc)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Main method for invoking rendering
|
|
311
|
+
* render({ template: { content: 'foo', engine: 'none', recipe: 'html' }, data: { foo: 'hello' } })
|
|
312
|
+
*
|
|
313
|
+
* @request {Object}
|
|
314
|
+
* @return {Promise} response.content is output buffer, response.stream is output stream, response.headers contains http applicable headers
|
|
315
|
+
*
|
|
316
|
+
* @public
|
|
317
|
+
*/
|
|
318
|
+
async render (req, parentReq) {
|
|
319
|
+
if (!this._initialized) {
|
|
320
|
+
throw new Error('Not initialized, you need to call jsreport.init().then before rendering')
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
req = Object.assign({}, req)
|
|
324
|
+
req.context = Object.assign({}, req.context)
|
|
325
|
+
req.context.rootId = req.context.rootId || generateRequestId()
|
|
326
|
+
req.context.id = req.context.rootId
|
|
327
|
+
|
|
328
|
+
const worker = await this._workersManager.allocate(req, {
|
|
329
|
+
timeout: this.options.reportTimeout
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
let workerAborted
|
|
333
|
+
if (parentReq && !parentReq.__isJsreportRequest__) {
|
|
334
|
+
const options = parentReq
|
|
335
|
+
parentReq = null
|
|
336
|
+
|
|
337
|
+
if (options.abortEmitter) {
|
|
338
|
+
options.abortEmitter.once('abort', () => {
|
|
339
|
+
workerAborted = true
|
|
340
|
+
worker.release(req).catch((e) => this.logger.error('Failed to release worker ' + e))
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const res = { meta: {} }
|
|
346
|
+
try {
|
|
347
|
+
if (workerAborted) {
|
|
348
|
+
throw this.createError('Request aborted by client')
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
let isDataStoredInWorker = false
|
|
352
|
+
|
|
353
|
+
if (req.rawContent) {
|
|
354
|
+
isDataStoredInWorker = true
|
|
355
|
+
const result = await worker.execute({
|
|
356
|
+
actionName: 'parse',
|
|
357
|
+
req,
|
|
358
|
+
data: {}
|
|
359
|
+
}, {
|
|
360
|
+
timeout: this.options.reportTimeout
|
|
361
|
+
})
|
|
362
|
+
req = result
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
req = Request(req, parentReq)
|
|
366
|
+
|
|
367
|
+
if (isDataStoredInWorker) {
|
|
368
|
+
// we unset this because we want the Request() call in worker to evaluate the data
|
|
369
|
+
// and determine if the original was empty or not
|
|
370
|
+
delete req.context.originalInputDataIsEmpty
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// TODO: we will probably validate in the thread
|
|
374
|
+
if (this.entityTypeValidator.getSchema('TemplateType') != null) {
|
|
375
|
+
const templateValidationResult = this.entityTypeValidator.validate('TemplateType', req.template, { rootPrefix: 'template' })
|
|
376
|
+
|
|
377
|
+
if (!templateValidationResult.valid) {
|
|
378
|
+
throw this.createError(`template input in request contain values that does not match the defined schema. ${templateValidationResult.fullErrorMessage}`, {
|
|
379
|
+
statusCode: 400
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let reportTimeout = this.options.reportTimeout
|
|
385
|
+
|
|
386
|
+
if (
|
|
387
|
+
this.options.enableRequestReportTimeout &&
|
|
388
|
+
req.options &&
|
|
389
|
+
req.options.timeout != null
|
|
390
|
+
) {
|
|
391
|
+
reportTimeout = req
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
await this.beforeRenderListeners.fire(req, res)
|
|
395
|
+
|
|
396
|
+
if (req.context.isFinished) {
|
|
397
|
+
res.stream = Readable.from(res.content)
|
|
398
|
+
return res
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (workerAborted) {
|
|
402
|
+
throw this.createError('Request aborted by client')
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const responseResult = await this.executeWorkerAction('render', {}, {
|
|
406
|
+
timeout: reportTimeout + this.options.reportTimeoutMargin,
|
|
407
|
+
worker
|
|
408
|
+
}, req)
|
|
409
|
+
|
|
410
|
+
Object.assign(res, responseResult)
|
|
411
|
+
await this.afterRenderListeners.fire(req, res)
|
|
412
|
+
res.stream = Readable.from(res.content)
|
|
413
|
+
return res
|
|
414
|
+
} catch (err) {
|
|
415
|
+
if (err.code === 'WORKER_TIMEOUT') {
|
|
416
|
+
err.message = 'Report timeout'
|
|
417
|
+
err.weak = true
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (err.code === 'WORKER_ABORTED') {
|
|
421
|
+
err.message = 'Report cancelled'
|
|
422
|
+
err.weak = true
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!err.logged) {
|
|
426
|
+
const logFn = err.weak ? this.logger.warn : this.logger.error
|
|
427
|
+
logFn(`Report render failed: ${err.message}${err.stack != null ? ' ' + err.stack : ''}`, req)
|
|
428
|
+
}
|
|
429
|
+
await this.renderErrorListeners.fire(req, res, err)
|
|
430
|
+
throw err
|
|
431
|
+
} finally {
|
|
432
|
+
if (!workerAborted) {
|
|
433
|
+
await worker.release(req)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
registerWorkersManagerFactory (workersManagerFactory) {
|
|
439
|
+
this._workersManagerFactory = workersManagerFactory
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
*
|
|
444
|
+
* @public
|
|
445
|
+
*/
|
|
446
|
+
async close () {
|
|
447
|
+
this.closing = true
|
|
448
|
+
this.logger.info('Closing jsreport instance')
|
|
449
|
+
|
|
450
|
+
if (this.monitoring) {
|
|
451
|
+
await this.monitoring.close()
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (this._reaperTimerRef) {
|
|
455
|
+
clearInterval(this._reaperTimerRef)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
await this.closeListeners.fire()
|
|
459
|
+
|
|
460
|
+
if (this._workersManager) {
|
|
461
|
+
await this._workersManager.close()
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (this.documentStore) {
|
|
465
|
+
await this.documentStore.close()
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
this.logger.info('jsreport instance has been closed')
|
|
469
|
+
this.closed = true
|
|
470
|
+
|
|
471
|
+
return this
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
registerMainAction (actionName, fn) {
|
|
475
|
+
this._mainActions.set(actionName, fn)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async _invokeMainAction (data, req) {
|
|
479
|
+
await this.beforeMainActionListeners.fire(data.actionName, data.data, req)
|
|
480
|
+
if (!this._mainActions.has(data.actionName)) {
|
|
481
|
+
throw this.createError(`Main process action ${data.actionName} wasn't registered`)
|
|
482
|
+
}
|
|
483
|
+
return this._mainActions.get(data.actionName)(data.data, req)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
_registerLogMainAction () {
|
|
487
|
+
this.registerMainAction('log', (log, req) => {
|
|
488
|
+
this.logger[log.level](log.message, { ...req, ...log.meta, timestamp: log.timestamp })
|
|
489
|
+
})
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async executeWorkerAction (actionName, data, options = {}, req) {
|
|
493
|
+
req.context.rootId = req.context.rootId || generateRequestId()
|
|
494
|
+
const timeout = options.timeout || 60000
|
|
495
|
+
|
|
496
|
+
const worker = options.worker
|
|
497
|
+
? options.worker
|
|
498
|
+
: await this._workersManager.allocate(req, {
|
|
499
|
+
timeout
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
try {
|
|
503
|
+
const result = await worker.execute({
|
|
504
|
+
actionName,
|
|
505
|
+
data,
|
|
506
|
+
// we set just known props, to avoid cloning failures on express req properties
|
|
507
|
+
req: {
|
|
508
|
+
context: req.context,
|
|
509
|
+
template: req.template,
|
|
510
|
+
data: req.data,
|
|
511
|
+
options: req.options
|
|
512
|
+
}
|
|
513
|
+
}, {
|
|
514
|
+
// TODO add worker timeout
|
|
515
|
+
timeout,
|
|
516
|
+
timeoutErrorMessage: options.timeoutErrorMessage || ('Timeout during worker action ' + actionName),
|
|
517
|
+
executeMain: async (data) => {
|
|
518
|
+
return this._invokeMainAction(data, req)
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
this._workersManager.convertUint8ArrayToBuffer(result)
|
|
522
|
+
return result
|
|
523
|
+
} finally {
|
|
524
|
+
if (!options.worker) {
|
|
525
|
+
await worker.release(req)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Periodical cleaning of folders where recipes are storing files like source html for pdf rendering
|
|
532
|
+
*
|
|
533
|
+
* @private
|
|
534
|
+
*/
|
|
535
|
+
_startReaper (dir) {
|
|
536
|
+
const dirsToWatch = !Array.isArray(dir) ? [dir] : dir
|
|
537
|
+
|
|
538
|
+
if (this.options.autoTempCleanup === false) {
|
|
539
|
+
return
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const threshold = this.options.reportTimeout > 180000 ? this.options.reportTimeout : 180000
|
|
543
|
+
|
|
544
|
+
this.logger.info(`Starting temp files cleanup with ${threshold}ms threshold`)
|
|
545
|
+
|
|
546
|
+
const reaper = new Reaper({ threshold })
|
|
547
|
+
|
|
548
|
+
dirsToWatch.forEach(d => reaper.watch(d))
|
|
549
|
+
|
|
550
|
+
reaper.start((err, files) => {
|
|
551
|
+
if (err) {
|
|
552
|
+
this.logger.error(`Failed to start auto cleanup: ${err.stack}`)
|
|
553
|
+
}
|
|
554
|
+
})
|
|
555
|
+
|
|
556
|
+
this._reaperTimerRef = setInterval(() => {
|
|
557
|
+
try {
|
|
558
|
+
reaper.start((err, files) => {
|
|
559
|
+
if (err) {
|
|
560
|
+
// NOT logging the error anymore because it was confusing users that something bad was happening
|
|
561
|
+
// this.logger.error('Failed to delete temp file: ' + err)
|
|
562
|
+
}
|
|
563
|
+
})
|
|
564
|
+
} catch (e) {
|
|
565
|
+
// NOT logging the error anymore because it was confusing users that something bad was happening
|
|
566
|
+
// catch error in case the reaper can not read directory
|
|
567
|
+
// this.logger.error('Failed to run reaper: ' + e)
|
|
568
|
+
}
|
|
569
|
+
}, 30000 /* check every 30s for old files */)
|
|
570
|
+
|
|
571
|
+
this._reaperTimerRef.unref()
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
module.exports = MainReporter
|