I've got an Express API which has some download functionality, implemented by piping a stream from a fetch call to res. I want to record the amount of data downloaded, so I can track data used by account. My current implementation is:
let bytesSent = 0
res.set({
'content-length': contentLength,
'content-type': contentType,
'content-disposition': `attachment;filename="${filename}"`,
})
download.body.pipe(res)
download.body.on('data', (chunk) => {
bytesSent += chunk.byteLength
})
download.body.on('error', next)
res.on('close', async () => {
// Store bytesSent
})
The problem with this is (I think) it's tracking the data downloaded from source, and not taking into account bandwidth constraints from the client. For example if I download a 180 MB file but cancel the download on the client 20 MB in, it still records 100-180MB.
How can I track the amount of data actually downloaded by the client, rather than downloaded/buffered by the fetch call?
You could try to "decorate" the res.write function itself and record the bytes passing through there. Something like:
const origResWrite = res.write.bind(res);
res.write = (chunk, encoding, callback) => {
// Store byteLength of chunk somewhere - here we just log it
console.log("Writing bytes of size", Buffer.byteLength(chunk));
origResWrite(chunk, encoding, callback);
}
download.body.pipe(res);