src/process.ts
import events from 'events';
import readline from 'readline';
import validator from 'validator';
import { spawn } from 'child_process';
export interface Hop {
hop: number;
ip: string;
rtt1: string;
rtt2?: string;
rtt3?: string;
}
export abstract class Process extends events.EventEmitter {
constructor(private command: string, private args: string[]) {
super();
}
public trace(domainName: string): void {
if (!this.isValidDomainName(domainName)) {
throw "Invalid domain name or IP address";
}
this.args.push(domainName);
const process = spawn(this.command, this.args);
process.on('close', (code) => {
this.emit('close', code);
});
this.emit('pid', process.pid);
let isDestinationCaptured = false;
if (process.pid) {
readline.createInterface({
input: process.stdout,
terminal: false
})
.on('line', (line) => {
if (!isDestinationCaptured) {
const destination = this.parseDestination(line);
if (destination !== null) {
this.emit('destination', destination);
isDestinationCaptured = true;
}
}
const hop = this.parseHop(line);
if (hop !== null) {
this.emit('hop', hop);
}
});
}
}
private isValidDomainName(domainName: string): boolean {
return validator.isFQDN(domainName + '') || validator.isIP(domainName + '');
}
abstract parseDestination(data: string): string | null;
abstract parseHop(hopData: string): Hop | null;
}