Skip to content

Instantly share code, notes, and snippets.

@stuartambient
Last active December 14, 2020 18:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stuartambient/b96fcb65d58e2916cad6f84ab380337c to your computer and use it in GitHub Desktop.
Save stuartambient/b96fcb65d58e2916cad6f84ab380337c to your computer and use it in GitHub Desktop.
NodeJS Design Patterns (third edition) challenges
import { readdir, stat } from 'fs';
import { basename, join, resolve } from 'path';
import { TaskQueue } from './TaskQueue.js';
import { searchFile, processFile } from './searchFiles.js';
let results = [],
allFiles = [],
processed = null,
readFiles = false;
function fileType(file, cb) {
stat(file, function (err, stats) {
if (err) cb(err);
return cb(null, stats);
});
}
export default function recursiveFind(dir, keyword, queue, completed) {
readdir(dir, function (err, files) {
if (err) return completed(err.message);
let remaining = files.length;
if (!remaining) completed(null, keyword, allFiles);
//(!remaining) return completed(null, results);
files.forEach(function (file) {
file = resolve(dir, file);
fileType(file, (err, stats) => {
if (err) completed(err);
if (stats.isDirectory()) {
recursiveFind(file, keyword, queue, function (err, res) {
//results = results.concat(res);
if (!--remaining) completed(null, keyword, allFiles);
});
} else {
allFiles.push(file);
if (!--remaining) completed(null, keyword, queue, allFiles);
}
});
});
});
}
function completed(err, keyword, allFiles) {
if (err) console.error(err.message);
allFiles.forEach(file =>
processFile(file, keyword, queue, function (err, result) {
if (err) console.error(err.message);
if (result) results.push(result);
})
);
}
const queue = new TaskQueue(2);
queue.on('error', error => console.log('error: ', error.message));
queue.on('empty', () => console.log(results));
recursiveFind('../..', 'scripts', queue, completed);
import { readFile } from 'fs';
export function searchFile(file, keyword, done, cb) {
readFile(file, 'utf8', (err, data) => {
if (err) return cb(err);
if (data) {
cb(null, data.includes(keyword));
}
return done();
});
}
export function processFile(file, keyword, queue, cb) {
queue.pushTask(done => {
searchFile(file, keyword, done, function (err, matched) {
if (err) return console.log(err);
if (matched) {
cb(null, file);
}
});
});
}
import { EventEmitter } from 'events';
export class TaskQueue extends EventEmitter {
constructor(concurrency) {
super();
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
this.count = 0;
}
pushTask(task) {
//console.log(this.count++, this.queue.length);
this.queue.push(task);
process.nextTick(this.next.bind(this));
return this;
}
next() {
if (this.running === 0 && this.queue.length === 0) {
return this.emit('empty');
}
while (this.running < this.concurrency && this.queue.length) {
const task = this.queue.shift();
task(err => {
if (err) {
this.emit('error', err);
}
this.running--;
process.nextTick(this.next.bind(this));
});
this.running++;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment