Initial sync up with master after Prettier
This commit is contained in:
@@ -2,30 +2,30 @@
|
||||
'use strict';
|
||||
|
||||
// enigma-bbs
|
||||
const MenuModule = require('./menu_module.js').MenuModule;
|
||||
const Config = require('./config.js').get;
|
||||
const stringFormat = require('./string_format.js');
|
||||
const Errors = require('./enig_error.js').Errors;
|
||||
const DownloadQueue = require('./download_queue.js');
|
||||
const StatLog = require('./stat_log.js');
|
||||
const FileEntry = require('./file_entry.js');
|
||||
const Log = require('./logger.js').log;
|
||||
const Events = require('./events.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const SysProps = require('./system_property.js');
|
||||
const MenuModule = require('./menu_module.js').MenuModule;
|
||||
const Config = require('./config.js').get;
|
||||
const stringFormat = require('./string_format.js');
|
||||
const Errors = require('./enig_error.js').Errors;
|
||||
const DownloadQueue = require('./download_queue.js');
|
||||
const StatLog = require('./stat_log.js');
|
||||
const FileEntry = require('./file_entry.js');
|
||||
const Log = require('./logger.js').log;
|
||||
const Events = require('./events.js');
|
||||
const UserProps = require('./user_property.js');
|
||||
const SysProps = require('./system_property.js');
|
||||
|
||||
// deps
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const pty = require('node-pty');
|
||||
const temptmp = require('temptmp').createTrackedSession('transfer_file');
|
||||
const paths = require('path');
|
||||
const fs = require('graceful-fs');
|
||||
const fse = require('fs-extra');
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
const pty = require('node-pty');
|
||||
const temptmp = require('temptmp').createTrackedSession('transfer_file');
|
||||
const paths = require('path');
|
||||
const fs = require('graceful-fs');
|
||||
const fse = require('fs-extra');
|
||||
|
||||
// some consts
|
||||
const SYSTEM_EOL = require('os').EOL;
|
||||
const TEMP_SUFFIX = 'enigtf-'; // temp CWD/etc.
|
||||
const SYSTEM_EOL = require('os').EOL;
|
||||
const TEMP_SUFFIX = 'enigtf-'; // temp CWD/etc.
|
||||
|
||||
/*
|
||||
Notes
|
||||
@@ -44,9 +44,9 @@ const TEMP_SUFFIX = 'enigtf-'; // temp CWD/etc.
|
||||
*/
|
||||
|
||||
exports.moduleInfo = {
|
||||
name : 'Transfer file',
|
||||
desc : 'Sends or receives a file(s)',
|
||||
author : 'NuSkooler',
|
||||
name: 'Transfer file',
|
||||
desc: 'Sends or receives a file(s)',
|
||||
author: 'NuSkooler',
|
||||
};
|
||||
|
||||
exports.getModule = class TransferFileModule extends MenuModule {
|
||||
@@ -59,56 +59,58 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
// Most options can be set via extraArgs or config block
|
||||
//
|
||||
const config = Config();
|
||||
if(options.extraArgs) {
|
||||
if(options.extraArgs.protocol) {
|
||||
this.protocolConfig = config.fileTransferProtocols[options.extraArgs.protocol];
|
||||
if (options.extraArgs) {
|
||||
if (options.extraArgs.protocol) {
|
||||
this.protocolConfig =
|
||||
config.fileTransferProtocols[options.extraArgs.protocol];
|
||||
}
|
||||
|
||||
if(options.extraArgs.direction) {
|
||||
if (options.extraArgs.direction) {
|
||||
this.direction = options.extraArgs.direction;
|
||||
}
|
||||
|
||||
if(options.extraArgs.sendQueue) {
|
||||
if (options.extraArgs.sendQueue) {
|
||||
this.sendQueue = options.extraArgs.sendQueue;
|
||||
}
|
||||
|
||||
if(options.extraArgs.recvFileName) {
|
||||
if (options.extraArgs.recvFileName) {
|
||||
this.recvFileName = options.extraArgs.recvFileName;
|
||||
}
|
||||
|
||||
if(options.extraArgs.recvDirectory) {
|
||||
if (options.extraArgs.recvDirectory) {
|
||||
this.recvDirectory = options.extraArgs.recvDirectory;
|
||||
}
|
||||
} else {
|
||||
if(this.config.protocol) {
|
||||
if (this.config.protocol) {
|
||||
this.protocolConfig = config.fileTransferProtocols[this.config.protocol];
|
||||
}
|
||||
|
||||
if(this.config.direction) {
|
||||
if (this.config.direction) {
|
||||
this.direction = this.config.direction;
|
||||
}
|
||||
|
||||
if(this.config.sendQueue) {
|
||||
if (this.config.sendQueue) {
|
||||
this.sendQueue = this.config.sendQueue;
|
||||
}
|
||||
|
||||
if(this.config.recvFileName) {
|
||||
if (this.config.recvFileName) {
|
||||
this.recvFileName = this.config.recvFileName;
|
||||
}
|
||||
|
||||
if(this.config.recvDirectory) {
|
||||
if (this.config.recvDirectory) {
|
||||
this.recvDirectory = this.config.recvDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
this.protocolConfig = this.protocolConfig || config.fileTransferProtocols.zmodem8kSz; // try for *something*
|
||||
this.direction = this.direction || 'send';
|
||||
this.sendQueue = this.sendQueue || [];
|
||||
this.protocolConfig =
|
||||
this.protocolConfig || config.fileTransferProtocols.zmodem8kSz; // try for *something*
|
||||
this.direction = this.direction || 'send';
|
||||
this.sendQueue = this.sendQueue || [];
|
||||
|
||||
// Ensure sendQueue is an array of objects that contain at least a 'path' member
|
||||
this.sendQueue = this.sendQueue.map(item => {
|
||||
if(_.isString(item)) {
|
||||
return { path : item };
|
||||
if (_.isString(item)) {
|
||||
return { path: item };
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
@@ -118,11 +120,11 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
}
|
||||
|
||||
isSending() {
|
||||
return ('send' === this.direction);
|
||||
return 'send' === this.direction;
|
||||
}
|
||||
|
||||
restorePipeAfterExternalProc() {
|
||||
if(!this.pipeRestored) {
|
||||
if (!this.pipeRestored) {
|
||||
this.pipeRestored = true;
|
||||
|
||||
this.client.restoreDataHandler();
|
||||
@@ -134,14 +136,16 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
// :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)' );
|
||||
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 }, `User "${self.client.user.username}" uploaded ${sentFiles.length} file(s)` );
|
||||
@@ -196,29 +200,32 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
// Move |src| -> |dst| renaming to file(1).ext, file(2).ext, etc.
|
||||
// in the case of collisions.
|
||||
//
|
||||
const dstPath = paths.dirname(dst);
|
||||
const dstFileExt = paths.extname(dst);
|
||||
const dstPath = paths.dirname(dst);
|
||||
const dstFileExt = paths.extname(dst);
|
||||
const dstFileSuffix = paths.basename(dst, dstFileExt);
|
||||
|
||||
let renameIndex = 0;
|
||||
let movedOk = false;
|
||||
let renameIndex = 0;
|
||||
let movedOk = false;
|
||||
let tryDstPath;
|
||||
|
||||
async.until(
|
||||
(callback) => callback(null, movedOk), // until moved OK
|
||||
(cb) => {
|
||||
if(0 === renameIndex) {
|
||||
callback => callback(null, movedOk), // until moved OK
|
||||
cb => {
|
||||
if (0 === renameIndex) {
|
||||
// try originally supplied path first
|
||||
tryDstPath = dst;
|
||||
} else {
|
||||
tryDstPath = paths.join(dstPath, `${dstFileSuffix}(${renameIndex})${dstFileExt}`);
|
||||
tryDstPath = paths.join(
|
||||
dstPath,
|
||||
`${dstFileSuffix}(${renameIndex})${dstFileExt}`
|
||||
);
|
||||
}
|
||||
|
||||
fse.move(src, tryDstPath, err => {
|
||||
if(err) {
|
||||
if('EEXIST' === err.code) {
|
||||
if (err) {
|
||||
if ('EEXIST' === err.code) {
|
||||
renameIndex += 1;
|
||||
return cb(null); // keep trying
|
||||
return cb(null); // keep trying
|
||||
}
|
||||
|
||||
return cb(err);
|
||||
@@ -236,25 +243,27 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
|
||||
recvFiles(cb) {
|
||||
this.executeExternalProtocolHandlerForRecv(err => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
this.recvFilePaths = [];
|
||||
|
||||
if(this.recvFileName) {
|
||||
if (this.recvFileName) {
|
||||
//
|
||||
// file name specified - we expect a single file in |this.recvDirectory|
|
||||
// by the name of |this.recvFileName|
|
||||
//
|
||||
const recvFullPath = paths.join(this.recvDirectory, this.recvFileName);
|
||||
fs.stat(recvFullPath, (err, stats) => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if(!stats.isFile()) {
|
||||
return cb(Errors.Invalid('Expected file entry in recv directory'));
|
||||
if (!stats.isFile()) {
|
||||
return cb(
|
||||
Errors.Invalid('Expected file entry in recv directory')
|
||||
);
|
||||
}
|
||||
|
||||
this.recvFilePaths.push(recvFullPath);
|
||||
@@ -265,83 +274,96 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
// Blind Upload (recv): files in |this.recvDirectory| should be named appropriately already
|
||||
//
|
||||
fs.readdir(this.recvDirectory, (err, files) => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
// stat each to grab files only
|
||||
async.each(files, (fileName, nextFile) => {
|
||||
const recvFullPath = paths.join(this.recvDirectory, fileName);
|
||||
async.each(
|
||||
files,
|
||||
(fileName, nextFile) => {
|
||||
const recvFullPath = paths.join(this.recvDirectory, fileName);
|
||||
|
||||
fs.stat(recvFullPath, (err, stats) => {
|
||||
if(err) {
|
||||
this.client.log.warn('Failed to stat file', { path : recvFullPath } );
|
||||
return nextFile(null); // just try the next one
|
||||
}
|
||||
fs.stat(recvFullPath, (err, stats) => {
|
||||
if (err) {
|
||||
this.client.log.warn('Failed to stat file', {
|
||||
path: recvFullPath,
|
||||
});
|
||||
return nextFile(null); // just try the next one
|
||||
}
|
||||
|
||||
if(stats.isFile()) {
|
||||
this.recvFilePaths.push(recvFullPath);
|
||||
}
|
||||
if (stats.isFile()) {
|
||||
this.recvFilePaths.push(recvFullPath);
|
||||
}
|
||||
|
||||
return nextFile(null);
|
||||
});
|
||||
}, () => {
|
||||
return cb(null);
|
||||
});
|
||||
return nextFile(null);
|
||||
});
|
||||
},
|
||||
() => {
|
||||
return cb(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pathWithTerminatingSeparator(path) {
|
||||
if(path && paths.sep !== path.charAt(path.length - 1)) {
|
||||
if (path && paths.sep !== path.charAt(path.length - 1)) {
|
||||
path = path + paths.sep;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
prepAndBuildSendArgs(filePaths, cb) {
|
||||
const externalArgs = this.protocolConfig.external['sendArgs'];
|
||||
const externalArgs = this.protocolConfig.external['sendArgs'];
|
||||
|
||||
async.waterfall(
|
||||
[
|
||||
function getTempFileListPath(callback) {
|
||||
const hasFileList = externalArgs.find(ea => (ea.indexOf('{fileListPath}') > -1) );
|
||||
if(!hasFileList) {
|
||||
const hasFileList = externalArgs.find(
|
||||
ea => ea.indexOf('{fileListPath}') > -1
|
||||
);
|
||||
if (!hasFileList) {
|
||||
return callback(null, null);
|
||||
}
|
||||
|
||||
temptmp.open( { prefix : TEMP_SUFFIX, suffix : '.txt' }, (err, tempFileInfo) => {
|
||||
if(err) {
|
||||
return callback(err); // failed to create it
|
||||
}
|
||||
|
||||
fs.write(tempFileInfo.fd, filePaths.join(SYSTEM_EOL), err => {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
temptmp.open(
|
||||
{ prefix: TEMP_SUFFIX, suffix: '.txt' },
|
||||
(err, tempFileInfo) => {
|
||||
if (err) {
|
||||
return callback(err); // failed to create it
|
||||
}
|
||||
fs.close(tempFileInfo.fd, err => {
|
||||
return callback(err, tempFileInfo.path);
|
||||
|
||||
fs.write(tempFileInfo.fd, filePaths.join(SYSTEM_EOL), err => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
fs.close(tempFileInfo.fd, err => {
|
||||
return callback(err, tempFileInfo.path);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
function createArgs(tempFileListPath, callback) {
|
||||
// initial args: ignore {filePaths} as we must break that into it's own sep array items
|
||||
const args = externalArgs.map(arg => {
|
||||
return '{filePaths}' === arg ? arg : stringFormat(arg, {
|
||||
fileListPath : tempFileListPath || '',
|
||||
});
|
||||
return '{filePaths}' === arg
|
||||
? arg
|
||||
: stringFormat(arg, {
|
||||
fileListPath: tempFileListPath || '',
|
||||
});
|
||||
});
|
||||
|
||||
const filePathsPos = args.indexOf('{filePaths}');
|
||||
if(filePathsPos > -1) {
|
||||
if (filePathsPos > -1) {
|
||||
// replace {filePaths} with 0:n individual entries in |args|
|
||||
args.splice.apply( args, [ filePathsPos, 1 ].concat(filePaths) );
|
||||
args.splice.apply(args, [filePathsPos, 1].concat(filePaths));
|
||||
}
|
||||
|
||||
return callback(null, args);
|
||||
}
|
||||
},
|
||||
],
|
||||
(err, args) => {
|
||||
return cb(err, args);
|
||||
@@ -350,47 +372,52 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
}
|
||||
|
||||
prepAndBuildRecvArgs(cb) {
|
||||
const argsKey = this.recvFileName ? 'recvArgsNonBatch' : 'recvArgs';
|
||||
const externalArgs = this.protocolConfig.external[argsKey];
|
||||
const args = externalArgs.map(arg => stringFormat(arg, {
|
||||
uploadDir : this.recvDirectory,
|
||||
fileName : this.recvFileName || '',
|
||||
}));
|
||||
const argsKey = this.recvFileName ? 'recvArgsNonBatch' : 'recvArgs';
|
||||
const externalArgs = this.protocolConfig.external[argsKey];
|
||||
const args = externalArgs.map(arg =>
|
||||
stringFormat(arg, {
|
||||
uploadDir: this.recvDirectory,
|
||||
fileName: this.recvFileName || '',
|
||||
})
|
||||
);
|
||||
|
||||
return cb(null, args);
|
||||
}
|
||||
|
||||
executeExternalProtocolHandler(args, cb) {
|
||||
const external = this.protocolConfig.external;
|
||||
const cmd = external[`${this.direction}Cmd`];
|
||||
const external = this.protocolConfig.external;
|
||||
const cmd = external[`${this.direction}Cmd`];
|
||||
|
||||
// support for handlers that need IACs taken care of over Telnet/etc.
|
||||
const processIACs =
|
||||
external.processIACs ||
|
||||
external.escapeTelnet; // deprecated name
|
||||
const processIACs = external.processIACs || external.escapeTelnet; // deprecated name
|
||||
|
||||
// :TODO: we should only do this when over Telnet (or derived, such as WebSockets)?
|
||||
|
||||
const IAC = Buffer.from([255]);
|
||||
const EscapedIAC = Buffer.from([255, 255]);
|
||||
const IAC = Buffer.from([255]);
|
||||
const EscapedIAC = Buffer.from([255, 255]);
|
||||
|
||||
this.client.log.debug(
|
||||
{ cmd : cmd, args : args, tempDir : this.recvDirectory, direction : this.direction },
|
||||
{
|
||||
cmd: cmd,
|
||||
args: args,
|
||||
tempDir: this.recvDirectory,
|
||||
direction: this.direction,
|
||||
},
|
||||
'Executing external protocol'
|
||||
);
|
||||
|
||||
const spawnOpts = {
|
||||
cols : this.client.term.termWidth,
|
||||
rows : this.client.term.termHeight,
|
||||
cwd : this.recvDirectory,
|
||||
encoding : null, // don't bork our data!
|
||||
cols: this.client.term.termWidth,
|
||||
rows: this.client.term.termHeight,
|
||||
cwd: this.recvDirectory,
|
||||
encoding: null, // don't bork our data!
|
||||
};
|
||||
|
||||
const externalProc = pty.spawn(cmd, args, spawnOpts);
|
||||
|
||||
let dataHits = 0;
|
||||
const updateActivity = () => {
|
||||
if (0 === (dataHits++ % 4)) {
|
||||
if (0 === dataHits++ % 4) {
|
||||
this.client.explicitActivityTimeUpdate();
|
||||
}
|
||||
};
|
||||
@@ -399,7 +426,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
updateActivity();
|
||||
|
||||
// needed for things like sz/rz
|
||||
if(processIACs) {
|
||||
if (processIACs) {
|
||||
let iacPos = data.indexOf(EscapedIAC);
|
||||
if (-1 === iacPos) {
|
||||
return externalProc.write(data);
|
||||
@@ -430,7 +457,7 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
updateActivity();
|
||||
|
||||
// needed for things like sz/rz
|
||||
if(processIACs) {
|
||||
if (processIACs) {
|
||||
let iacPos = data.indexOf(IAC);
|
||||
if (-1 === iacPos) {
|
||||
return this.client.term.rawWrite(data);
|
||||
@@ -459,23 +486,33 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
return this.restorePipeAfterExternalProc();
|
||||
});
|
||||
|
||||
externalProc.once('exit', (exitCode) => {
|
||||
this.client.log.debug( { cmd : cmd, args : args, exitCode : exitCode }, 'Process exited' );
|
||||
externalProc.once('exit', exitCode => {
|
||||
this.client.log.debug(
|
||||
{ cmd: cmd, args: args, exitCode: exitCode },
|
||||
'Process exited'
|
||||
);
|
||||
|
||||
this.restorePipeAfterExternalProc();
|
||||
externalProc.removeAllListeners();
|
||||
|
||||
return cb(exitCode ? Errors.ExternalProcess(`Process exited with exit code ${exitCode}`, 'EBADEXIT') : null);
|
||||
return cb(
|
||||
exitCode
|
||||
? Errors.ExternalProcess(
|
||||
`Process exited with exit code ${exitCode}`,
|
||||
'EBADEXIT'
|
||||
)
|
||||
: null
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
executeExternalProtocolHandlerForSend(filePaths, cb) {
|
||||
if(!Array.isArray(filePaths)) {
|
||||
filePaths = [ filePaths ];
|
||||
if (!Array.isArray(filePaths)) {
|
||||
filePaths = [filePaths];
|
||||
}
|
||||
|
||||
this.prepAndBuildSendArgs(filePaths, (err, args) => {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
@@ -486,8 +523,8 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
}
|
||||
|
||||
executeExternalProtocolHandlerForRecv(cb) {
|
||||
this.prepAndBuildRecvArgs( (err, args) => {
|
||||
if(err) {
|
||||
this.prepAndBuildRecvArgs((err, args) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
@@ -498,91 +535,115 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
}
|
||||
|
||||
getMenuResult() {
|
||||
if(this.isSending()) {
|
||||
return { sentFileIds : this.sentFileIds };
|
||||
if (this.isSending()) {
|
||||
return { sentFileIds: this.sentFileIds };
|
||||
} else {
|
||||
return { recvFilePaths : this.recvFilePaths };
|
||||
return { recvFilePaths: this.recvFilePaths };
|
||||
}
|
||||
}
|
||||
|
||||
updateSendStats(cb) {
|
||||
let downloadBytes = 0;
|
||||
let downloadCount = 0;
|
||||
let fileIds = [];
|
||||
let downloadBytes = 0;
|
||||
let downloadCount = 0;
|
||||
let fileIds = [];
|
||||
|
||||
async.each(this.sendQueue, (queueItem, next) => {
|
||||
if(!queueItem.sent) {
|
||||
return next(null);
|
||||
}
|
||||
|
||||
if(queueItem.fileId) {
|
||||
fileIds.push(queueItem.fileId);
|
||||
}
|
||||
|
||||
if(_.isNumber(queueItem.byteSize)) {
|
||||
downloadCount += 1;
|
||||
downloadBytes += queueItem.byteSize;
|
||||
return next(null);
|
||||
}
|
||||
|
||||
// we just have a path - figure it out
|
||||
fs.stat(queueItem.path, (err, stats) => {
|
||||
if(err) {
|
||||
this.client.log.warn( { error : err.message, path : queueItem.path }, 'File stat failed' );
|
||||
} else {
|
||||
downloadCount += 1;
|
||||
downloadBytes += stats.size;
|
||||
async.each(
|
||||
this.sendQueue,
|
||||
(queueItem, next) => {
|
||||
if (!queueItem.sent) {
|
||||
return next(null);
|
||||
}
|
||||
|
||||
return next(null);
|
||||
});
|
||||
}, () => {
|
||||
// All stats/meta currently updated via fire & forget - if this is ever a issue, we can wait for callbacks
|
||||
StatLog.incrementUserStat(this.client.user, UserProps.FileDlTotalCount, downloadCount);
|
||||
StatLog.incrementUserStat(this.client.user, UserProps.FileDlTotalBytes, downloadBytes);
|
||||
if (queueItem.fileId) {
|
||||
fileIds.push(queueItem.fileId);
|
||||
}
|
||||
|
||||
StatLog.incrementSystemStat(SysProps.FileDlTotalCount, downloadCount);
|
||||
StatLog.incrementSystemStat(SysProps.FileDlTotalBytes, downloadBytes);
|
||||
if (_.isNumber(queueItem.byteSize)) {
|
||||
downloadCount += 1;
|
||||
downloadBytes += queueItem.byteSize;
|
||||
return next(null);
|
||||
}
|
||||
|
||||
StatLog.incrementNonPersistentSystemStat(SysProps.FileDlTodayCount, downloadCount);
|
||||
StatLog.incrementNonPersistentSystemStat(SysProps.FileDlTodayBytes, downloadBytes);
|
||||
// we just have a path - figure it out
|
||||
fs.stat(queueItem.path, (err, stats) => {
|
||||
if (err) {
|
||||
this.client.log.warn(
|
||||
{ error: err.message, path: queueItem.path },
|
||||
'File stat failed'
|
||||
);
|
||||
} else {
|
||||
downloadCount += 1;
|
||||
downloadBytes += stats.size;
|
||||
}
|
||||
|
||||
fileIds.forEach(fileId => {
|
||||
FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1);
|
||||
});
|
||||
return next(null);
|
||||
});
|
||||
},
|
||||
() => {
|
||||
// All stats/meta currently updated via fire & forget - if this is ever a issue, we can wait for callbacks
|
||||
StatLog.incrementUserStat(
|
||||
this.client.user,
|
||||
UserProps.FileDlTotalCount,
|
||||
downloadCount
|
||||
);
|
||||
StatLog.incrementUserStat(
|
||||
this.client.user,
|
||||
UserProps.FileDlTotalBytes,
|
||||
downloadBytes
|
||||
);
|
||||
|
||||
return cb(null);
|
||||
});
|
||||
StatLog.incrementSystemStat(SysProps.FileDlTotalCount, downloadCount);
|
||||
StatLog.incrementSystemStat(SysProps.FileDlTotalBytes, downloadBytes);
|
||||
|
||||
fileIds.forEach(fileId => {
|
||||
FileEntry.incrementAndPersistMetaValue(fileId, 'dl_count', 1);
|
||||
});
|
||||
|
||||
return cb(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
updateRecvStats(cb) {
|
||||
let uploadBytes = 0;
|
||||
let uploadCount = 0;
|
||||
|
||||
async.each(this.recvFilePaths, (filePath, next) => {
|
||||
// we just have a path - figure it out
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if(err) {
|
||||
this.client.log.warn( { error : err.message, path : filePath }, 'File stat failed' );
|
||||
} else {
|
||||
uploadCount += 1;
|
||||
uploadBytes += stats.size;
|
||||
}
|
||||
async.each(
|
||||
this.recvFilePaths,
|
||||
(filePath, next) => {
|
||||
// we just have a path - figure it out
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if (err) {
|
||||
this.client.log.warn(
|
||||
{ error: err.message, path: filePath },
|
||||
'File stat failed'
|
||||
);
|
||||
} else {
|
||||
uploadCount += 1;
|
||||
uploadBytes += stats.size;
|
||||
}
|
||||
|
||||
return next(null);
|
||||
});
|
||||
}, () => {
|
||||
StatLog.incrementUserStat(this.client.user, UserProps.FileUlTotalCount, uploadCount);
|
||||
StatLog.incrementUserStat(this.client.user, UserProps.FileUlTotalBytes, uploadBytes);
|
||||
return next(null);
|
||||
});
|
||||
},
|
||||
() => {
|
||||
StatLog.incrementUserStat(
|
||||
this.client.user,
|
||||
UserProps.FileUlTotalCount,
|
||||
uploadCount
|
||||
);
|
||||
StatLog.incrementUserStat(
|
||||
this.client.user,
|
||||
UserProps.FileUlTotalBytes,
|
||||
uploadBytes
|
||||
);
|
||||
|
||||
StatLog.incrementSystemStat(SysProps.FileUlTotalCount, uploadCount);
|
||||
StatLog.incrementSystemStat(SysProps.FileUlTotalBytes, uploadBytes);
|
||||
StatLog.incrementSystemStat(SysProps.FileUlTotalCount, uploadCount);
|
||||
StatLog.incrementSystemStat(SysProps.FileUlTotalBytes, uploadBytes);
|
||||
|
||||
StatLog.incrementNonPersistentSystemStat(SysProps.FileUlTodayCount, uploadCount);
|
||||
StatLog.incrementNonPersistentSystemStat(SysProps.FileUlTodayBytes, uploadBytes);
|
||||
|
||||
return cb(null);
|
||||
});
|
||||
return cb(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
initSequence() {
|
||||
@@ -593,41 +654,38 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
async.series(
|
||||
[
|
||||
function validateConfig(callback) {
|
||||
if(self.isSending()) {
|
||||
if(!Array.isArray(self.sendQueue)) {
|
||||
self.sendQueue = [ self.sendQueue ];
|
||||
if (self.isSending()) {
|
||||
if (!Array.isArray(self.sendQueue)) {
|
||||
self.sendQueue = [self.sendQueue];
|
||||
}
|
||||
}
|
||||
|
||||
return callback(null);
|
||||
},
|
||||
function transferFiles(callback) {
|
||||
if(self.isSending()) {
|
||||
self.sendFiles( err => {
|
||||
if(err) {
|
||||
if (self.isSending()) {
|
||||
self.sendFiles(err => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
const sentFileIds = [];
|
||||
self.sendQueue.forEach(queueItem => {
|
||||
if(queueItem.sent && queueItem.fileId) {
|
||||
if (queueItem.sent && queueItem.fileId) {
|
||||
sentFileIds.push(queueItem.fileId);
|
||||
}
|
||||
});
|
||||
|
||||
if(sentFileIds.length > 0) {
|
||||
if (sentFileIds.length > 0) {
|
||||
// remove items we sent from the D/L queue
|
||||
const dlQueue = new DownloadQueue(self.client);
|
||||
const dlFileEntries = dlQueue.removeItems(sentFileIds);
|
||||
|
||||
// fire event for downloaded entries
|
||||
Events.emit(
|
||||
Events.getSystemEvents().UserDownload,
|
||||
{
|
||||
user : self.client.user,
|
||||
files : dlFileEntries
|
||||
}
|
||||
);
|
||||
Events.emit(Events.getSystemEvents().UserDownload, {
|
||||
user: self.client.user,
|
||||
files: dlFileEntries,
|
||||
});
|
||||
|
||||
self.sentFileIds = sentFileIds;
|
||||
}
|
||||
@@ -635,29 +693,32 @@ exports.getModule = class TransferFileModule extends MenuModule {
|
||||
return callback(null);
|
||||
});
|
||||
} else {
|
||||
self.recvFiles( err => {
|
||||
self.recvFiles(err => {
|
||||
return callback(err);
|
||||
});
|
||||
}
|
||||
},
|
||||
function cleanupTempFiles(callback) {
|
||||
temptmp.cleanup( paths => {
|
||||
Log.debug( { paths : paths, sessionId : temptmp.sessionId }, 'Temporary files cleaned up' );
|
||||
temptmp.cleanup(paths => {
|
||||
Log.debug(
|
||||
{ paths: paths, sessionId: temptmp.sessionId },
|
||||
'Temporary files cleaned up'
|
||||
);
|
||||
});
|
||||
|
||||
return callback(null);
|
||||
},
|
||||
function updateUserAndSystemStats(callback) {
|
||||
if(self.isSending()) {
|
||||
if (self.isSending()) {
|
||||
return self.updateSendStats(callback);
|
||||
} else {
|
||||
return self.updateRecvStats(callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
err => {
|
||||
if(err) {
|
||||
self.client.log.warn( { error : err.message }, 'File transfer error');
|
||||
if (err) {
|
||||
self.client.log.warn({ error: err.message }, 'File transfer error');
|
||||
}
|
||||
|
||||
return self.prevMenu();
|
||||
|
||||
Reference in New Issue
Block a user