Воспроизведите файл журнала с NodeJS, как будто это происходит в режиме реального времени

У меня есть файл журнала с приблизительно 14.000 точками данных о местоположении самолета, захваченными из системы под названием Flarm, это выглядит так:

{"addr":"A","time":1531919658.578100,"dist":902.98,"alt":385,"vs":-8}
{"addr":"A","time":1531919658.987861,"dist":914.47,"alt":384,"vs":-7}
{"addr":"A","time":1531919660.217471,"dist":925.26,"alt":383,"vs":-7}
{"addr":"A","time":1531919660.623466,"dist":925.26,"alt":383,"vs":-7}

Что мне нужно сделать, так это найти способ "воспроизвести" этот файл в режиме реального времени (как если бы он происходил прямо сейчас, даже если он был предварительно записан) и генерировать событие всякий раз, когда происходит запись в журнале. Файл не добавляется, он предварительно записан, и воспроизведение начнется на более поздней стадии.

Причина этого заключается в том, что у меня нет доступа к принимающему оборудованию во время разработки.

Единственный способ, которым я могу думать, это установить тайм-аут для каждой записи журнала, но это не похоже на правильный способ сделать это. Кроме того, этот процесс должен был бы масштабироваться для более длинных записей (этот был только часом).

Есть ли другие способы сделать это?

3 ответа

Решение

Если вы хотите "воспроизвести их" с фактической разницей во времени, setTimeout в значительной степени то, что вы должны сделать.

const processEntry = (entry, index) => {
  index++;
  const nextEntry = getEntry(index);
  if (nextEntry == null) return;

  const timeDiff = nextEntry.time - entry.time;
  emitEntryEvent(entry);
  setTimeout(processEntry, timeDiff, nextEntry, index);
};

processEntry(getEntry(0), 0);

Это излучает текущую запись, а затем устанавливает тайм-аут на основе разницы до следующей записи. getEntry может либо извлекать строки из предварительно заполненного массива, либо извлекать строки по отдельности на основе индекса. В последнем случае только две строки данных будут одновременно находиться в памяти.

Получилось это работает в конце концов! setTimeout оказался ответом, и в сочетании с вводом Лукаса С. вот что я закончил:

const EventEmitter = require('events');
const fs = require('fs');

const readable = fs.createReadStream("./data/2018-07-18_1509log.json", {
  encoding: 'utf8',
  fd: null
});

function read_next_line() {
  var chunk;
  var line = '';
  // While this is a thing we can do, assign chunk
  while ((chunk = readable.read(1)) !== null) {
    // If chunk is a newline character, return the line
    if (chunk === '\n'){
      return JSON.parse(line);
    } else {
      line += chunk;
    }
  }
  return false;
}

var lines = [];
var nextline;

const processEntry = () => {
  // If lines is empty, read a line
  if (lines.length === 0) lines.push(read_next_line());

  // Quit here if we've reached the last line
  if ((nextline = read_next_line()) == false) return true;

  // Else push the just read line into our array
  lines.push(nextline);

  // Get the time difference in milliseconds
  var delay = Number(lines[1].time - lines[0].time) * 1000;

  // Remove the first line
  lines.shift();

  module.exports.emit('data', lines[0]);

  // Repeat after the calculated delay
  setTimeout(processEntry, delay);
}

var ready_to_start = false;

// When the stream becomes readable, allow starting
readable.on('readable', function() {
  ready_to_start = true;
});


module.exports = new EventEmitter;
module.exports.start = function() {
  if (ready_to_start) processEntry();
  if (!ready_to_start) return false;
}

Предполагая, что вы хотите визуализировать журналы полетов, вы можете использовать fs смотрите, как показано ниже, чтобы посмотреть файл журнала на предмет изменений:

fs.watch('somefile', function (event, filename) {
    console.log('event is: ' + event);
    if (filename) {
        console.log('filename provided: ' + filename);
    } else {
        console.log('filename not provided');
    }
});

Отрывок кода отсюда. Для получения дополнительной информации о fs.watch() проверить здесь

Затем, для беспрепятственного обновления во внешнем интерфейсе, вы можете установить Websocket на свой сервер, где вы просматриваете файл журнала и отправляете вновь добавленную строку через этот сокет во внешний интерфейс.

После того, как вы получите данные во внешнем интерфейсе, вы сможете визуализировать их там. Несмотря на то, что я ранее не делал ни одного проекта по визуализации полета, я использовал D3js для визуализации других вещей (звук, числовые данные, метрический анализ и т. Д.) Пару раз, и он каждый раз выполнял свою работу.

Другие вопросы по тегам