JavaScript

Working between renderer.js and walker.js with the help of walkerHelper.js to control FileWalker

As we discussed in previous tutorial, now we know how a child process works. In this tutorial we’ll create a child process file: walkerHelper.js. This child process will allow communication between renderer.js and walker.js (FileWalker class) files. The walkerHelper.js receives start, stop, pause and resume commands from the parent process, renderer.js, to control the FileWalker and send the duplicate files back to renderer.js when FileWalker (walker.js) emits duplicate event.

Let’s start writing the code, first we include the walker.js and options.js file:

const walkerClass = require('./walker.js'),
OPT = require ('./options.js');

Next, we create some variables to store some information, like:

let includedDirs=[],
excludedDirs=[],
totalProcessedFiles=0,
totalProcessedDirs=0;

The includedDirs and excludedDirs arrays will store the paths received from the parent (renderer.js). The totalProcessedFiles and totalProcessedDirs will count the processed files and dirs.

Receiving messages from walker.js

Next, we’ll create a new instance of FileWalker class and respond to its event by creating the callback functions:

let walker = new walkerClass();
walker.on('error', cbError);
walker.on('file',  cbFile);
walker.on('dir',   cbDir);
walker.on('hash',  cbHash);
walker.on('unknown', cbUnknow);
walker.on('pause',  cbPause);
walker.on('resume', cbResume);
walker.on('duplicate',cbDuplicate);
walker.on('done', cbDone);

The explanation of each callback function is:

  1. FileWalker.on('error', cbError)
    Run the cbError function If error occurred while scanning or reading the entry (dir or file)
  2. FileWalker.on('file', cbFile)
    Run cbFile function when a file entry found.
  3. FileWalker.on('dir', cbDir)
    Execute cbDir function when a directory entry found.
  4. FileWalker.on('unknown', cbUnknown)
    Run cbUnknown function if an unknown error occurred while scanning or reading the entry.
  5. FileWalker.on('hash', cbHash)
    Execute cbHash function when a Hash generated for a file.
  6. FileWalker.on('duplicate', cbDuplicate)
    Run cbDuplicate function when a duplicate file entry found.
  7. FileWalker.on('pause', cbPause)
    Run cbPause function when FileWalker paused.
  8. FileWalker.on('resume', cbResume)
    Run cbResume function when FileWalker resumed.
  9. FileWalker.on('done', cbDone)
    Run the cbDone function when FileWalker finished scanning.

Receiving messages from renderer.js

The walkerHelper.js process will receive messages in an object form from its parent:

process.on('message',(m)=>{
 switch (m.walker){
  case OPT.START:
   start(m.dirs);
  break;

  case OPT.PAUSE:
   walker.pause();
  break;
  
  case OPT.RESUME:
   walker.resume();
  break;
  
  case OPT.RESET:
   reset();
  break;
 }
})

The process.on event listen IPC messages from parent. We use switch case statement to filter out the received message. The start function will execute if the received message contains OPT.START value. The start function will store the files in includedDirs and excludedDirs array and start the FileWalker.

The OPT.PAUSE and OPT.RESUME will use to pause and resume the FileWalker.

Let’s create the start and reset functions later in this tutorial.

start function

When a user click on the start button, the renderer.js file sends OPT.START message along with a dirs object. The dirs object is a nested object which contains dir objects, each dir object has two properties: path and isIncluded. If the isIncluded property is true then the dir path added to includedDirs array otherwise it added to excludedDirs array.

function start(dirs){
 reset();

 for (let i in dirs){
  let dir = dirs[i];
  if (dir.isIncluded)
   includedDirs.push(dir.path);
  else 
   excludedDirs.push(dir.path);
 }
 //add to walker's queue
 walker.addToQueue(includedDirs);

 //walker's callback function to filter dirs
 walker.filterDir((dir,stat)=>{
  return excludedDirs.indexOf(dir) !== -1
 });
 
 walker.next();

 let obj = {
  walker:OPT.STARTED
 }

 process.send(obj);
}

Then we pass the includedDirs array to walker.addToQueue method. Next, the walker.filterDir callback method compare the each dir, found on the file-system, with excludedDirs array. The matched dir path will not scan.

The walker.next(); starts the file system scanning for next available entry from the queue. Then we send a OPT.STARTED message to renderer.js to inform that walker started and scanning the received directories.

reset function

The reset function resets the FileWalker and the following variables:

function reset(){
 walker.reset();
 includedDirs=[],
 excludedDirs=[],
 totalProcessedFiles=0,
 totalProcessedDirs=0;
}

It is useful when a user want to start a new scanning and cancel the existing process.

Creating FileWalker callback functions

cbError function

We can use this function to log error messages.

function cbError(err,entry,stat){
 //The entry has some issues
 console.log(err)
}

cbUnknown function

An unknown error occurred, it usually receive on Windows os, when walker try to scan system or protected files or dirs.

function cbError(entry,stat){
 //The entry has some issues
 console.log(err)
}

cbFile function

This function triggered when a file found, we’ll use this function to count processed files:

function cbFile(entry,stat){
 totalProcessedFiles++;

/*You can send file information to parent
  if necessary.
 let obj = {
 walker: OPT.FILE,
 file: entry,
 stat: stat,
 totalProcessedFiles:totalProcessedFiles
 }
 process.send(obj)*/

}

cbDir function

This function will trigger when a director found while scanning file system. The process.send method send an object to renderer.js, which contains the current working directory along-with its stat and total processed dirs.

function cbDir(entry,stat){
 totalProcessedDirs++
 
 let obj = {
 walker: OPT.DIR,
 dir: entry,
 stat: stat,
 totalDirs:totalProcessedDirs
 }
 process.send(obj);
}

cbHash function

cbHash function returns file, its stat and its generated hash. We don’t need it at this moment, we’ll use it when a duplicate file found.

function cbHash(file,stat,hash){
 //We'll not use this cb
 //For demonstration purpose only
}

cbPause and cbResume functions

These methods trigger when FileWalker paused or resume. We’ll send a message OPT.PAUSED or OPT.RESUMED to parent, renderer.js, to inform FileWalker has been paused or resumed.

function cbPause(){
 let obj = {
  walker:OPT.PAUSED
 }
 process.send(obj);
}

function cbResume(){
 let obj = {
  walker: OPT.RESUMED
 }
 process.send(obj);
}

cbDuplicate function

Here we’ll receive the duplicate files. This method has four parameters:

  1. files (array)
  2. size (integer)
  3. ext (string)
  4. hash (stirng)
function cbDuplicate(files,size,ext,hash){
 let df = JSON.stringify(
         {size:size,
          id:hash+ext+size,
          files:files}
 );
 
 let obj = {
  walker:    OPT.WEBVIEW,
  addRows:   'addRows('+df+')'
 }
 process.send(obj);
}

We’ll send these file to renderer.js to display on GUI. We’ll use chrome’s webview feature to display duplicate files in index.html file.

cbDone function

This method triggered when FileWalker finished scanning the provided directories.

function cbDone(){
 let obj = {
  walker:    OPT.DONE,
  totalFiles:totalProcessedFiles,
  totalDirs: totalProcessedDirs
 }
  process.send(obj);
}

This function send OPT.DONE message to renderer.js. The message properties are:

  • totalFiles the number of files read
  • totalDirs the number of directories scanned

Next, we’ll re-create the rendrer.js file so it can communicate properly with walkerHelper.js by establishing the IPC channel between them.

Click here to download walkerHelper.js file.