UNPKG

traffic-lens

Version:

A network traffic monitoring tool with proxy awareness for Node.js

253 lines (252 loc) 8.71 kB
"use strict"; 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;