|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
# @push.rocks/smartnetwork
|
|
|
|
|
|
|
|
|
|
network diagnostics
|
|
|
|
|
Comprehensive network diagnostics and utilities for Node.js applications
|
|
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
|
|
|
@@ -10,20 +10,9 @@ To install `@push.rocks/smartnetwork`, run the following command in your termina
|
|
|
|
|
npm install @push.rocks/smartnetwork --save
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Performing a Traceroute
|
|
|
|
|
|
|
|
|
|
You can perform a hop-by-hop traceroute to measure latency per hop. Falls back to a single-hop stub if the `traceroute` binary is unavailable.
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const hops = await myNetwork.traceroute('google.com', { maxHops: 10, timeout: 5000 });
|
|
|
|
|
hops.forEach((h) => console.log(`${h.ttl}\t${h.ip}\t${h.rtt === null ? '*' : h.rtt + ' ms'}`));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This command will download `@push.rocks/smartnetwork` and add it to your project's `package.json` file.
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
In this section, we will dive deep into the capabilities of the `@push.rocks/smartnetwork` package, exploring its various features through TypeScript examples. The package is designed to simplify network diagnostics tasks, including speed tests, port availability checks, ping operations, and more.
|
|
|
|
|
The `@push.rocks/smartnetwork` package provides a comprehensive suite of network diagnostic tools including speed tests, port availability checks, ping operations, DNS resolution, HTTP endpoint health checks, and more.
|
|
|
|
|
|
|
|
|
|
### Basic Setup
|
|
|
|
|
|
|
|
|
@@ -37,135 +26,294 @@ Then, create an instance of `SmartNetwork`:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const myNetwork = new SmartNetwork();
|
|
|
|
|
|
|
|
|
|
// Or with caching enabled (60 seconds TTL)
|
|
|
|
|
const myNetworkCached = new SmartNetwork({ cacheTtl: 60000 });
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Performing a Speed Test
|
|
|
|
|
### Network Speed Testing
|
|
|
|
|
|
|
|
|
|
You can measure the network speed using the `getSpeed` method. It supports optional parameters:
|
|
|
|
|
|
|
|
|
|
- `parallelStreams`: number of concurrent streams (default: 1)
|
|
|
|
|
- `duration`: test duration in seconds (default: fixed segments)
|
|
|
|
|
Measure network download and upload speeds using Cloudflare's speed test infrastructure:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const speedTest = async () => {
|
|
|
|
|
// Default fixed-segment test
|
|
|
|
|
let r = await myNetwork.getSpeed();
|
|
|
|
|
console.log(`Download: ${r.downloadSpeed} Mbps, Upload: ${r.uploadSpeed} Mbps`);
|
|
|
|
|
// Basic speed test
|
|
|
|
|
const result = await myNetwork.getSpeed();
|
|
|
|
|
console.log(`Download: ${result.downloadSpeed} Mbps`);
|
|
|
|
|
console.log(`Upload: ${result.uploadSpeed} Mbps`);
|
|
|
|
|
|
|
|
|
|
// Parallel + duration-based test
|
|
|
|
|
r = await myNetwork.getSpeed({ parallelStreams: 3, duration: 5 });
|
|
|
|
|
console.log(`Download: ${r.downloadSpeed} Mbps, Upload: ${r.uploadSpeed} Mbps`);
|
|
|
|
|
// Advanced speed test with options
|
|
|
|
|
const advancedResult = await myNetwork.getSpeed({
|
|
|
|
|
parallelStreams: 3, // Number of concurrent connections
|
|
|
|
|
duration: 5 // Test duration in seconds
|
|
|
|
|
});
|
|
|
|
|
console.log(`Download: ${advancedResult.downloadSpeed} Mbps`);
|
|
|
|
|
console.log(`Upload: ${advancedResult.uploadSpeed} Mbps`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
speedTest();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Checking Port Availability Locally
|
|
|
|
|
### Port Management
|
|
|
|
|
|
|
|
|
|
The `isLocalPortUnused` method allows you to check if a specific port on your local machine is available for use.
|
|
|
|
|
#### Check Local Port Availability
|
|
|
|
|
|
|
|
|
|
Verify if a specific port is available on your local machine (checks both IPv4 and IPv6):
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const checkLocalPort = async (port: number) => {
|
|
|
|
|
const isUnused = await myNetwork.isLocalPortUnused(port);
|
|
|
|
|
if (isUnused) {
|
|
|
|
|
console.log(`Port ${port} is available.`);
|
|
|
|
|
console.log(`Port ${port} is available`);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`Port ${port} is in use.`);
|
|
|
|
|
console.log(`Port ${port} is in use`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
checkLocalPort(8080); // Example port number
|
|
|
|
|
await checkLocalPort(8080);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Checking Remote Port Availability
|
|
|
|
|
#### Find Free Port in Range
|
|
|
|
|
|
|
|
|
|
To verify if a port is available on a remote server, use `isRemotePortAvailable`. You can specify target as `"host:port"` or host plus a numeric port.
|
|
|
|
|
Automatically find the first available port within a specified range:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Using "host:port"
|
|
|
|
|
await myNetwork.isRemotePortAvailable('example.com:443');
|
|
|
|
|
const findFreePort = async () => {
|
|
|
|
|
// Find a free port between 3000 and 3100
|
|
|
|
|
const freePort = await myNetwork.findFreePort(3000, 3100);
|
|
|
|
|
|
|
|
|
|
if (freePort) {
|
|
|
|
|
console.log(`Found free port: ${freePort}`);
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No free ports available in the specified range');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
// Using host + port
|
|
|
|
|
await myNetwork.isRemotePortAvailable('example.com', 443);
|
|
|
|
|
#### Check Remote Port Availability
|
|
|
|
|
|
|
|
|
|
// UDP is not supported:
|
|
|
|
|
Verify if a port is open on a remote server:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Method 1: Using "host:port" syntax
|
|
|
|
|
const isOpen1 = await myNetwork.isRemotePortAvailable('example.com:443');
|
|
|
|
|
|
|
|
|
|
// Method 2: Using separate host and port
|
|
|
|
|
const isOpen2 = await myNetwork.isRemotePortAvailable('example.com', 443);
|
|
|
|
|
|
|
|
|
|
// Method 3: With options (retries, timeout)
|
|
|
|
|
const isOpen3 = await myNetwork.isRemotePortAvailable('example.com', {
|
|
|
|
|
port: 443,
|
|
|
|
|
protocol: 'tcp', // Only TCP is supported
|
|
|
|
|
retries: 3, // Number of connection attempts
|
|
|
|
|
timeout: 5000 // Timeout per attempt in ms
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Note: UDP is not supported and will throw an error
|
|
|
|
|
try {
|
|
|
|
|
await myNetwork.isRemotePortAvailable('example.com', { port: 53, protocol: 'udp' });
|
|
|
|
|
await myNetwork.isRemotePortAvailable('example.com', {
|
|
|
|
|
port: 53,
|
|
|
|
|
protocol: 'udp'
|
|
|
|
|
});
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error((e as any).code); // ENOTSUP
|
|
|
|
|
console.error(e.code); // ENOTSUP
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Using Ping
|
|
|
|
|
### Network Connectivity
|
|
|
|
|
|
|
|
|
|
The `ping` method sends ICMP echo requests and optionally repeats them to collect statistics.
|
|
|
|
|
#### Ping Operations
|
|
|
|
|
|
|
|
|
|
Send ICMP echo requests to test connectivity and measure latency:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Single ping
|
|
|
|
|
const p1 = await myNetwork.ping('google.com');
|
|
|
|
|
console.log(`Alive: ${p1.alive}, RTT: ${p1.time} ms`);
|
|
|
|
|
// Simple ping
|
|
|
|
|
const pingResult = await myNetwork.ping('google.com');
|
|
|
|
|
console.log(`Host alive: ${pingResult.alive}`);
|
|
|
|
|
console.log(`RTT: ${pingResult.time} ms`);
|
|
|
|
|
|
|
|
|
|
// Multiple pings with statistics
|
|
|
|
|
const stats = await myNetwork.ping('google.com', { count: 5 });
|
|
|
|
|
console.log(
|
|
|
|
|
`min=${stats.min} ms, max=${stats.max} ms, avg=${stats.avg.toFixed(2)} ms, loss=${stats.packetLoss}%`,
|
|
|
|
|
);
|
|
|
|
|
// Ping with statistics (multiple pings)
|
|
|
|
|
const pingStats = await myNetwork.ping('google.com', {
|
|
|
|
|
count: 5, // Number of pings
|
|
|
|
|
timeout: 1000 // Timeout per ping in ms
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log(`Packet loss: ${pingStats.packetLoss}%`);
|
|
|
|
|
console.log(`Min: ${pingStats.min} ms`);
|
|
|
|
|
console.log(`Max: ${pingStats.max} ms`);
|
|
|
|
|
console.log(`Avg: ${pingStats.avg.toFixed(2)} ms`);
|
|
|
|
|
console.log(`Stddev: ${pingStats.stddev.toFixed(2)} ms`);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Getting Network Gateways
|
|
|
|
|
#### Traceroute
|
|
|
|
|
|
|
|
|
|
You can also retrieve network interfaces (gateways) and determine the default gateway. Caching with TTL is supported via constructor options.
|
|
|
|
|
Perform hop-by-hop network path analysis:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Create with cache TTL of 60 seconds
|
|
|
|
|
const netCached = new SmartNetwork({ cacheTtl: 60000 });
|
|
|
|
|
const hops = await myNetwork.traceroute('google.com', {
|
|
|
|
|
maxHops: 10, // Maximum number of hops
|
|
|
|
|
timeout: 5000 // Timeout in ms
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// List all interfaces
|
|
|
|
|
const gateways = await netCached.getGateways();
|
|
|
|
|
console.log(gateways);
|
|
|
|
|
|
|
|
|
|
// Get default gateway
|
|
|
|
|
const defaultGw = await netCached.getDefaultGateway();
|
|
|
|
|
console.log(defaultGw);
|
|
|
|
|
hops.forEach(hop => {
|
|
|
|
|
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
|
|
|
|
console.log(`${hop.ttl}\t${hop.ip}\t${rtt}`);
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Discovering Public IP Addresses
|
|
|
|
|
Note: Falls back to a single-hop stub if the `traceroute` binary is unavailable on the system.
|
|
|
|
|
|
|
|
|
|
To find out your public IPv4 and IPv6 addresses (with caching):
|
|
|
|
|
### DNS Operations
|
|
|
|
|
|
|
|
|
|
Resolve DNS records for a hostname:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const publicIps = await netCached.getPublicIps();
|
|
|
|
|
console.log(`Public IPv4: ${publicIps.v4}`);
|
|
|
|
|
console.log(`Public IPv6: ${publicIps.v6}`);
|
|
|
|
|
const dnsRecords = await myNetwork.resolveDns('example.com');
|
|
|
|
|
|
|
|
|
|
console.log('A records:', dnsRecords.A); // IPv4 addresses
|
|
|
|
|
console.log('AAAA records:', dnsRecords.AAAA); // IPv6 addresses
|
|
|
|
|
console.log('MX records:', dnsRecords.MX); // Mail servers
|
|
|
|
|
|
|
|
|
|
// MX records include priority
|
|
|
|
|
dnsRecords.MX.forEach(mx => {
|
|
|
|
|
console.log(`Mail server: ${mx.exchange} (priority: ${mx.priority})`);
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `@push.rocks/smartnetwork` package provides an easy-to-use, comprehensive suite of tools for network diagnostics and monitoring, encapsulating complex network operations into simple asynchronous methods. By leveraging TypeScript, developers can benefit from type checking, ensuring that they can work with clear structures and expectations.
|
|
|
|
|
### HTTP/HTTPS Endpoint Health Checks
|
|
|
|
|
|
|
|
|
|
These examples offer a glimpse into the module's utility in real-world scenarios, demonstrating its versatility in handling common network tasks. Whether you're developing a network-sensitive application, diagnosing connectivity issues, or simply curious about your network performance, `@push.rocks/smartnetwork` equips you with the tools you need.
|
|
|
|
|
Check the health and response time of HTTP/HTTPS endpoints:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const health = await myNetwork.checkEndpoint('https://example.com', {
|
|
|
|
|
timeout: 5000 // Request timeout in ms
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log(`Status: ${health.status}`);
|
|
|
|
|
console.log(`RTT: ${health.rtt} ms`);
|
|
|
|
|
console.log('Headers:', health.headers);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Network Interface Information
|
|
|
|
|
|
|
|
|
|
#### Get Network Gateways
|
|
|
|
|
|
|
|
|
|
List all network interfaces on the system:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const gateways = await myNetwork.getGateways();
|
|
|
|
|
|
|
|
|
|
Object.entries(gateways).forEach(([name, interfaces]) => {
|
|
|
|
|
console.log(`Interface: ${name}`);
|
|
|
|
|
interfaces.forEach(iface => {
|
|
|
|
|
console.log(` ${iface.family}: ${iface.address}`);
|
|
|
|
|
console.log(` Netmask: ${iface.netmask}`);
|
|
|
|
|
console.log(` MAC: ${iface.mac}`);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### Get Default Gateway
|
|
|
|
|
|
|
|
|
|
Retrieve the system's default network gateway:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const defaultGateway = await myNetwork.getDefaultGateway();
|
|
|
|
|
|
|
|
|
|
if (defaultGateway) {
|
|
|
|
|
console.log('IPv4 Gateway:', defaultGateway.ipv4.address);
|
|
|
|
|
console.log('IPv6 Gateway:', defaultGateway.ipv6.address);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Public IP Discovery
|
|
|
|
|
|
|
|
|
|
Discover your public IPv4 and IPv6 addresses:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
const publicIps = await myNetwork.getPublicIps();
|
|
|
|
|
|
|
|
|
|
console.log(`Public IPv4: ${publicIps.v4 || 'Not available'}`);
|
|
|
|
|
console.log(`Public IPv6: ${publicIps.v6 || 'Not available'}`);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Caching
|
|
|
|
|
|
|
|
|
|
SmartNetwork supports caching for gateway and public IP lookups to reduce repeated network calls:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Create instance with 60-second cache TTL
|
|
|
|
|
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
|
|
|
|
|
|
|
|
// These calls will use cached results if called within 60 seconds
|
|
|
|
|
const gateways1 = await cachedNetwork.getGateways();
|
|
|
|
|
const publicIps1 = await cachedNetwork.getPublicIps();
|
|
|
|
|
|
|
|
|
|
// Subsequent calls within TTL return cached results
|
|
|
|
|
const gateways2 = await cachedNetwork.getGateways(); // From cache
|
|
|
|
|
const publicIps2 = await cachedNetwork.getPublicIps(); // From cache
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Plugin Architecture
|
|
|
|
|
|
|
|
|
|
You can extend `SmartNetwork` with custom plugins by registering them at runtime:
|
|
|
|
|
Extend SmartNetwork's functionality with custom plugins:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
|
|
|
|
|
|
|
|
|
// Define your plugin class or constructor
|
|
|
|
|
class MyCustomPlugin {
|
|
|
|
|
// plugin implementation goes here
|
|
|
|
|
// Define your plugin
|
|
|
|
|
class CustomNetworkPlugin {
|
|
|
|
|
constructor(private smartNetwork: SmartNetwork) {}
|
|
|
|
|
|
|
|
|
|
async customMethod() {
|
|
|
|
|
// Your custom network functionality
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Register and unregister your plugin by name
|
|
|
|
|
SmartNetwork.registerPlugin('myPlugin', MyCustomPlugin);
|
|
|
|
|
// Later, remove it if no longer needed
|
|
|
|
|
SmartNetwork.unregisterPlugin('myPlugin');
|
|
|
|
|
// Register the plugin
|
|
|
|
|
SmartNetwork.registerPlugin('customPlugin', CustomNetworkPlugin);
|
|
|
|
|
|
|
|
|
|
// Use the plugin
|
|
|
|
|
const network = new SmartNetwork();
|
|
|
|
|
const plugin = new (SmartNetwork.pluginsRegistry.get('customPlugin'))(network);
|
|
|
|
|
await plugin.customMethod();
|
|
|
|
|
|
|
|
|
|
// Unregister when no longer needed
|
|
|
|
|
SmartNetwork.unregisterPlugin('customPlugin');
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Plugins enable you to dynamically augment the core functionality without altering the library's source.
|
|
|
|
|
### Error Handling
|
|
|
|
|
|
|
|
|
|
The package uses custom `NetworkError` class for network-related errors:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { NetworkError } from '@push.rocks/smartnetwork';
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await myNetwork.isRemotePortAvailable('example.com', { protocol: 'udp' });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error instanceof NetworkError) {
|
|
|
|
|
console.error(`Network error: ${error.message}`);
|
|
|
|
|
console.error(`Error code: ${error.code}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### TypeScript Support
|
|
|
|
|
|
|
|
|
|
This package is written in TypeScript and provides full type definitions. Key interfaces include:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
interface SmartNetworkOptions {
|
|
|
|
|
cacheTtl?: number; // Cache TTL in milliseconds
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Hop {
|
|
|
|
|
ttl: number; // Time to live
|
|
|
|
|
ip: string; // IP address of the hop
|
|
|
|
|
rtt: number | null; // Round trip time in ms
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## License and Legal Information
|
|
|
|
|
|
|
|
|
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
|
|
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
|
|
|
|
|
|
|
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
|
|
|
|
|
|
|
@@ -180,4 +328,4 @@ Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
|
|
|
|
|
|
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
|
|
|
|
|
|
|
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
|
|
|
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|