mStream/src/db/task-queue.js
2021-01-11 11:49:13 -05:00

112 lines
3.4 KiB
JavaScript

const child = require('child_process');
const path = require('path');
const winston = require('winston');
const nanoid = require('nanoid');
const config = require('../state/config');
const mstreamReadPublicDB = require('../../modules/db-read/database-public-loki');
const taskQueue = [];
const runningTasks = new Set();
const vpathLimiter = new Set();
let scanIntervalTimer = null; // This gets set after the server boots
function addScanTask(vpath) {
if (runningTasks.size < config.program.scanOptions.maxConcurrentTasks) {
runScan(vpath);
} else {
taskQueue.push({ task: 'scan', vpath: vpath, id: nanoid.nanoid(8) });
}
}
function removeTask(taskId) {
}
function scanAll() {
Object.keys(config.program.folders).forEach((vpath) => {
addScanTask(vpath);
});
}
function nextTask() {
if (taskQueue.length > 0 && runningTasks.size < config.program.scanOptions.maxConcurrentTasks && !vpathLimiter.has(taskQueue[taskQueue.length - 1].vpath)) {
runScan(taskQueue.pop().vpath);
}
}
function runScan(vpath) {
let parseFlag = false;
const jsonLoad = {
directory: config.program.folders[vpath].root,
vpath: vpath,
dbPath: path.join(config.program.storage.dbDirectory, mstreamReadPublicDB.getFileDbName()),
albumArtDirectory: config.program.storage.albumArtDirectory,
skipImg: config.program.scanOptions.skipImg,
saveInterval: config.program.scanOptions.saveInterval,
pause: config.program.scanOptions.pause,
supportedFiles: config.program.supportedAudioFiles
};
const forkedScan = child.fork(path.join(__dirname, './scanner.js'), [JSON.stringify(jsonLoad)], { silent: true });
winston.info(`File scan started on ${jsonLoad.directory}`);
runningTasks.add(forkedScan);
vpathLimiter.add(vpath);
forkedScan.stdout.on('data', (data) => {
try {
const parsedMsg = JSON.parse(data, 'utf8');
winston.info(`File scan message: ${parsedMsg.msg}`);
// TODO: Ideally, if there are no changes to the DB we should not be reloading it. Ideally...
if (parsedMsg.loadDB === true) {
parseFlag = true;
mstreamReadPublicDB.loadDB();
}
} catch (error) {
winston.info(`File scan message: ${data}`);
}
});
forkedScan.stderr.on('data', (data) => {
winston.error(`File scan error: ${data}`);
});
forkedScan.on('close', (code) => {
if(parseFlag === false) {
mstreamReadPublicDB.loadDB();
}
runningTasks.delete(forkedScan);
vpathLimiter.delete(vpath);
nextTask();
winston.info(`File scan completed with code ${code}`);
});
}
exports.scanVPath = (vPath) => {
addScanTask(vPath);
}
exports.scanAll = () => {
scanAll();
}
exports.isScanning = () => {
return runningTasks.size > 0 ? true : false;
}
exports.runAfterBoot = () => {
setTimeout(() => {
// This only gets run once after boot. Will not be run on server restart b/c scanIntervalTimer is already set
if (config.program.scanOptions.scanInterval > 0 && scanIntervalTimer === null) {
scanAll();
scanIntervalTimer = setInterval(() => scanAll(), config.program.scanOptions.scanInterval * 60 * 60 * 1000);
}
}, config.program.scanOptions.scanDelay * 1000);
}
exports.resetScanInterval = () => {
if (scanIntervalTimer) { clearInterval(scanIntervalTimer); }
if (config.program.scanOptions.scanInterval > 0) {
scanIntervalTimer = setInterval(() => scanAll(), config.program.scanOptions.scanInterval * 60 * 60 * 1000);
}
}