* More file area utility methods/etc.
* Start adding oputil file-area --scan <areaTag> stuff * New new ArchiveUtil.getInstance()
This commit is contained in:
parent
35e7610670
commit
ec716fdf2c
|
@ -215,10 +215,24 @@ function getDefaultConfig() {
|
||||||
zip : {
|
zip : {
|
||||||
sig : '504b0304',
|
sig : '504b0304',
|
||||||
offset : 0,
|
offset : 0,
|
||||||
compressCmd : '7z',
|
compress : {
|
||||||
compressArgs : [ 'a', '-tzip', '{archivePath}', '{fileList}' ],
|
cmd : '7z',
|
||||||
decompressCmd : '7z',
|
args : [ 'a', '-tzip', '{archivePath}', '{fileList}' ],
|
||||||
decompressArgs : [ 'e', '-o{extractPath}', '{archivePath}' ]
|
},
|
||||||
|
decompress : {
|
||||||
|
cmd : '7z',
|
||||||
|
args : [ 'e', '-o{extractPath}', '{archivePath}' ]
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
list : {
|
||||||
|
cmd : '7z',
|
||||||
|
args : [ 'l', '{archivePath}' ],
|
||||||
|
match : '...someregex...'
|
||||||
|
},*/
|
||||||
|
extract : {
|
||||||
|
cmd : '7z',
|
||||||
|
args : [ 'x', '-o{extractPath}', '{archivePath}', '{fileList}' ],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,24 @@
|
||||||
const Config = require('./config.js').config;
|
const Config = require('./config.js').config;
|
||||||
const Errors = require('./enig_error.js').Errors;
|
const Errors = require('./enig_error.js').Errors;
|
||||||
const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs;
|
const sortAreasOrConfs = require('./conf_area_util.js').sortAreasOrConfs;
|
||||||
|
const FileEntry = require('./file_entry.js');
|
||||||
|
const FileDb = require('./database.js').dbs.file;
|
||||||
|
const ArchiveUtil = require('./archive_util.js');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
const fs = require('fs');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const paths = require('path');
|
||||||
|
|
||||||
exports.getAvailableFileAreas = getAvailableFileAreas;
|
exports.getAvailableFileAreas = getAvailableFileAreas;
|
||||||
exports.getSortedAvailableFileAreas = getSortedAvailableFileAreas;
|
exports.getSortedAvailableFileAreas = getSortedAvailableFileAreas;
|
||||||
exports.getDefaultFileArea = getDefaultFileArea;
|
exports.getDefaultFileArea = getDefaultFileArea;
|
||||||
exports.getFileAreaByTag = getFileAreaByTag;
|
exports.getFileAreaByTag = getFileAreaByTag;
|
||||||
exports.changeFileAreaWithOptions = changeFileAreaWithOptions;
|
exports.changeFileAreaWithOptions = changeFileAreaWithOptions;
|
||||||
|
//exports.addOrUpdateFileEntry = addOrUpdateFileEntry;
|
||||||
|
exports.scanFileAreaForChanges = scanFileAreaForChanges;
|
||||||
|
|
||||||
const WellKnownAreaTags = exports.WellKnownAreaTags = {
|
const WellKnownAreaTags = exports.WellKnownAreaTags = {
|
||||||
Invalid : '',
|
Invalid : '',
|
||||||
|
@ -64,7 +72,11 @@ function getDefaultFileArea(client, disableAcsCheck) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileAreaByTag(areaTag) {
|
function getFileAreaByTag(areaTag) {
|
||||||
return Config.fileAreas.areas[areaTag];
|
const areaInfo = Config.fileAreas.areas[areaTag];
|
||||||
|
if(areaInfo) {
|
||||||
|
areaInfo.areaTag = areaTag; // convienence!
|
||||||
|
return areaInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeFileAreaWithOptions(client, areaTag, options, cb) {
|
function changeFileAreaWithOptions(client, areaTag, options, cb) {
|
||||||
|
@ -101,3 +113,167 @@ function changeFileAreaWithOptions(client, areaTag, options, cb) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAreaStorageDirectory(areaInfo) {
|
||||||
|
return paths.join(Config.fileBase.areaStoragePrefix, areaInfo.storageDir || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExistingFileEntriesBySha1(sha1, cb) {
|
||||||
|
const entries = [];
|
||||||
|
|
||||||
|
FileDb.each(
|
||||||
|
`SELECT file_id, area_tag
|
||||||
|
FROM file
|
||||||
|
WHERE file_sha1=?;`,
|
||||||
|
[ sha1 ],
|
||||||
|
(err, fileRow) => {
|
||||||
|
if(fileRow) {
|
||||||
|
entries.push({
|
||||||
|
fileId : fileRow.file_id,
|
||||||
|
areaTag : fileRow.area_tag,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
return cb(err, entries);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNewArchiveFileEnty(fileEntry, filePath, archiveType, cb) {
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
function getArchiveFileList(callback) {
|
||||||
|
// :TODO: get list of files in archive
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNewFileEntry(fileEntry, filePath, cb) {
|
||||||
|
const archiveUtil = ArchiveUtil.getInstance();
|
||||||
|
|
||||||
|
// :TODO: Use detectTypeWithBuf() once avail - we *just* read some file data
|
||||||
|
archiveUtil.detectType(filePath, (err, archiveType) => {
|
||||||
|
if(archiveType) {
|
||||||
|
return addNewArchiveFileEnty(fileEntry, filePath, archiveType, cb);
|
||||||
|
} else {
|
||||||
|
// :TODO:addNewNonArchiveFileEntry
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addOrUpdateFileEntry(areaInfo, fileName, options, cb) {
|
||||||
|
|
||||||
|
const fileEntry = new FileEntry({
|
||||||
|
areaTag : areaInfo.areaTag,
|
||||||
|
meta : options.meta,
|
||||||
|
hashTags : options.hashTags, // Set() or Array
|
||||||
|
});
|
||||||
|
|
||||||
|
const filePath = paths.join(getAreaStorageDirectory(areaInfo), fileName);
|
||||||
|
|
||||||
|
async.waterfall(
|
||||||
|
[
|
||||||
|
function processPhysicalFile(callback) {
|
||||||
|
const stream = fs.createReadStream(filePath);
|
||||||
|
|
||||||
|
let byteSize = 0;
|
||||||
|
const sha1 = crypto.createHash('sha1');
|
||||||
|
const sha256 = crypto.createHash('sha256');
|
||||||
|
const md5 = crypto.createHash('md5');
|
||||||
|
|
||||||
|
|
||||||
|
// :TODO: crc32
|
||||||
|
|
||||||
|
stream.on('data', data => {
|
||||||
|
byteSize += data.length;
|
||||||
|
|
||||||
|
sha1.update(data);
|
||||||
|
sha256.update(data);
|
||||||
|
md5.update(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', () => {
|
||||||
|
fileEntry.meta.byte_size = byteSize;
|
||||||
|
|
||||||
|
// sha-1 is in basic file entry
|
||||||
|
fileEntry.fileSha1 = sha1.digest('hex');
|
||||||
|
|
||||||
|
// others are meta
|
||||||
|
fileEntry.meta.file_sha256 = sha256.digest('hex');
|
||||||
|
fileEntry.meta.file_md5 = md5.digest('hex');
|
||||||
|
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('error', err => {
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function fetchExistingEntry(callback) {
|
||||||
|
getExistingFileEntriesBySha1(fileEntry.fileSha1, (err, existingEntries) => {
|
||||||
|
return callback(err, existingEntries);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function addOrUpdate(callback, existingEntries) {
|
||||||
|
if(existingEntries.length > 0) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return addNewFileEntry(fileEntry, filePath, callback);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scanFileAreaForChanges(areaInfo, cb) {
|
||||||
|
const areaPhysDir = getAreaStorageDirectory(areaInfo);
|
||||||
|
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
function scanPhysFiles(callback) {
|
||||||
|
fs.readdir(areaPhysDir, (err, files) => {
|
||||||
|
if(err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
async.each(files, (fileName, next) => {
|
||||||
|
const fullPath = paths.join(areaPhysDir, fileName);
|
||||||
|
|
||||||
|
fs.stat(fullPath, (err, stats) => {
|
||||||
|
if(err) {
|
||||||
|
// :TODO: Log me!
|
||||||
|
return next(null); // always try next file
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!stats.isFile()) {
|
||||||
|
return next(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
addOrUpdateFileEntry(areaInfo, fileName, err => {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, err => {
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function scanDbEntries(callback) {
|
||||||
|
// :TODO: Look @ db entries for area that were *not* processed above
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ const _ = require('lodash');
|
||||||
|
|
||||||
const FILE_TABLE_MEMBERS = [
|
const FILE_TABLE_MEMBERS = [
|
||||||
'file_id', 'area_tag', 'file_sha1', 'file_name',
|
'file_id', 'area_tag', 'file_sha1', 'file_name',
|
||||||
'desc', 'desc_long', 'upload_by_username', 'upload_timestamp'
|
'desc', 'desc_long', 'upload_by_username', 'upload_timestamp' // :TODO: remove upload_by_username -- and from database.js, etc.
|
||||||
];
|
];
|
||||||
|
|
||||||
const FILE_WELL_KNOWN_META = {
|
const FILE_WELL_KNOWN_META = {
|
||||||
|
|
|
@ -37,6 +37,8 @@ exports.moduleInfo = {
|
||||||
* Support NetMail
|
* Support NetMail
|
||||||
* NetMail needs explicit isNetMail() check
|
* NetMail needs explicit isNetMail() check
|
||||||
* NetMail filename / location / etc. is still unknown - need to post on groups & get real answers
|
* NetMail filename / location / etc. is still unknown - need to post on groups & get real answers
|
||||||
|
* Validate packet passwords!!!!
|
||||||
|
=> secure vs insecure landing areas
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -49,9 +51,7 @@ function FTNMessageScanTossModule() {
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
this.archUtil = new ArchiveUtil();
|
this.archUtil = ArchiveUtil.getInstance();
|
||||||
this.archUtil.init();
|
|
||||||
|
|
||||||
|
|
||||||
if(_.has(Config, 'scannerTossers.ftn_bso')) {
|
if(_.has(Config, 'scannerTossers.ftn_bso')) {
|
||||||
this.moduleConfig = Config.scannerTossers.ftn_bso;
|
this.moduleConfig = Config.scannerTossers.ftn_bso;
|
||||||
|
|
|
@ -67,6 +67,8 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
this.filterCriteria = this.filterCriteria || {
|
this.filterCriteria = this.filterCriteria || {
|
||||||
// :TODO: set area tag - all in current area by default
|
// :TODO: set area tag - all in current area by default
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.currentFileEntry = new FileEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
enter() {
|
enter() {
|
||||||
|
@ -139,9 +141,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
function fetchEntryData(callback) {
|
function fetchEntryData(callback) {
|
||||||
return self.loadFileIds(callback);
|
return self.loadFileIds(callback);
|
||||||
},
|
},
|
||||||
function loadCurrentFileInfo(callback) {
|
function loadCurrentFileInfo(callback) {
|
||||||
self.currentFileEntry = new FileEntry();
|
|
||||||
|
|
||||||
self.currentFileEntry.load( self.fileList[ self.fileListPosition ], err => {
|
self.currentFileEntry.load( self.fileList[ self.fileListPosition ], err => {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
});
|
});
|
||||||
|
|
78
oputil.js
78
oputil.js
|
@ -38,6 +38,7 @@ global args:
|
||||||
commands:
|
commands:
|
||||||
user : user utilities
|
user : user utilities
|
||||||
config : config file management
|
config : config file management
|
||||||
|
file-area : file area management
|
||||||
|
|
||||||
`,
|
`,
|
||||||
User :
|
User :
|
||||||
|
@ -56,11 +57,24 @@ valid args:
|
||||||
|
|
||||||
valid args:
|
valid args:
|
||||||
--new : generate a new/initial configuration
|
--new : generate a new/initial configuration
|
||||||
|
`,
|
||||||
|
FileArea :
|
||||||
|
`usage: oputil.js file-area <args>
|
||||||
|
|
||||||
|
valid args:
|
||||||
|
--scan AREA_TAG : (re)scan area specified by AREA_TAG for new files
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
function printUsage(command) {
|
function printUsageAndSetExitCode(command, exitCode) {
|
||||||
console.error(USAGE_HELP[command]);
|
if(_.isUndefined(exitCode)) {
|
||||||
|
exitCode = ExitCodes.ERROR;
|
||||||
|
}
|
||||||
|
process.exitCode = exitCode;
|
||||||
|
const errMsg = USAGE_HELP[command];
|
||||||
|
if(errMsg) {
|
||||||
|
console.error(errMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initConfig(cb) {
|
function initConfig(cb) {
|
||||||
|
@ -144,8 +158,7 @@ function setAccountStatus(userName, active) {
|
||||||
|
|
||||||
function handleUserCommand() {
|
function handleUserCommand() {
|
||||||
if(true === argv.help || !_.isString(argv.user) || 0 === argv.user.length) {
|
if(true === argv.help || !_.isString(argv.user) || 0 === argv.user.length) {
|
||||||
process.exitCode = ExitCodes.ERROR;
|
return printUsageAndSetExitCode('User', ExitCodes.ERROR);
|
||||||
return printUsage('User');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_.isString(argv.password)) {
|
if(_.isString(argv.password)) {
|
||||||
|
@ -399,8 +412,7 @@ function askNewConfigQuestions(cb) {
|
||||||
|
|
||||||
function handleConfigCommand() {
|
function handleConfigCommand() {
|
||||||
if(true === argv.help) {
|
if(true === argv.help) {
|
||||||
process.exitCode = ExitCodes.ERROR;
|
return printUsageAndSetExitCode('Config', ExitCodes.ERROR);
|
||||||
return printUsage('Config');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(argv.new) {
|
if(argv.new) {
|
||||||
|
@ -419,11 +431,51 @@ function handleConfigCommand() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
process.exitCode = ExitCodes.ERROR;
|
return printUsageAndSetExitCode('Config', ExitCodes.ERROR);
|
||||||
return printUsage('Config');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fileAreaScan(areaTag) {
|
||||||
|
async.waterfall(
|
||||||
|
[
|
||||||
|
function init(callback) {
|
||||||
|
return initConfigAndDatabases(callback);
|
||||||
|
},
|
||||||
|
function getFileArea(callback) {
|
||||||
|
const fileAreaMod = require('./core/file_area.js');
|
||||||
|
|
||||||
|
const areaInfo = fileAreaMod.getFileAreaByTag(argv.scan);
|
||||||
|
if(!areaInfo) {
|
||||||
|
return callback(new Error('Invalid file area'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(null, fileAreaMod, areaInfo);
|
||||||
|
},
|
||||||
|
function performScan(fileAreaMod, areaInfo, callback) {
|
||||||
|
fileAreaMod.scanFileAreaForChanges(areaInfo, err => {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
],
|
||||||
|
err => {
|
||||||
|
if(err) {
|
||||||
|
process.exitCode = ExitCodes.ERROR;
|
||||||
|
console.error(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFileAreaCommand() {
|
||||||
|
if(true === argv.help) {
|
||||||
|
return printUsageAndSetExitCode('FileArea', ExitCodes.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argv.scan) {
|
||||||
|
return fileAreaScan(argv.scan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
|
|
||||||
process.exitCode = ExitCodes.SUCCESS;
|
process.exitCode = ExitCodes.SUCCESS;
|
||||||
|
@ -435,8 +487,7 @@ function main() {
|
||||||
if(0 === argv._.length ||
|
if(0 === argv._.length ||
|
||||||
'help' === argv._[0])
|
'help' === argv._[0])
|
||||||
{
|
{
|
||||||
printUsage('General');
|
printUsageAndSetExitCode('General', ExitCodes.SUCCESS);
|
||||||
process.exit(ExitCodes.SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(argv._[0]) {
|
switch(argv._[0]) {
|
||||||
|
@ -448,9 +499,12 @@ function main() {
|
||||||
handleConfigCommand();
|
handleConfigCommand();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'file-area' :
|
||||||
|
handleFileAreaCommand();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printUsage('');
|
printUsageAndSetExitCode('', ExitCodes.BAD_COMMAND);
|
||||||
process.exitCode = ExitCodes.BAD_COMMAND;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue