Skip to content

Commit

Permalink
[DDW-812] Remove tail dependency and copy only the necessary code fro…
Browse files Browse the repository at this point in the history
…m it
  • Loading branch information
Lucas Araujo committed Mar 21, 2022
1 parent bf5d7be commit c186797
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 6 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@
"shasum": "1.0.2",
"source-map-support": "0.5.19",
"spectron-fake-dialog": "0.0.1",
"tail": "2.2.4",
"tcp-port-used": "1.0.1",
"trezor-connect": "8.2.4-extended",
"unorm": "1.6.0",
Expand Down
2 changes: 1 addition & 1 deletion source/main/utils/handleCheckBlockReplayProgress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BrowserWindow } from 'electron';
import fs from 'fs';
import moment from 'moment';
import path from 'path';
import { Tail } from 'tail';
import { Tail } from './tail';
import { getBlockSyncProgressChannel } from '../ipc/get-block-sync-progress';
import type { GetBlockSyncProgressType } from '../../common/ipc/api';
import { BlockSyncType } from '../../common/types/cardano-node.types';
Expand Down
183 changes: 183 additions & 0 deletions source/main/utils/tail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import events from 'events';
import fs from 'fs';
import path from 'path';
import { logger as defaultLogger } from './logging';
import type { Logger } from '../../common/types/logging.types';

const ENCODING = 'utf-8';

export class Tail extends events.EventEmitter {
filename: string;
buffer: string;
internalDispatcher: events.EventEmitter;
queue: { start: number; end: number }[];
isWatching: boolean;
currentCursorPos: number;
watcher: fs.FSWatcher;
rewatchId: NodeJS.Timeout;
logger: Logger;

constructor(filename: string, logger: Logger = defaultLogger) {
super();
this.filename = filename;
this.logger = logger;

this.logger.info(`Tail starting...`);
this.logger.info(`filename: ${this.filename}`);

try {
fs.accessSync(this.filename, fs.constants.F_OK);
} catch (err) {
if (err.code === 'ENOENT') {
throw err;
}
}

this.buffer = '';
this.internalDispatcher = new events.EventEmitter();
this.queue = [];
this.isWatching = false;

this.internalDispatcher.on('next', () => {
this.readBlock();
});

try {
this.watch(this.latestPosition());
} catch (err) {
this.logger.error(`watch for ${this.filename} failed: ${err}`);
this.emit('error', `watch for ${this.filename} failed: ${err}`);
}
}

latestPosition() {
try {
return fs.statSync(this.filename).size;
} catch (err) {
this.logger.error(`size check for ${this.filename} failed: ${err}`);
this.emit('error', `size check for ${this.filename} failed: ${err}`);
throw err;
}
}

readBlock() {
if (this.queue.length >= 1) {
const block = this.queue[0];
if (block.end > block.start) {
const stream = fs.createReadStream(this.filename, {
start: block.start,
end: block.end - 1,
encoding: ENCODING,
});
stream.on('error', (error) => {
this.logger.error(`Tail error: ${error}`);
this.emit('error', error);
});
stream.on('end', () => {
this.queue.shift();
if (this.queue.length > 0) {
this.internalDispatcher.emit('next');
}
});
stream.on('data', (d) => {
this.buffer += d;
const parts = this.buffer.split(/[\r]{0,1}\n/);
this.buffer = parts.pop();
for (const chunk of parts) {
this.emit('line', chunk);
}
});
}
}
}

change() {
const p = this.latestPosition();
if (p < this.currentCursorPos) {
this.currentCursorPos = p;
} else if (p > this.currentCursorPos) {
this.queue.push({ start: this.currentCursorPos, end: p });
this.currentCursorPos = p;
if (this.queue.length === 1) {
this.internalDispatcher.emit('next');
}
}
}

watch(startingCursor) {
if (this.isWatching) return;
this.logger.info(`filesystem.watch present? ${fs.watch !== undefined}`);

this.isWatching = true;
this.currentCursorPos = startingCursor;

if (fs.watch) {
this.logger.info(`watch strategy: watch`);
this.watcher = fs.watch(this.filename, {}, (e, filename) => {
this.watchEvent(e, filename);
});
} else {
this.logger.info(`watch strategy: watchFile`);
fs.watchFile(this.filename, {}, (curr, prev) => {
this.watchFileEvent(curr, prev);
});
}
}

rename(filename) {
if (filename === undefined || filename !== this.filename) {
this.unwatch();
this.filename = path.join(path.dirname(this.filename), filename);
this.rewatchId = setTimeout(() => {
try {
this.watch(this.currentCursorPos);
} catch (ex) {
this.logger.error(
`'rename' event for ${this.filename}. File not available anymore.`
);
this.emit('error', ex);
}
}, 1000);
} else {
this.logger.info('rename event but same filename');
}
}

watchEvent(e, evtFilename) {
try {
if (e === 'change') {
this.change();
} else if (e === 'rename') {
this.rename(evtFilename);
}
} catch (err) {
this.logger.error(`watchEvent for ${this.filename} failed: ${err}`);
this.emit('error', `watchEvent for ${this.filename} failed: ${err}`);
}
}

watchFileEvent(curr, prev) {
if (curr.size > prev.size) {
this.currentCursorPos = curr.size;
this.queue.push({ start: prev.size, end: curr.size });
if (this.queue.length === 1) {
this.internalDispatcher.emit('next');
}
}
}

unwatch() {
if (this.watcher) {
this.watcher.close();
} else {
fs.unwatchFile(this.filename);
}
if (this.rewatchId) {
clearTimeout(this.rewatchId);
this.rewatchId = undefined;
}
this.isWatching = false;
this.queue = [];
this.logger.info(`Unwatch ${this.filename}`);
}
}
4 changes: 0 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16456,10 +16456,6 @@ table@^6.0.1:
slice-ansi "^4.0.0"
string-width "^4.2.0"

[email protected]:
version "2.2.4"
resolved "https://registry.yarnpkg.com/tail/-/tail-2.2.4.tgz#90dd4c5a174a3fa39dcb65a1df1950a4a0093a41"

tapable@^0.1.8:
version "0.1.10"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
Expand Down

0 comments on commit c186797

Please sign in to comment.