UNPKG

synapse_fs

Version:
169 lines (145 loc) 5.84 kB
//Each node has it's own thread count, starting at 0 var fs = require('fs'); //Require, but without setting a reference, and instead just directly instantiating a new instance, with constructor parameter of 0 (Singleton pattern) var threadCounter = new (require('./ThreadCounter/ThreadCounter'))(0); var File = require('./file'); var globalFileIndex = {}; var rootSearchPath; /* * Functionality: * - Reads some root directory provided by user input, for file names * - Calls stat with the file names that were found, and retrieves the file type (File, Directory, Link, etc); * - Returns an objectResult to the callback function, listing all Files/Directories & their properties. */ function FileSearchEngine (options, callback, threadId) { //if dirName == '/' then we are looking at a drive name (root node): / or c:\ if (options && options.searchPath) { /*if (options.searchPath == '/') this.searchPath = options.searchPath; else*/ this.searchPath = options.searchPath + '/'; } else throw 'Error! A search path has not been provided.'; if (options && Number(options.maxDepth) >= 0) { this.maxDepth = options.maxDepth; if (!this.currenDepth) this.currentDepth = 0; } if (options && Number(options.currentDepth) >= 0) this.currentDepth = options.currentDepth; this.remainingFileCount = 0; this.callback = callback; if (threadId) this.threadId = threadId; else this.threadId = threadCounter.newThread(options.searchPath); }; FileSearchEngine.prototype.constructor = FileSearchEngine; FileSearchEngine.prototype.list = function list () { fs.readdir(this.searchPath, this.readDirHandler.bind(this)); }; /* * Reads the contents of a directory. The callback gets two arguments (err, files) where files is an array of the names * of the files in the directory excluding '.' and '..'. */ FileSearchEngine.prototype.readDirHandler = function readDirHandler (error, dirFileList) { if (error) { threadCounter.closeThread(this.threadId); console.log(error); this.callback(error); this.rootSearchPath = null; globalFileIndex = {}; } else if (threadCounter.isActiveThread(this.threadId)) { //If count down counter is 0, Initialize it. if (!this.remainingFileCount) this.remainingFileCount = dirFileList.length; //If a folder is empty at depth 0, close the thread, otherwise it'll just hang. //Only counts for the first thread. We don't want to return if we find empty folders in other threads. if (dirFileList.length == 0 && threadCounter.threadCount == 1) { threadCounter.closeThread(this.threadId); this.callback(globalFileIndex); rootSearchPath = null; //reset root search path globalFileIndex = {}; //Need to reset the file index, since it's global it will retain it's state. } else if (dirFileList.length == 0) //Still need to close the thread when an empty folder is detected at a depth > 0 threadCounter.closeThread(this.threadId); dirFileList.forEach(this.searchDir.bind(this)); } }; FileSearchEngine.prototype.searchDir = function searchDir (fileName) { if (this.searchPath && this.searchPath.length > 0) { //At initialization, set the root search path if (!rootSearchPath && threadCounter.threadCount == 1) rootSearchPath = this.searchPath; var absoluteFileName = this.searchPath + fileName; fs.stat(absoluteFileName, this.handleStats.bind(this, absoluteFileName, fileName)); } }; FileSearchEngine.prototype.handleStats = function handleStats (absoluteFileName, fileName, error, stats) { if (!(absoluteFileName in globalFileIndex)) globalFileIndex[absoluteFileName] = new File({absoluteFileName: absoluteFileName, fileName: fileName, rootSearchPath : rootSearchPath}); else globalFileIndex[absoluteFileName].error = 'Duplicate file name detected'; if (error) { globalFileIndex[absoluteFileName].error = error; globalFileIndex[absoluteFileName].isDirectory = false; globalFileIndex[absoluteFileName].isFile = false; this.ifDoneCallbackElseCloseThread(error); } else if (threadCounter.isActiveThread(this.threadId)) { if (stats) { if (absoluteFileName in globalFileIndex && !absoluteFileName.error) { if (stats.isDirectory()) { globalFileIndex[absoluteFileName].isDirectory = true; globalFileIndex[absoluteFileName].isFile = false; //This is a directory, so the absolute file name = directory path if ((Number(this.currentDepth) >= 0 && Number(this.maxDepth) >= 0 && this.currentDepth < this.maxDepth) || typeof this.maxDepth == 'undefined' || Number(this.maxDepth) < 0) new FileSearchEngine({searchPath: absoluteFileName, maxDepth: this.maxDepth, currentDepth: this.currentDepth + 1}, this.callback, threadCounter.newThread(absoluteFileName)).list(); } if (stats.isFile()) { globalFileIndex[absoluteFileName].isDirectory = false; globalFileIndex[absoluteFileName].isFile = true; } } else console.log('path not found: ' + absoluteFileName); } this.ifDoneCallbackElseCloseThread(); } }; FileSearchEngine.prototype.ifDoneCallbackElseCloseThread = function ifDoneCallbackElseCloseThread (resultOverride) { --this.remainingFileCount; //Close this last thread if (!this.remainingFileCount) threadCounter.closeThread(this.threadId); if (threadCounter.isDone() && !this.remainingFileCount && this.callback) { if (resultOverride) this.callback(resultOverride); else this.callback(globalFileIndex); rootSearchPath = null; //reset root search path globalFileIndex = {}; //Need to reset the file index, since it's global it will retain it's state. } }; module.exports = FileSearchEngine;