Initial support for non-blind aka non-batch uploads
This commit is contained in:
parent
f65ef7b79e
commit
8261881e3e
|
@ -379,7 +379,6 @@ function getDefaultConfig() {
|
||||||
],
|
],
|
||||||
// :TODO: can we not just use --escape ?
|
// :TODO: can we not just use --escape ?
|
||||||
escapeTelnet : true, // set to true to escape Telnet codes such as IAC
|
escapeTelnet : true, // set to true to escape Telnet codes such as IAC
|
||||||
supportsBatch : true,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -396,8 +395,10 @@ function getDefaultConfig() {
|
||||||
recvArgs : [
|
recvArgs : [
|
||||||
'-telnet', '-8', 'rz', '{uploadDir}'
|
'-telnet', '-8', 'rz', '{uploadDir}'
|
||||||
],
|
],
|
||||||
|
recvArgsNonBatch : [
|
||||||
|
'-telnet', '-8', 'rz', '{fileName}'
|
||||||
|
],
|
||||||
escapeTelnet : false, // -telnet option does this for us
|
escapeTelnet : false, // -telnet option does this for us
|
||||||
supportsBatch : true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,6 +479,7 @@ function getDefaultConfig() {
|
||||||
'\\b[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b',
|
'\\b[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})\\b',
|
||||||
'\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)?,?\\s((?:[0-9]{2})?[0-9]{2})\\b', // November 29th, 1997
|
'\\b(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)?,?\\s((?:[0-9]{2})?[0-9]{2})\\b', // November 29th, 1997
|
||||||
// :TODO: DD/MMM/YY, DD/MMMM/YY, DD/MMM/YYYY, etc.
|
// :TODO: DD/MMM/YY, DD/MMMM/YY, DD/MMM/YYYY, etc.
|
||||||
|
// :TODO: "Copyright YYYY someone"
|
||||||
],
|
],
|
||||||
|
|
||||||
web : {
|
web : {
|
||||||
|
|
|
@ -29,6 +29,7 @@ exports.Errors = {
|
||||||
Invalid : (reason, reasonCode) => new EnigError('Invalid', -32004, reason, reasonCode),
|
Invalid : (reason, reasonCode) => new EnigError('Invalid', -32004, reason, reasonCode),
|
||||||
ExternalProcess : (reason, reasonCode) => new EnigError('External process error', -32005, reason, reasonCode),
|
ExternalProcess : (reason, reasonCode) => new EnigError('External process error', -32005, reason, reasonCode),
|
||||||
MissingConfig : (reason, reasonCode) => new EnigError('Missing configuration', -32006, reason, reasonCode),
|
MissingConfig : (reason, reasonCode) => new EnigError('Missing configuration', -32006, reason, reasonCode),
|
||||||
|
UnexpectedState : (reason, reasonCode) => new EnigError('Unexpected state', -32007, reason, reasonCode),
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.ErrorReasons = {
|
exports.ErrorReasons = {
|
||||||
|
|
|
@ -61,7 +61,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(options.extraArgs.recvFileName) {
|
if(options.extraArgs.recvFileName) {
|
||||||
this.recvFileName = options.extraArgs.recvFiles;
|
this.recvFileName = options.extraArgs.recvFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(options.extraArgs.recvDirectory) {
|
if(options.extraArgs.recvDirectory) {
|
||||||
|
@ -117,6 +117,28 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendFiles(cb) {
|
||||||
|
// assume *sending* can always batch
|
||||||
|
// :TODO: Look into this further
|
||||||
|
const allFiles = this.sendQueue.map(f => f.path);
|
||||||
|
this.executeExternalProtocolHandlerForSend(allFiles, err => {
|
||||||
|
if(err) {
|
||||||
|
this.client.log.warn( { files : allFiles, error : err.message }, 'Error sending file(s)' );
|
||||||
|
} else {
|
||||||
|
const sentFiles = [];
|
||||||
|
this.sendQueue.forEach(f => {
|
||||||
|
f.sent = true;
|
||||||
|
sentFiles.push(f.path);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this.client.log.info( { sentFiles : sentFiles }, `Successfully sent ${sentFiles.length} file(s)` );
|
||||||
|
}
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
sendFiles(cb) {
|
sendFiles(cb) {
|
||||||
// :TODO: built in/native protocol support
|
// :TODO: built in/native protocol support
|
||||||
|
|
||||||
|
@ -155,6 +177,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
moveFileWithCollisionHandling(src, dst, cb) {
|
moveFileWithCollisionHandling(src, dst, cb) {
|
||||||
//
|
//
|
||||||
|
@ -208,11 +231,23 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
this.recvFilePaths = [];
|
this.recvFilePaths = [];
|
||||||
|
|
||||||
if(this.recvFileName) {
|
if(this.recvFileName) {
|
||||||
|
//
|
||||||
// file name specified - we expect a single file in |this.recvDirectory|
|
// file name specified - we expect a single file in |this.recvDirectory|
|
||||||
|
// by the name of |this.recvFileName|
|
||||||
// :TODO: support non-blind: Move file to dest path, add to recvFilePaths, etc.
|
//
|
||||||
|
const recvFullPath = paths.join(this.recvDirectory, this.recvFileName);
|
||||||
|
fs.stat(recvFullPath, (err, stats) => {
|
||||||
|
if(err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
return cb(null);
|
if(!stats.isFile()) {
|
||||||
|
return cb(Errors.Invalid('Expected file entry in recv directory'));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recvFilePaths.push(recvFullPath);
|
||||||
|
return cb(null);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Blind Upload (recv): files in |this.recvDirectory| should be named appropriately already
|
// Blind Upload (recv): files in |this.recvDirectory| should be named appropriately already
|
||||||
|
@ -254,8 +289,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepAndBuildSendArgs(filePaths, cb) {
|
prepAndBuildSendArgs(filePaths, cb) {
|
||||||
const external = this.protocolConfig.external;
|
const externalArgs = this.protocolConfig.external['sendArgs'];
|
||||||
const externalArgs = external[`${this.direction}Args`];
|
|
||||||
|
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
|
@ -300,7 +334,8 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepAndBuildRecvArgs(cb) {
|
prepAndBuildRecvArgs(cb) {
|
||||||
const externalArgs = this.protocolConfig.external[`${this.direction}Args`];
|
const argsKey = this.recvFileName ? 'recvArgsNonBatch' : 'recvArgs';
|
||||||
|
const externalArgs = this.protocolConfig.external[argsKey];
|
||||||
const args = externalArgs.map(arg => stringFormat(arg, {
|
const args = externalArgs.map(arg => stringFormat(arg, {
|
||||||
uploadDir : this.recvDirectory,
|
uploadDir : this.recvDirectory,
|
||||||
fileName : this.recvFileName || '',
|
fileName : this.recvFileName || '',
|
||||||
|
|
|
@ -36,8 +36,6 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule {
|
||||||
|
|
||||||
this.config.direction = this.config.direction || 'send';
|
this.config.direction = this.config.direction || 'send';
|
||||||
|
|
||||||
this.loadAvailProtocols();
|
|
||||||
|
|
||||||
this.extraArgs = options.extraArgs;
|
this.extraArgs = options.extraArgs;
|
||||||
|
|
||||||
if(_.has(options, 'lastMenuResult.sentFileIds')) {
|
if(_.has(options, 'lastMenuResult.sentFileIds')) {
|
||||||
|
@ -50,6 +48,8 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule {
|
||||||
|
|
||||||
this.fallbackOnly = options.lastMenuResult ? true : false;
|
this.fallbackOnly = options.lastMenuResult ? true : false;
|
||||||
|
|
||||||
|
this.loadAvailProtocols();
|
||||||
|
|
||||||
this.menuMethods = {
|
this.menuMethods = {
|
||||||
selectProtocol : (formData, extraArgs, cb) => {
|
selectProtocol : (formData, extraArgs, cb) => {
|
||||||
const protocol = this.protocols[formData.value.protocol];
|
const protocol = this.protocols[formData.value.protocol];
|
||||||
|
@ -130,12 +130,21 @@ exports.getModule = class FileTransferProtocolSelectModule extends MenuModule {
|
||||||
|
|
||||||
loadAvailProtocols() {
|
loadAvailProtocols() {
|
||||||
this.protocols = _.map(Config.fileTransferProtocols, (protInfo, protocol) => {
|
this.protocols = _.map(Config.fileTransferProtocols, (protInfo, protocol) => {
|
||||||
return {
|
return {
|
||||||
protocol : protocol,
|
protocol : protocol,
|
||||||
name : protInfo.name,
|
name : protInfo.name,
|
||||||
|
hasBatch : _.has(protInfo, 'external.recvArgs'),
|
||||||
|
hasNonBatch : _.has(protInfo, 'external.recvArgsNonBatch'),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Filter out batch vs non-batch only protocols
|
||||||
|
if(this.extraArgs.recvFileName) { // non-batch aka non-blind
|
||||||
|
this.protocols = this.protocols.filter( prot => prot.hasNonBatch );
|
||||||
|
} else {
|
||||||
|
this.protocols = this.protocols.filter( prot => prot.hasBatch );
|
||||||
|
}
|
||||||
|
|
||||||
this.protocols.sort( (a, b) => a.name.localeCompare(b.name) );
|
this.protocols.sort( (a, b) => a.name.localeCompare(b.name) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
112
mods/upload.js
112
mods/upload.js
|
@ -11,6 +11,7 @@ const ansiGoto = require('../core/ansi_term.js').goto;
|
||||||
const moveFileWithCollisionHandling = require('../core/file_util.js').moveFileWithCollisionHandling;
|
const moveFileWithCollisionHandling = require('../core/file_util.js').moveFileWithCollisionHandling;
|
||||||
const pathWithTerminatingSeparator = require('../core/file_util.js').pathWithTerminatingSeparator;
|
const pathWithTerminatingSeparator = require('../core/file_util.js').pathWithTerminatingSeparator;
|
||||||
const Log = require('../core/logger.js').log;
|
const Log = require('../core/logger.js').log;
|
||||||
|
const Errors = require('../core/enig_error.js').Errors;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -69,41 +70,28 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
|
|
||||||
this.menuMethods = {
|
this.menuMethods = {
|
||||||
optionsNavContinue : (formData, extraArgs, cb) => {
|
optionsNavContinue : (formData, extraArgs, cb) => {
|
||||||
if(this.isBlindUpload()) {
|
return this.performUpload(cb);
|
||||||
return this.performBlindUpload(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// non-blind
|
|
||||||
// jump to fileDetails form
|
|
||||||
// :TODO: support non-blind: collect info/filename -> upload -> complete
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fileDetailsContinue : (formData, extraArgs, cb) => {
|
fileDetailsContinue : (formData, extraArgs, cb) => {
|
||||||
|
// see displayFileDetailsPageForUploadEntry() for this hackery:
|
||||||
|
cb(null);
|
||||||
// see notes in displayFileDetailsPageForEntry() about this hackery:
|
|
||||||
cb(null);
|
|
||||||
return this.fileDetailsCurrentEntrySubmitCallback(null, formData.value); // move on to the next entry, if any
|
return this.fileDetailsCurrentEntrySubmitCallback(null, formData.value); // move on to the next entry, if any
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getSaveState() {
|
getSaveState() {
|
||||||
const saveState = {
|
return {
|
||||||
uploadType : this.uploadType,
|
uploadType : this.uploadType,
|
||||||
tempRecvDirectory : this.tempRecvDirectory
|
tempRecvDirectory : this.tempRecvDirectory,
|
||||||
|
areaInfo : this.availAreas[ this.viewControllers.options.getView(MciViewIds.options.area).getData() ],
|
||||||
};
|
};
|
||||||
|
|
||||||
if(this.isBlindUpload()) {
|
|
||||||
const areaSelectView = this.viewControllers.options.getView(MciViewIds.options.area);
|
|
||||||
saveState.areaInfo = this.availAreas[areaSelectView.getData()];
|
|
||||||
}
|
|
||||||
|
|
||||||
return saveState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreSavedState(savedState) {
|
restoreSavedState(savedState) {
|
||||||
if(savedState.areaInfo) {
|
if(savedState.areaInfo) {
|
||||||
|
this.uploadType = savedState.uploadType;
|
||||||
this.areaInfo = savedState.areaInfo;
|
this.areaInfo = savedState.areaInfo;
|
||||||
this.tempRecvDirectory = savedState.tempRecvDirectory;
|
this.tempRecvDirectory = savedState.tempRecvDirectory;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +139,7 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
super.leave();
|
super.leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
performBlindUpload(cb) {
|
performUpload(cb) {
|
||||||
temptmp.mkdir( { prefix : 'enigul-' }, (err, tempRecvDirectory) => {
|
temptmp.mkdir( { prefix : 'enigul-' }, (err, tempRecvDirectory) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
@ -167,6 +155,10 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(!this.isBlindUpload()) {
|
||||||
|
modOpts.extraArgs.recvFileName = this.viewControllers.options.getView(MciViewIds.options.fileName).getData();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Move along to protocol selection -> file transfer
|
// Move along to protocol selection -> file transfer
|
||||||
// Upon completion, we'll re-enter the module with some file paths handed to us
|
// Upon completion, we'll re-enter the module with some file paths handed to us
|
||||||
|
@ -176,7 +168,11 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
modOpts,
|
modOpts,
|
||||||
cb
|
cb
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
continueNonBlindUpload(cb) {
|
||||||
|
return cb(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScanStepInfoViews(stepInfo) {
|
updateScanStepInfoViews(stepInfo) {
|
||||||
|
@ -343,6 +339,34 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepDetailsForUpload(scanResults, cb) {
|
||||||
|
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
||||||
|
this.displayFileDetailsPageForUploadEntry(newEntry, (err, newValues) => {
|
||||||
|
if(err) {
|
||||||
|
return nextEntry(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the file entry did *not* have a desc, take the user desc
|
||||||
|
if(!this.fileEntryHasDetectedDesc(newEntry)) {
|
||||||
|
newEntry.desc = newValues.shortDesc.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newValues.estYear.length > 0) {
|
||||||
|
newEntry.meta.est_release_year = newValues.estYear;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newValues.tags.length > 0) {
|
||||||
|
newEntry.setHashTags(newValues.tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextEntry(err);
|
||||||
|
});
|
||||||
|
}, err => {
|
||||||
|
delete this.fileDetailsCurrentEntrySubmitCallback;
|
||||||
|
return cb(err, scanResults);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
processUploadedFiles() {
|
processUploadedFiles() {
|
||||||
//
|
//
|
||||||
// For each file uploaded, we need to process & gather information
|
// For each file uploaded, we need to process & gather information
|
||||||
|
@ -351,6 +375,22 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
|
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
|
function prepNonBlind(callback) {
|
||||||
|
if(self.isBlindUpload()) {
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// For non-blind uploads, batch is not supported, we expect a single file
|
||||||
|
// in |recvFilePaths|. If not, it's an error (we don't want to process the wrong thing)
|
||||||
|
//
|
||||||
|
if(self.recvFilePaths.length > 1) {
|
||||||
|
self.client.log.warn( { recvFilePaths : self.recvFilePaths }, 'Non-blind upload received 2:n files' );
|
||||||
|
return callback(Errors.UnexpectedState(`Non-blind upload expected single file but got received ${self.recvFilePaths.length}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(null);
|
||||||
|
},
|
||||||
function scan(callback) {
|
function scan(callback) {
|
||||||
return self.scanFiles(callback);
|
return self.scanFiles(callback);
|
||||||
},
|
},
|
||||||
|
@ -374,31 +414,7 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
return callback(null, scanResults);
|
return callback(null, scanResults);
|
||||||
},
|
},
|
||||||
function prepDetails(scanResults, callback) {
|
function prepDetails(scanResults, callback) {
|
||||||
async.eachSeries(scanResults.newEntries, (newEntry, nextEntry) => {
|
return self.prepDetailsForUpload(scanResults, callback);
|
||||||
self.displayFileDetailsPageForEntry(newEntry, (err, newValues) => {
|
|
||||||
if(err) {
|
|
||||||
return nextEntry(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the file entry did *not* have a desc, take the user desc
|
|
||||||
if(!self.fileEntryHasDetectedDesc(newEntry)) {
|
|
||||||
newEntry.desc = newValues.shortDesc.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(newValues.estYear.length > 0) {
|
|
||||||
newEntry.meta.est_release_year = newValues.estYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(newValues.tags.length > 0) {
|
|
||||||
newEntry.setHashTags(newValues.tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextEntry(err);
|
|
||||||
});
|
|
||||||
}, err => {
|
|
||||||
delete self.fileDetailsCurrentEntrySubmitCallback;
|
|
||||||
return callback(err, scanResults);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
function startMovingAndPersistingToDatabase(scanResults, callback) {
|
function startMovingAndPersistingToDatabase(scanResults, callback) {
|
||||||
//
|
//
|
||||||
|
@ -486,7 +502,7 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
return (fileEntry.desc && fileEntry.desc.length > 0);
|
return (fileEntry.desc && fileEntry.desc.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
displayFileDetailsPageForEntry(fileEntry, cb) {
|
displayFileDetailsPageForUploadEntry(fileEntry, cb) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
async.series(
|
async.series(
|
||||||
|
|
Loading…
Reference in New Issue