+ Add compression for larger exports
* Temp disable of idle monitor while building large lists * Fix hash tags * Handle no results & other errors
This commit is contained in:
parent
44a4a4aeb4
commit
74b9d587c9
|
@ -26,6 +26,7 @@ const paths = require('path');
|
||||||
const iconv = require('iconv-lite');
|
const iconv = require('iconv-lite');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const uuidv4 = require('uuid/v4');
|
const uuidv4 = require('uuid/v4');
|
||||||
|
const yazl = require('yazl');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
:TODO: document:
|
:TODO: document:
|
||||||
|
@ -71,6 +72,7 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
this.config.tsFormat = this.config.tsFormat || this.client.currentTheme.helpers.getDateTimeFormat('short');
|
this.config.tsFormat = this.config.tsFormat || this.client.currentTheme.helpers.getDateTimeFormat('short');
|
||||||
this.config.descWidth = this.config.descWidth || 45; // ie FILE_ID.DIZ
|
this.config.descWidth = this.config.descWidth || 45; // ie FILE_ID.DIZ
|
||||||
this.config.progBarChar = (this.config.progBarChar || '▒').charAt(0);
|
this.config.progBarChar = (this.config.progBarChar || '▒').charAt(0);
|
||||||
|
this.config.compressThreshold = this.config.compressThreshold || (1440000); // >= 1.44M by default :)
|
||||||
}
|
}
|
||||||
|
|
||||||
mciReady(mciData, cb) {
|
mciReady(mciData, cb) {
|
||||||
|
@ -85,6 +87,13 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
(callback) => this.prepareList(callback),
|
(callback) => this.prepareList(callback),
|
||||||
],
|
],
|
||||||
err => {
|
err => {
|
||||||
|
if(err) {
|
||||||
|
if('NORESULTS' === err.reasonCode) {
|
||||||
|
return this.gotoMenu(this.menuConfig.config.noResultsMenu || 'fileBaseExportListNoResults');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prevMenu();
|
||||||
|
}
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -157,7 +166,10 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
updateStatus('Gathering files for supplied criteria');
|
updateStatus('Gathering files for supplied criteria');
|
||||||
|
|
||||||
FileEntry.findFiles(filterCriteria, (err, fileIds) => {
|
FileEntry.findFiles(filterCriteria, (err, fileIds) => {
|
||||||
// :TODO: handle empty file IDs -- bail early.
|
if(0 === fileIds.length) {
|
||||||
|
return callback(Errors.General('No results for criteria', 'NORESULTS'));
|
||||||
|
}
|
||||||
|
|
||||||
return callback(err, headerTemplate, entryTemplate, descIndent, fileIds);
|
return callback(err, headerTemplate, entryTemplate, descIndent, fileIds);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -166,12 +178,15 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
totalFileCount : fileIds.length,
|
totalFileCount : fileIds.length,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileInfo = new FileEntry();
|
|
||||||
let current = 0;
|
let current = 0;
|
||||||
let listBody = '';
|
let listBody = '';
|
||||||
const totals = { fileCount : fileIds.length, bytes : 0 };
|
const totals = { fileCount : fileIds.length, bytes : 0 };
|
||||||
|
|
||||||
|
// this may take quite a while; temp disable of idle monitor
|
||||||
|
self.client.stopIdleMonitor();
|
||||||
|
|
||||||
async.eachSeries(fileIds, (fileId, nextFileId) => {
|
async.eachSeries(fileIds, (fileId, nextFileId) => {
|
||||||
|
const fileInfo = new FileEntry();
|
||||||
current += 1;
|
current += 1;
|
||||||
|
|
||||||
fileInfo.load(fileId, err => {
|
fileInfo.load(fileId, err => {
|
||||||
|
@ -237,6 +252,9 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, err => {
|
}, err => {
|
||||||
|
// re-enable idle monitor
|
||||||
|
self.client.startIdleMonitor();
|
||||||
|
|
||||||
return callback(err, listBody, headerTemplate, totals);
|
return callback(err, listBody, headerTemplate, totals);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -283,52 +301,56 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
|
|
||||||
const outputFileName = paths.join(
|
const outputFileName = paths.join(
|
||||||
sysTempDownloadDir,
|
sysTempDownloadDir,
|
||||||
`file_list_${uuidv4()}.txt`
|
`file_list_${uuidv4().substr(-8)}_${moment().format('YYYY-MM-DD')}.txt`
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFile(outputFileName, listBody, 'utf8', err => {
|
fs.writeFile(outputFileName, listBody, 'utf8', err => {
|
||||||
return callback(err, outputFileName, sysTempDownloadArea);
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.getSizeAndCompressIfMeetsSizeThreshold(outputFileName, (err, finalOutputFileName, fileSize) => {
|
||||||
|
return callback(err, finalOutputFileName, fileSize, sysTempDownloadArea);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function persistFileEntry(outputFileName, sysTempDownloadArea, callback) {
|
function persistFileEntry(outputFileName, fileSize, sysTempDownloadArea, callback) {
|
||||||
fse.stat(outputFileName, (err, stats) => {
|
const newEntry = new FileEntry({
|
||||||
const newEntry = new FileEntry({
|
areaTag : sysTempDownloadArea.areaTag,
|
||||||
areaTag : sysTempDownloadArea.areaTag,
|
fileName : paths.basename(outputFileName),
|
||||||
fileName : paths.basename(outputFileName),
|
storageTag : sysTempDownloadArea.storageTags[0],
|
||||||
storageTag : sysTempDownloadArea.storageTags[0],
|
meta : {
|
||||||
meta : {
|
upload_by_username : self.client.user.username,
|
||||||
upload_by_username : self.client.user.username,
|
upload_by_user_id : self.client.user.userId,
|
||||||
upload_by_user_id : self.client.user.userId,
|
byte_size : fileSize,
|
||||||
byte_size : stats.size,
|
session_temp_dl : 1, // download is valid until session is over
|
||||||
session_temp_dl : 1, // download is valid until session is over
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
newEntry.desc = 'File List Export';
|
newEntry.desc = 'File List Export';
|
||||||
|
|
||||||
newEntry.persist(err => {
|
newEntry.persist(err => {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
// queue it!
|
// queue it!
|
||||||
const dlQueue = new DownloadQueue(self.client);
|
const dlQueue = new DownloadQueue(self.client);
|
||||||
dlQueue.add(newEntry);
|
dlQueue.add(newEntry);
|
||||||
|
|
||||||
// clean up after ourselves when the session ends
|
// clean up after ourselves when the session ends
|
||||||
const thisClientId = self.client.session.id;
|
const thisClientId = self.client.session.id;
|
||||||
Events.once('codes.l33t.enigma.system.disconnected', evt => { // :TODO: Make a enum for system events/etc.
|
Events.once('codes.l33t.enigma.system.disconnected', evt => { // :TODO: Make a enum for system events/etc.
|
||||||
if(thisClientId === _.get(evt, 'client.session.id')) {
|
if(thisClientId === _.get(evt, 'client.session.id')) {
|
||||||
FileEntry.removeEntry(newEntry, { removePhysFile : true }, err => {
|
FileEntry.removeEntry(newEntry, { removePhysFile : true }, err => {
|
||||||
if(err) {
|
if(err) {
|
||||||
Log.warn( { fileId : newEntry.fileId, path : outputFileName }, 'Failed removing temporary session download' );
|
Log.warn( { fileId : newEntry.fileId, path : outputFileName }, 'Failed removing temporary session download' );
|
||||||
} else {
|
} else {
|
||||||
Log.debug( { fileId : newEntry.fileId, path : outputFileName }, 'Removed temporary session download item' );
|
Log.debug( { fileId : newEntry.fileId, path : outputFileName }, 'Removed temporary session download item' );
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return callback(err);
|
return callback(err);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function done(callback) {
|
function done(callback) {
|
||||||
|
@ -340,4 +362,39 @@ exports.getModule = class FileBaseListExport extends MenuModule {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSizeAndCompressIfMeetsSizeThreshold(filePath, cb) {
|
||||||
|
fse.stat(filePath, (err, stats) => {
|
||||||
|
if(err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stats.size < this.config.compressThreshold) {
|
||||||
|
// small enough, keep orig
|
||||||
|
return cb(null, filePath, stats.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const zipFilePath = `${filePath}.zip`;
|
||||||
|
|
||||||
|
const zipFile = new yazl.ZipFile();
|
||||||
|
zipFile.addFile(filePath, paths.basename(filePath));
|
||||||
|
zipFile.end( () => {
|
||||||
|
const outZipFile = fs.createWriteStream(zipFilePath);
|
||||||
|
zipFile.outputStream.pipe(outZipFile);
|
||||||
|
zipFile.outputStream.on('finish', () => {
|
||||||
|
// delete the original
|
||||||
|
fse.unlink(filePath, err => {
|
||||||
|
if(err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally stat the new output
|
||||||
|
fse.stat(zipFilePath, (err, stats) => {
|
||||||
|
return cb(err, zipFilePath, stats ? stats.size : 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
Loading…
Reference in New Issue