Files
speckle-server/packages/server/modules/core/rest/diffDownload.js
T

96 lines
2.8 KiB
JavaScript

'use strict'
const zlib = require( 'zlib' )
const Busboy = require( 'busboy' )
const debug = require( 'debug' )
const appRoot = require( 'app-root-path' )
const cors = require( 'cors' )
const { matomoMiddleware } = require( `${appRoot}/logging/matomoHelper` )
const { contextMiddleware, validateScopes, authorizeResolver } = require( `${appRoot}/modules/shared` )
const { validatePermissionsReadStream } = require( './authUtils' )
const { getObjectsStream } = require( '../services/objects' )
module.exports = ( app ) => {
app.options( '/api/getobjects/:streamId', cors() )
app.post( '/api/getobjects/:streamId', cors(), contextMiddleware, matomoMiddleware, async ( req, res ) => {
let hasStreamAccess = await validatePermissionsReadStream( req.params.streamId, req )
if ( !hasStreamAccess.result ) {
return res.status( hasStreamAccess.status ).end()
}
let childrenList = JSON.parse( req.body.objects )
let simpleText = req.headers.accept === 'text/plain'
let dbStream = await getObjectsStream( { streamId: req.params.streamId, objectIds: childrenList } )
let currentChunkSize = 0
let maxChunkSize = 50000
let chunk = simpleText ? '' : [ ]
let isFirstBuffer = true
res.writeHead( 200, { 'Content-Encoding': 'gzip', 'Content-Type': simpleText ? 'text/plain' : 'application/json' } )
const gzip = zlib.createGzip( )
if ( !simpleText ) gzip.write( '[' )
// helper func to flush the gzip buffer
const writeBuffer = () => {
if ( simpleText ) {
gzip.write( chunk )
} else {
if ( !isFirstBuffer ) {
gzip.write( ',' )
}
gzip.write( chunk.join( ',' ) )
}
gzip.flush( )
chunk = simpleText ? '' : [ ]
isFirstBuffer = false
}
let k = 0
let requestDropped = false
dbStream.on( 'data', row => {
try {
let data = JSON.stringify( row.data )
currentChunkSize += Buffer.byteLength( data, 'utf8' )
if ( simpleText ) {
chunk += `${row.data.id}\t${data}\n`
} else {
chunk.push( data )
}
if ( currentChunkSize >= maxChunkSize ) {
currentChunkSize = 0
writeBuffer()
}
k++
} catch ( e ) {
requestDropped = true
debug( 'speckle:error' )( `'Failed to find object, or object is corrupted.' ${req.params.objectId}` )
return
}
} )
dbStream.on( 'error', err => {
debug( 'speckle:error' )( `Error in streaming object children for ${req.params.objectId}: ${err}` )
requestDropped = true
return
} )
dbStream.on( 'end', ( ) => {
if ( currentChunkSize !== 0 ) {
writeBuffer()
}
if ( !simpleText ) gzip.write( ']' )
gzip.end( )
} )
// 🚬
gzip.pipe( res )
} )
}