123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- /**
- * tail-file.js: TODO: add file header description.
- *
- * (C) 2010 Charlie Robbins
- * MIT LICENCE
- */
- 'use strict';
- const fs = require('fs');
- const { StringDecoder } = require('string_decoder');
- const { Stream } = require('readable-stream');
- /**
- * Simple no-op function.
- * @returns {undefined}
- */
- function noop() {}
- /**
- * TODO: add function description.
- * @param {Object} options - Options for tail.
- * @param {function} iter - Iterator function to execute on every line.
- * `tail -f` a file. Options must include file.
- * @returns {mixed} - TODO: add return description.
- */
- module.exports = (options, iter) => {
- const buffer = Buffer.alloc(64 * 1024);
- const decode = new StringDecoder('utf8');
- const stream = new Stream();
- let buff = '';
- let pos = 0;
- let row = 0;
- if (options.start === -1) {
- delete options.start;
- }
- stream.readable = true;
- stream.destroy = () => {
- stream.destroyed = true;
- stream.emit('end');
- stream.emit('close');
- };
- fs.open(options.file, 'a+', '0644', (err, fd) => {
- if (err) {
- if (!iter) {
- stream.emit('error', err);
- } else {
- iter(err);
- }
- stream.destroy();
- return;
- }
- (function read() {
- if (stream.destroyed) {
- fs.close(fd, noop);
- return;
- }
- return fs.read(fd, buffer, 0, buffer.length, pos, (err, bytes) => {
- if (err) {
- if (!iter) {
- stream.emit('error', err);
- } else {
- iter(err);
- }
- stream.destroy();
- return;
- }
- if (!bytes) {
- if (buff) {
- // eslint-disable-next-line eqeqeq
- if (options.start == null || row > options.start) {
- if (!iter) {
- stream.emit('line', buff);
- } else {
- iter(null, buff);
- }
- }
- row++;
- buff = '';
- }
- return setTimeout(read, 1000);
- }
- let data = decode.write(buffer.slice(0, bytes));
- if (!iter) {
- stream.emit('data', data);
- }
- data = (buff + data).split(/\n+/);
- const l = data.length - 1;
- let i = 0;
- for (; i < l; i++) {
- // eslint-disable-next-line eqeqeq
- if (options.start == null || row > options.start) {
- if (!iter) {
- stream.emit('line', data[i]);
- } else {
- iter(null, data[i]);
- }
- }
- row++;
- }
- buff = data[l];
- pos += bytes;
- return read();
- });
- }());
- });
- if (!iter) {
- return stream;
- }
- return stream.destroy;
- };
|