read-last-lines icon indicating copy to clipboard operation
read-last-lines copied to clipboard

Want a More Modern Version of Your Code?

Open machineghost opened this issue 3 years ago • 1 comments

I stole your source code, and then revamped it to use modern JS (eg. async/await). I also changed your snake case variables to camel case, factored a few inner functions outside, etc. (I also eliminated the encoding arg since I didn't need it, but it could easily be restored and I left a note about it in the comments.)

Now I completely understand that when someone says "hey I took your great source code and screwed it all up", the original author runs screaming in the opposite :) So feel free to close this ticket without even looking at it ... but just in case you wanted to see my take, I thought I'd share.

Either way though, thanks for making this (small but useful) library :)

const readPreviousChar = async (stat, file, currentCharacterCount) => {
  const position = stat.size - 1 - currentCharacterCount;
  const { bytesRead, buffer } = await fs.read(
    file, // file descriptor
    Buffer.alloc(1), // buffer to write data to
    0, // offset
    1, // # of bytes to read
    position // position in data to read
  );
  return String.fromCharCode(buffer[0]);
};

const NEW_LINE_CHARACTERS = ['\n'];

const doWhileLoop = async function (
  self,
  lines,
  chars,
  lineCount,
  maxLineCount,
  resolve
) {
  if (lines.length > self.stat.size) {
    lines = lines.substring(lines.length - self.stat.size);
  }

  if (lines.length >= self.stat.size || lineCount >= maxLineCount) {
    if (NEW_LINE_CHARACTERS.includes(lines.substring(0, 1))) {
      lines = lines.substring(1);
    }
    fs.close(self.file);
    // I didn't have to worry about other encoding types;
    // if you want to keep supporting them this function would need an encoding arg
    // if (encoding === 'buffer') {
    //   return resolve(Buffer.from(lines, 'binary'));
    // }
    // return resolve(Buffer.from(lines, 'binary').toString(encoding));
    return resolve(Buffer.from(lines, 'binary').toString('utf8'));
  }

  const nextCharacter = await readPreviousChar(self.stat, self.file, chars);
  lines = nextCharacter + lines;
  if (NEW_LINE_CHARACTERS.includes(nextCharacter) && lines.length > 1) {
    lineCount++;
  }
  chars++;

  await doWhileLoop(self, lines, chars, lineCount, maxLineCount, resolve);
};

/**
 * Read in the last `n` lines of a file
 * @param  {string}   inputFilePath - file (direct or relative path to file.)
 * @param  {int}      maxLineCount    - max number of lines to read in.
 * @param  {encoding} encoding        - specifies the character encoding to be used, or 'buffer'. defaults to 'utf8'.
 *
 * @return {promise}  a promise resolved with the lines or rejected with an error.
 */
const readLast = async (inputFilePath, maxLineCount) => {
  return new Promise(async (resolve, reject) => {
    let self = { stat: null, file: null };

    try {
      // @see https://nodejs.org/api/fs.html#fsexistspath-callback
      // "Using fs.exists() to check for the existence of a file before calling
      // fs.open(), fs.readFile() or fs.writeFile() is not recommended"

      // if (!(await fs.exists(inputFilePath))) {
      //   throw new Error(`file does not exist: ${inputFilePath}`);
      // }

      await Promise.all([
        // Load file Stats.
        fs.stat(inputFilePath).then((stat) => (self.stat = stat)),
        // Open file for reading.
        fs.open(inputFilePath, 'r').then((file) => (self.file = file)),
      ]);
      let chars = 0;
      let lines = '';

      return doWhileLoop(self, lines, chars, 0, maxLineCount, resolve);
    } catch (reason) {
      if (self.file !== null) {
        try {
          fs.close(self.file);
        } catch {
          // We might get here if the encoding is invalid.
          // Since we are already rejecting, let's ignore this error.
        }
      }
      return reject(reason);
    }
  });
};

machineghost avatar Oct 24 '21 17:10 machineghost

Check here: https://github.com/tjx666/scripting-listener/blob/master/src/LogViewer/readLastLines.ts

tjx666 avatar Mar 15 '22 20:03 tjx666