UNPKG

bot18

Version:

A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f

246 lines (231 loc) 7.05 kB
var path = require('path') , fs = require('fs') , EventEmitter = require('events').EventEmitter , glob = require('glob') , LRU = require('lru-cache') , inherits = require('util').inherits function Dollop (globs, options) { EventEmitter.call(this); this.setMaxListeners(0); var self = this; Object.keys(Dollop.prototype).forEach(function (method) { self[method] = Dollop.prototype[method].bind(self); }); this.closed = false; this.isDollop = true; this.setParams(globs, options); this.reset(); setImmediate(this.scan); } inherits(Dollop, EventEmitter); Dollop.prototype.setParams = function (globs, options) { var self = this; this.options || (this.options = {}); Object.keys(options || {}).forEach(function (k) { self.options[k] = options[k]; }); var cwd = this.options.cwd || this.cwd; if (!globs) globs = '.'; // if "globs" is a dir/file, detect options from fs if (!cwd) { try { var stat = fs.statSync(globs); if (stat.isFile()) cwd = path.dirname(globs) else if (stat.isDirectory()) cwd = globs; globs = [cwd, cwd + '/**/*']; } catch (e) {} } this.cwd = path.resolve(cwd || process.cwd()); if (!Array.isArray(globs)) globs = globs.replace(/^\{|\}$/g, '').split(','); this.globs = globs; var absGlobs = [], absParents = [this.cwd]; globs.forEach(function (g) { var p = path.resolve(self.cwd, g); absGlobs.push(p); // find the part of the path preceding a *, if present var baseMatch = p.match(/([^\*]*)\/\*/); if (baseMatch) absParents.push(baseMatch[1]); }); this.stripRegex = new RegExp('^(' + absParents.sort(function (a, b) { var aMatch = a.match(/\//g); var bMatch = b.match(/\//g); if (aMatch && !bMatch) return -1; if (!aMatch && bMatch) return 1; if (aMatch && bMatch && aMatch.length !== bMatch.length) { return aMatch.length > bMatch.length ? -1 : 1; } return 0; }).join('|') + ')'); this.pattern = absGlobs.length < 2 ? absGlobs[0] : '{' + absGlobs.join(',') + '}'; this.watch = typeof this.options.watch !== 'undefined' ? this.options.watch : true; this.dirWatchers = {}; if (this.watch) { this.dirWatchers[this.cwd] = this.createWatcher(this.cwd); } }; Dollop.prototype.onErr = function (err) { if (err.code !== 'ENOENT') this.emit('error', err); }; Dollop.prototype.createWatcher = function (p) { var self = this; try { return fs.watch(p, {persistent: this.options.persistent}) .on('change', function () { self.scan(); }) .on('error', this.onErr); } catch (err) { this.onErr(err); } }; Dollop.prototype.scan = function () { if (this.closed) return false; if (this.scanning) return this.once('scan', this.scan); this.latch = 1; this.scanning = true; var self = this; glob(this.pattern, {stat: true, cwd: this.cwd, dot: this.options.dot}) .on('error', this.onErr) .on('stat', this.onStat) .on('end', function () { if (!--self.latch) self.onEnd(); }); }; Dollop.prototype.onStat = function (p, stat) { var self = this; var key = path.resolve(this.cwd, p).replace(this.stripRegex, ''); if (~this.keys.indexOf(key)) return; this.keys.push(key); var file = this.get(key); var cached = !!file; if (!cached) { file = { path: path.resolve(this.cwd, p).replace(this.cwd + '/', ''), cwd: this.cwd, fullPath: path.resolve(this.cwd, p), stat: stat, name: path.basename(p), key: key, read: fsMethod('readFile'), readSync: fsMethod('readFileSync'), readStream: fsMethod('createReadStream'), write: fsMethod('writeFile'), writeSync: fsMethod('writeFileSync'), writeStream: fsMethod('createWriteStream'), data: function (buf, options) { if (buf && toString.call(buf) === '[object Object]') { options = buf; buf = null; } options || (options = {}); if (buf) return this.writeSync(buf, options); if (!this._data || options.nocache) this._data = this.readSync(); if (options && options.encoding) return this._data.toString(options.encoding); return this._data; } }; function fsMethod (method) { return function () { var args = [].slice.call(arguments); args.unshift(file.fullPath); return fs[method].apply(fs, args); }; } file.parentDir = path.dirname(file.path); file.fullParentDir = path.dirname(file.fullPath); } var op = 'noop'; if (!cached || file.deleted) { op = 'add'; } else if (file.stat.isFile() && file.stat.mtime.getTime() !== stat.mtime.getTime()) { op = 'update'; } if (op !== 'noop') { file.stat = stat; delete file._data; if (this.watch && !file.watcher || file.deleted) { file.watcher = this.createWatcher(file.fullPath); if (typeof this.dirWatchers[file.fullParentDir] === 'undefined') { this.dirWatchers[file.fullParentDir] = this.createWatcher(file.fullParentDir); } } this.set(key, file); if (file.fullPath !== this.cwd) { this.emit(op, file); this.emit('all', op, file); } } }; Dollop.prototype.onEnd = function () { var self = this; var files = this.files(true); this.scanning = false; this.keys = []; this.emit('scan', files); this.emit('all', 'scan', files); if (!this.ready) { this.ready = true; this.emit('ready', files); this.emit('all', 'ready', files); } }; Dollop.prototype.files = function (doCleanup) { var self = this; return this.cache.values().filter(function (file) { if (file.deleted) return false; if (doCleanup && !~self.keys.indexOf(file.key)) { if (file.watcher) file.watcher.close(); file.deleted = true; self.set(file.key, file); if (file.fullPath !== self.cwd) { self.emit('cleanup', file); if (self.ready) { self.emit('remove', file); self.emit('all', 'remove', file); } else self.emit('all', 'cleanup', file); } } return file.fullPath !== self.cwd; }); }; Dollop.prototype.get = function (key) { var file = this.cache.get(key); if (file && file.deleted) return undefined; return file; }; Dollop.prototype.set = function (key, file) { return this.cache.set(key, file); }; Dollop.prototype.del = function (key) { return this.cache.del(key); }; Dollop.prototype.reset = function () { this.keys = []; var self = this; if (this.cache) { this.files(true); Object.keys(this.dirWatchers).forEach(function (p) { self.dirWatchers[p].close(); }); } this.scanning = false; this.ready = false; this.cache = LRU(this.options.cache || {}); this.emit('reset'); this.emit('all', 'reset'); }; Dollop.prototype.close = function () { this.closed = true; this.reset(); }; module.exports = function (globs, options) { return new Dollop(globs, options); }; module.exports.Dollop = Dollop; module.exports.isDollop = function (o) { return !!o.isDollop; };