@jsreport/jsreport-core
Version:
javascript based business reporting
89 lines (73 loc) • 2.78 kB
JavaScript
const bytes = require('bytes')
const { Readable } = require('stream')
/*
This adds jsreport.templatingEngines.createStream to the helpers proxy allowing to write giant texts to output
which would otherwise hit nodejs max string size limit.
Example usage
===================
async function myEach(items, options) {
const stream = await jsreport.templatingEngines.createStream()
for (let i = 0; i < items.length; i++) {
await stream.write(options.fn())
}
return await stream.toResult()
}
*/
module.exports = (reporter) => {
reporter.afterTemplatingEnginesExecutedListeners.add('streamedEach', async (req, res) => {
if (req.context.engineStreamEnabled !== true) {
return
}
const content = (await res.output.getBuffer()).toString()
const matches = [...content.matchAll(/{#stream ([^{}]{0,500})}/g)]
async function * transform () {
if (matches.length) {
yield content.substring(0, matches[0].index)
for (let i = 0; i < matches.length; i++) {
const { stream } = reporter.readTempFileStream(matches[i][1])
for await (const content of stream) {
yield content
}
if (i < matches.length - 1) {
yield content.substring(matches[i].index + matches[i][0].length, matches[i + 1].index)
} else {
yield content.substring(matches[i].index + matches[i][0].length)
}
}
} else {
yield content
}
}
await res.output.update(Readable.from(transform()))
})
reporter.extendProxy((proxy, req, {
runInSandbox,
context,
getTopLevelFunctions
}) => {
if (proxy.templatingEngines) {
proxy.templatingEngines.createStream = async (opts = {}) => {
req.context.engineStreamEnabled = true
const bufferSize = bytes(opts.bufferSize || '10mb')
let buf = ''
// using proxy.openTempFile to respect limits of temp files in sandbox
const { fileHandle, filename } = await proxy.openTempFile((uuid) => `${uuid}.stream`, 'a')
proxy.templatingEngines.addFinishListener(() => fileHandle.close().catch((e) => reporter.logger.error('Failed to close temp file handle', e, req)))
return {
write: async (text) => {
const realText = await proxy.templatingEngines.waitForAsyncHelper(text)
buf += realText
if (buf.length > bufferSize) {
await fileHandle.appendFile(buf)
buf = ''
}
},
toResult: async () => {
await fileHandle.appendFile(buf)
return `{#stream ${filename}}`
}
}
}
}
})
}