apps: make downloadFile async

This commit is contained in:
Girish Ramakrishnan
2021-10-21 15:25:15 -07:00
parent 2e3070a5c6
commit 010024dfd7
2 changed files with 72 additions and 68 deletions
+61 -57
View File
@@ -2455,70 +2455,74 @@ async function listEventlog(app, page, perPage) {
return await eventlog.listPaged(actions, search, page, perPage);
}
function downloadFile(app, filePath, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof filePath, 'string');
assert.strictEqual(typeof callback, 'function');
exec(app, { cmd: [ 'stat', '--printf=%F-%s', filePath ], tty: true }, function (error, stream) {
if (error) return callback(error);
var data = '';
async function drainStream(stream) {
return new Promise((resolve, reject) => {
let data = '';
stream.setEncoding('utf8');
stream.on('error', (error) => reject(new BoxError.FS_ERROR, error.message));
stream.on('data', function (d) { data += d; });
stream.on('end', function () {
var parts = data.split('-');
if (parts.length !== 2) return callback(new BoxError(BoxError.NOT_FOUND, 'file does not exist'));
var type = parts[0], filename, cmd, size;
if (type === 'regular file') {
cmd = [ 'cat', filePath ];
size = parseInt(parts[1], 10);
filename = path.basename(filePath);
if (isNaN(size)) return callback(new BoxError(BoxError.NOT_FOUND, 'file does not exist'));
} else if (type === 'directory') {
cmd = ['tar', 'zcf', '-', '-C', filePath, '.'];
filename = path.basename(filePath) + '.tar.gz';
size = 0; // unknown
} else {
return callback(new BoxError(BoxError.NOT_FOUND, 'only files or dirs can be downloaded'));
}
exec(app, { cmd: cmd , tty: false }, function (error, stream) {
if (error) return callback(error);
var stdoutStream = new TransformStream({
transform: function (chunk, ignoredEncoding, callback) {
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
for (;;) {
if (this._buffer.length < 8) break; // header is 8 bytes
var type = this._buffer.readUInt8(0);
var len = this._buffer.readUInt32BE(4);
if (this._buffer.length < (8 + len)) break; // not enough
var payload = this._buffer.slice(8, 8 + len);
this._buffer = this._buffer.slice(8+len); // consumed
if (type === 1) this.push(payload);
}
callback();
}
});
stream.pipe(stdoutStream);
callback(null, stdoutStream, { filename: filename, size: size });
});
resolve(data);
});
});
}
async function downloadFile(app, filePath) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof filePath, 'string');
const statStream = await exec(app, { cmd: [ 'stat', '--printf=%F-%s', filePath ], tty: true });
const data = await drainStream(statStream);
const parts = data.split('-');
if (parts.length !== 2) throw new BoxError(BoxError.NOT_FOUND, 'file does not exist');
let type = parts[0], filename, cmd, size;
if (type === 'regular file') {
cmd = [ 'cat', filePath ];
size = parseInt(parts[1], 10);
filename = path.basename(filePath);
if (isNaN(size)) throw new BoxError(BoxError.NOT_FOUND, 'file does not exist');
} else if (type === 'directory') {
cmd = ['tar', 'zcf', '-', '-C', filePath, '.'];
filename = path.basename(filePath) + '.tar.gz';
size = 0; // unknown
} else {
throw new BoxError(BoxError.NOT_FOUND, 'only files or dirs can be downloaded');
}
const inputStream = await exec(app, { cmd, tty: false });
// transforms the docker stream into a normal stream
const stdoutStream = new TransformStream({
transform: function (chunk, ignoredEncoding, callback) {
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
for (;;) {
if (this._buffer.length < 8) break; // header is 8 bytes
var type = this._buffer.readUInt8(0);
var len = this._buffer.readUInt32BE(4);
if (this._buffer.length < (8 + len)) break; // not enough
var payload = this._buffer.slice(8, 8 + len);
this._buffer = this._buffer.slice(8+len); // consumed
if (type === 1) this.push(payload);
}
callback();
}
});
inputStream.pipe(stdoutStream);
return { stream: stdoutStream, filename, size };
}
async function uploadFile(app, sourceFilePath, destFilePath) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof sourceFilePath, 'string');
+11 -11
View File
@@ -798,26 +798,26 @@ async function uploadFile(req, res, next) {
next(new HttpSuccess(202, {}));
}
function downloadFile(req, res, next) {
async function downloadFile(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
if (typeof req.query.file !== 'string' || !req.query.file) return next(new HttpError(400, 'file query argument must be provided'));
req.clearTimeout();
apps.downloadFile(req.app, req.query.file, function (error, stream, info) {
if (error) return next(BoxError.toHttpError(error));
const [error, result] = await safe(apps.downloadFile(req.app, req.query.file));
if (error) return next(BoxError.toHttpError(error));
var headers = {
'Content-Type': 'application/octet-stream',
'Content-Disposition': `attachment; filename*=utf-8''${encodeURIComponent(info.filename)}` // RFC 2184 section 4
};
if (info.size) headers['Content-Length'] = info.size;
const { stream, filename, size } = result;
const headers = {
'Content-Type': 'application/octet-stream',
'Content-Disposition': `attachment; filename*=utf-8''${encodeURIComponent(filename)}` // RFC 2184 section 4
};
if (size) headers['Content-Length'] = size;
res.writeHead(200, headers);
res.writeHead(200, headers);
stream.pipe(res);
});
stream.pipe(res);
}
async function setMounts(req, res, next) {