UNPKG

serialport-v5

Version:

fork with electron support of Node.js package to access serial ports. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!

256 lines (214 loc) 7.08 kB
module.exports = Reader var fs = require('graceful-fs') var Stream = require('stream').Stream var inherits = require('inherits') var path = require('path') var getType = require('./get-type.js') var hardLinks = Reader.hardLinks = {} var Abstract = require('./abstract.js') // Must do this *before* loading the child classes inherits(Reader, Abstract) var LinkReader = require('./link-reader.js') function Reader (props, currentStat) { var self = this if (!(self instanceof Reader)) return new Reader(props, currentStat) if (typeof props === 'string') { props = { path: props } } // polymorphism. // call fstream.Reader(dir) to get a DirReader object, etc. // Note that, unlike in the Writer case, ProxyReader is going // to be the *normal* state of affairs, since we rarely know // the type of a file prior to reading it. var type var ClassType if (props.type && typeof props.type === 'function') { type = props.type ClassType = type } else { type = getType(props) ClassType = Reader } if (currentStat && !type) { type = getType(currentStat) props[type] = true props.type = type } switch (type) { case 'Directory': ClassType = require('./dir-reader.js') break case 'Link': // XXX hard links are just files. // However, it would be good to keep track of files' dev+inode // and nlink values, and create a HardLinkReader that emits // a linkpath value of the original copy, so that the tar // writer can preserve them. // ClassType = HardLinkReader // break case 'File': ClassType = require('./file-reader.js') break case 'SymbolicLink': ClassType = LinkReader break case 'Socket': ClassType = require('./socket-reader.js') break case null: ClassType = require('./proxy-reader.js') break } if (!(self instanceof ClassType)) { return new ClassType(props) } Abstract.call(self) if (!props.path) { self.error('Must provide a path', null, true) } self.readable = true self.writable = false self.type = type self.props = props self.depth = props.depth = props.depth || 0 self.parent = props.parent || null self.root = props.root || (props.parent && props.parent.root) || self self._path = self.path = path.resolve(props.path) if (process.platform === 'win32') { self.path = self._path = self.path.replace(/\?/g, '_') if (self._path.length >= 260) { // how DOES one create files on the moon? // if the path has spaces in it, then UNC will fail. self._swallowErrors = true // if (self._path.indexOf(" ") === -1) { self._path = '\\\\?\\' + self.path.replace(/\//g, '\\') // } } } self.basename = props.basename = path.basename(self.path) self.dirname = props.dirname = path.dirname(self.path) // these have served their purpose, and are now just noisy clutter props.parent = props.root = null // console.error("\n\n\n%s setting size to", props.path, props.size) self.size = props.size self.filter = typeof props.filter === 'function' ? props.filter : null if (props.sort === 'alpha') props.sort = alphasort // start the ball rolling. // this will stat the thing, and then call self._read() // to start reading whatever it is. // console.error("calling stat", props.path, currentStat) self._stat(currentStat) } function alphasort (a, b) { return a === b ? 0 : a.toLowerCase() > b.toLowerCase() ? 1 : a.toLowerCase() < b.toLowerCase() ? -1 : a > b ? 1 : -1 } Reader.prototype._stat = function (currentStat) { var self = this var props = self.props var stat = props.follow ? 'stat' : 'lstat' // console.error("Reader._stat", self._path, currentStat) if (currentStat) process.nextTick(statCb.bind(null, null, currentStat)) else fs[stat](self._path, statCb) function statCb (er, props_) { // console.error("Reader._stat, statCb", self._path, props_, props_.nlink) if (er) return self.error(er) Object.keys(props_).forEach(function (k) { props[k] = props_[k] }) // if it's not the expected size, then abort here. if (undefined !== self.size && props.size !== self.size) { return self.error('incorrect size') } self.size = props.size var type = getType(props) var handleHardlinks = props.hardlinks !== false // special little thing for handling hardlinks. if (handleHardlinks && type !== 'Directory' && props.nlink && props.nlink > 1) { var k = props.dev + ':' + props.ino // console.error("Reader has nlink", self._path, k) if (hardLinks[k] === self._path || !hardLinks[k]) { hardLinks[k] = self._path } else { // switch into hardlink mode. type = self.type = self.props.type = 'Link' self.Link = self.props.Link = true self.linkpath = self.props.linkpath = hardLinks[k] // console.error("Hardlink detected, switching mode", self._path, self.linkpath) // Setting __proto__ would arguably be the "correct" // approach here, but that just seems too wrong. self._stat = self._read = LinkReader.prototype._read } } if (self.type && self.type !== type) { self.error('Unexpected type: ' + type) } // if the filter doesn't pass, then just skip over this one. // still have to emit end so that dir-walking can move on. if (self.filter) { var who = self._proxy || self // special handling for ProxyReaders if (!self.filter.call(who, who, props)) { if (!self._disowned) { self.abort() self.emit('end') self.emit('close') } return } } // last chance to abort or disown before the flow starts! var events = ['_stat', 'stat', 'ready'] var e = 0 ;(function go () { if (self._aborted) { self.emit('end') self.emit('close') return } if (self._paused && self.type !== 'Directory') { self.once('resume', go) return } var ev = events[e++] if (!ev) { return self._read() } self.emit(ev, props) go() })() } } Reader.prototype.pipe = function (dest) { var self = this if (typeof dest.add === 'function') { // piping to a multi-compatible, and we've got directory entries. self.on('entry', function (entry) { var ret = dest.add(entry) if (ret === false) { self.pause() } }) } // console.error("R Pipe apply Stream Pipe") return Stream.prototype.pipe.apply(this, arguments) } Reader.prototype.pause = function (who) { this._paused = true who = who || this this.emit('pause', who) if (this._stream) this._stream.pause(who) } Reader.prototype.resume = function (who) { this._paused = false who = who || this this.emit('resume', who) if (this._stream) this._stream.resume(who) this._read() } Reader.prototype._read = function () { this.error('Cannot read unknown type: ' + this.type) }