Skip to content

Instantly share code, notes, and snippets.

@jhead
Created August 15, 2015 15:32
Show Gist options
  • Save jhead/8e88779036f3f6cc595f to your computer and use it in GitHub Desktop.
Save jhead/8e88779036f3f6cc595f to your computer and use it in GitHub Desktop.
import crypto from 'crypto';
import { EventEmitter } from 'events';
import fs from 'fs';
class ChunkedFileHasher extends EventEmitter {
constructor(path, chunkSize = 512) {
super();
this.paused = true;
this.ready = false;
this.chunkSize = chunkSize;
this.filePath = path;
this.fileStream = null;
this.fileDescriptor = null;
this.fileStats = null;
this.buffer = null;
this.bufferOffset = 0;
this.chunkOffset = 0;
init.bind(this)();
}
static hashChunk(chunk, algorithm = 'sha1') {
return crypto
.createHash(algorithm)
.update(chunk)
.digest('hex');
}
}
export default ChunkedFileHasher;
/** Private Functions **/
function init() {
this.on('newEventListener', (event) => {
if (event === 'hash' && !this.paused) {
this.paused = false;
if (this.ready)
begin.bind(this)();
}
});
this.buffer = new Buffer(this.chunkSize);
fs.stat(this.filePath, (err, stats) => {
if (err) {
this.emit('error', err);
return;
}
this.fileStats = stats;
});
this.stream = fs.createReadStream(this.filePath);
this.stream.on('open', (fd) => {
this.fileDescriptor = fd;
this.ready = true;
if (this.paused)
begin.bind(this)();
});
}
function begin() {
chunkReadLoop.bind(this)(() => {
this.emit('end');
});
}
function chunkReadLoop(callback) {
let { fileDescriptor, buffer, bufferOffset } = this;
let args = [ fileDescriptor, buffer, 0, buffer.length, bufferOffset ];
buffer.fill(0);
fs.read(...args, (err, bytesRead) => {
if (err) throw err;
this.bufferOffset += bytesRead;
let hash = ChunkedFileHasher.hashChunk(buffer.slice(0, bytesRead));
this.emit('hash', hash);
if (this.bufferOffset < this.fileStats.size)
return chunkReadLoop.bind(this)(callback);
callback();
});
}
import path from 'path';
import ChunkedFileHasher from './ChunkedFileHasher';
const CHUNK_SIZE = 512;
const args = process.argv.slice(2);
const inputPath = path.resolve(args[0]);
let hasher = new ChunkedFileHasher(inputPath, CHUNK_SIZE);
hasher.on('hash', (hash) => {
console.log(hash);
});
hasher.on('end', () => {
console.log('Done');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment