UNPKG

@jsreport/jsreport-core

Version:
225 lines (174 loc) 7.24 kB
/*! * Copyright(c) 2018 Jan Blaha * * Orchestration of the rendering process */ const { Readable } = require('stream') const extend = require('node.extend.without.arrays') const ExecuteEngine = require('./executeEngine') const Request = require('../../shared/request') const generateRequestId = require('../../shared/generateRequestId') const resolveReferences = require('./resolveReferences.js') const moduleHelper = require('./moduleHelper') module.exports = (reporter) => { moduleHelper(reporter) const executeEngine = ExecuteEngine(reporter) async function beforeRender (reporter, request, response) { if (!request.template) { throw reporter.createError('template property must be defined', { statusCode: 400 }) } await reporter.beforeRenderListeners.fire(request, response) await reporter.validateRenderListeners.fire(request, response) } async function invokeRender (reporter, request, response) { if (!request.template.engine) { throw reporter.createError('Engine must be specified', { statusCode: 400 }) } const engine = reporter.extensionsManager.engines.find((e) => e.name === request.template.engine) if (!engine) { throw reporter.createError(`Engine '${request.template.engine}' not found. If this is a custom engine make sure it's properly installed from npm`, { statusCode: 400 }) } if ( request.data != null && typeof request.data === 'object' && Array.isArray(request.data) ) { throw reporter.createError('Request data can not be an array. you should pass an object in request.data input', { statusCode: 400 }) } const engineProfilerEvent = reporter.profiler.emit({ type: 'operationStart', subtype: 'engine', name: request.template.engine }, request, response) reporter.logger.debug(`Rendering engine ${engine.name}`, request) const engineRes = await executeEngine(engine, request) response.content = Buffer.from(engineRes.content != null ? engineRes.content : '') reporter.profiler.emit({ type: 'operationEnd', operationId: engineProfilerEvent.operationId }, request, response) await reporter.afterTemplatingEnginesExecutedListeners.fire(request, response) if (!request.template.recipe) { throw reporter.createError('Recipe must be specified', { statusCode: 400 }) } const recipe = reporter.extensionsManager.recipes.find((r) => r.name === request.template.recipe) if (!recipe) { throw reporter.createError(`Recipe '${request.template.recipe}' not found. If this is a custom recipe make sure it's properly installed from npm.`, { statusCode: 400 }) } const recipeProfilerEvent = reporter.profiler.emit({ type: 'operationStart', subtype: 'recipe', name: request.template.recipe }, request, response) reporter.logger.debug('Executing recipe ' + request.template.recipe, request) await recipe.execute(request, response) reporter.profiler.emit({ type: 'operationEnd', operationId: recipeProfilerEvent.operationId }, request, response) } async function afterRender (reporter, request, response) { await reporter.afterRenderListeners.fire(request, response) response.stream = Readable.from(response.content) response.result = response.stream return response } return async (req, parentReq) => { const request = Request(req, parentReq) const response = { meta: {} } let renderStartProfilerEvent try { if (request.context.id == null) { request.context.id = generateRequestId() } renderStartProfilerEvent = await reporter.profiler.renderStart(request, parentReq, response) request.data = resolveReferences(request.data) || {} if (request.options.reportName) { response.meta.reportName = String(request.options.reportName) } else { response.meta.reportName = 'report' } if (parentReq == null) { reporter.requestModulesCache.set(request.context.rootId, Object.create(null)) } reporter.logger.info(`Starting rendering${childMsgDecorate(request)} request${counterMsgDecorate(request)}${userMsgDecorate(request)}`, request) // TODO /* if (reporter.entityTypeValidator.getSchema('TemplateType') != null) { const templateValidationResult = reporter.entityTypeValidator.validate('TemplateType', request.template, { rootPrefix: 'template' }) if (!templateValidationResult.valid) { throw reporter.createError(`template input in request contain values that does not match the defined schema. ${templateValidationResult.fullErrorMessage}`, { statusCode: 400 }) } } */ await beforeRender(reporter, request, response) await invokeRender(reporter, request, response) await afterRender(reporter, request, response) reporter.logger.info(`Rendering${childMsgDecorate(request)} request${counterMsgDecorate(request)} finished in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request) response.meta.logs = request.context.logs if (parentReq) { parentReq.context.logs = parentReq.context.logs.concat(request.context.logs) parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared) } await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response) return response } catch (e) { await reporter.renderErrorListeners.fire(request, response, e) const logFn = e.weak ? reporter.logger.warn : reporter.logger.error const errorMessage = reporter.createError(`Error when processing${childMsgDecorate(request)} render request${counterMsgDecorate(request)}`, { original: e }).message logFn(`${errorMessage}${e.stack != null ? '\n' + e.stack : ''}`, request) logFn(`Rendering${childMsgDecorate(request)} request${counterMsgDecorate(request)} finished with error in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request) if ( parentReq && parentReq.context && parentReq.context.logs && request.context && request.context.logs ) { parentReq.context.logs = parentReq.context.logs.concat(request.context.logs) } if (parentReq) { parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared) } e.logged = true if (renderStartProfilerEvent) { await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response, e) } throw e } finally { if (parentReq == null) { reporter.requestModulesCache.delete(request.context.rootId) } } } } function childMsgDecorate (req) { if (!req.context.isChildRequest) { return '' } return ' (child)' } function counterMsgDecorate (req) { if (req.context.isChildRequest) { return '' } return ` ${req.context.reportCounter}` } function userMsgDecorate (req) { if (!req.context.user) { return '' } return ` (user: ${req.context.user.name})` }