traffic-lens
Version:
A network traffic monitoring tool with proxy awareness for Node.js
253 lines (252 loc) • 8.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const si = require("systeminformation");
/**
* TrafficLens - A network traffic monitoring tool with proxy awareness
* @class
*/
class TrafficLens {
/**
* Creates a new TrafficLens instance
* @param {Config} config - Configuration options
* @throws {Error} If update interval is less than 3 seconds
* @example
* ```typescript
* const monitor = new TrafficLens({
* proxyPort: 1080,
* updateInterval: 5000
* });
* ```
*/
constructor(config) {
this.lastStats = null;
this.totalStats = {
proxied: {
upload: 0,
download: 0,
uploadSpeed: 0,
downloadSpeed: 0,
activeConnections: 0,
},
direct: {
upload: 0,
download: 0,
uploadSpeed: 0,
downloadSpeed: 0,
},
timestamp: Date.now(),
};
this.intervalId = null;
this.callbacks = [];
if (config.updateInterval && config.updateInterval < 3000) {
throw new Error("Update interval must be greater than 3 seconds");
}
this.config = {
updateInterval: config.updateInterval || 5000,
...config,
};
}
/**
* Get the current network stats
* @returns NetworkStats | null
*/
async getCurrentStats() {
try {
const networkStats = await si.networkStats();
const mainInterface = networkStats.find((stat) => stat.operstate === "up" && stat.rx_bytes > 0);
if (!mainInterface)
return null;
return {
uploadSpeed: mainInterface.tx_sec || 0,
downloadSpeed: mainInterface.rx_sec || 0,
upload: mainInterface.tx_bytes || 0,
download: mainInterface.rx_bytes || 0,
timestamp: Date.now(),
};
}
catch (error) {
console.error("Error getting network stats:", error);
return null;
}
}
/**
* Get the current proxy connections
* @returns ProxyConnections
*/
async checkProxyConnections() {
try {
const netConnections = await si.networkConnections();
const networkStats = await si.networkStats();
const proxyConnections = netConnections.filter((conn) => conn.localPort === this.config.proxyPort.toString());
const proxyInterface = networkStats.find((stat) => {
return proxyConnections.some((conn) => conn.localAddress.includes(stat.iface));
});
return {
activeConnections: proxyConnections.length,
stats: proxyInterface
? {
upload: proxyInterface.tx_bytes,
download: proxyInterface.rx_bytes,
uploadSpeed: proxyInterface.tx_sec,
downloadSpeed: proxyInterface.rx_sec,
}
: null,
};
}
catch (error) {
console.error("Error checking proxy connections:", error);
return {
activeConnections: 0,
stats: null,
};
}
}
/**
* Starts monitoring network traffic
* @returns {Promise<void>}
* @throws {Error} If monitor is already running
* @example
* ```typescript
* await monitor.start();
* ```
*/
async start() {
if (this.intervalId) {
throw new Error("Monitor is already running");
}
this.intervalId = setInterval(async () => {
var _a, _b, _c, _d;
const currentStats = await this.getCurrentStats();
const proxyResults = await this.checkProxyConnections();
if (!currentStats)
return;
if (this.lastStats) {
this.totalStats.timestamp = Date.now();
this.totalStats.proxied.activeConnections = proxyResults.activeConnections;
if (proxyResults.stats) {
this.totalStats.proxied = {
...proxyResults.stats,
activeConnections: proxyResults.activeConnections,
};
}
this.totalStats.direct = {
upload: currentStats.upload - (((_a = proxyResults.stats) === null || _a === void 0 ? void 0 : _a.upload) || 0),
download: currentStats.download - (((_b = proxyResults.stats) === null || _b === void 0 ? void 0 : _b.download) || 0),
uploadSpeed: currentStats.uploadSpeed - (((_c = proxyResults.stats) === null || _c === void 0 ? void 0 : _c.uploadSpeed) || 0),
downloadSpeed: currentStats.downloadSpeed - (((_d = proxyResults.stats) === null || _d === void 0 ? void 0 : _d.downloadSpeed) || 0),
};
this.callbacks.forEach((callback) => callback(this.totalStats));
}
this.lastStats = currentStats;
}, this.config.updateInterval);
}
/**
* Stops monitoring network traffic
* @example
* ```typescript
* monitor.stop();
* ```
*/
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
/**
* Subscribes to traffic updates
* @param {MonitorCallback} callback - Function to be called with traffic updates
* @returns {Function} Unsubscribe function
* @example
* ```typescript
* const unsubscribe = monitor.subscribe((stats) => {
* console.log('Upload speed:', stats.proxied.uploadSpeed);
* });
*
* // Later, to unsubscribe:
* unsubscribe();
* ```
*/
subscribe(callback) {
this.callbacks.push(callback);
return () => {
this.callbacks = this.callbacks.filter((cb) => cb !== callback);
};
}
/**
* Gets the current traffic statistics
* @returns {TrafficStats} Current traffic statistics
* @example
* ```typescript
* const stats = monitor.getTrafficStats();
* console.log('Active proxy connections:', stats.proxied.activeConnections);
* ```
*/
getTrafficStats() {
return this.totalStats;
}
/**
* Gets current speeds for proxied connections
* @returns {SpeedMetrics} Current proxy connection speeds
* @example
* ```typescript
* const speeds = monitor.getProxySpeed();
* console.log('Proxy upload speed:', TrafficLens.formatSpeed(speeds.uploadSpeed));
* ```
*/
getProxySpeed() {
return {
uploadSpeed: this.totalStats.proxied.uploadSpeed,
downloadSpeed: this.totalStats.proxied.downloadSpeed,
};
}
/**
* Gets current speeds for direct connections
* @returns {SpeedMetrics} Current direct connection speeds
* @example
* ```typescript
* const speeds = monitor.getDirectSpeed();
* console.log('Direct download speed:', TrafficLens.formatSpeed(speeds.downloadSpeed));
* ```
*/
getDirectSpeed() {
return {
uploadSpeed: this.totalStats.direct.uploadSpeed,
downloadSpeed: this.totalStats.direct.downloadSpeed,
};
}
/**
* Formats traffic bytes to a human readable string
* @param {number} bytes - Number of bytes to format
* @returns {string} Formatted string with appropriate unit
* @example
* ```typescript
* TrafficLens.formatBytes(1024); // "1.00 KB"
* TrafficLens.formatBytes(1048576); // "1.00 MB"
* ```
*/
static formatBytes(bytes) {
const units = ["B", "KB", "MB", "GB"];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
/**
* Formats speed to a human readable string (bytes per second)
* @param {number} bytesPerSec - Speed in bytes per second
* @returns {string} Formatted string with appropriate unit per second
* @example
* ```typescript
* TrafficLens.formatSpeed(1024); // "1.00 KB/s"
* TrafficLens.formatSpeed(1048576); // "1.00 MB/s"
* ```
*/
static formatSpeed(bytesPerSec) {
return `${TrafficLens.formatBytes(bytesPerSec)}/s`;
}
}
exports.default = TrafficLens;