@push.rocks/smartnetwork 4.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{npmextra.json → .smartconfig.json} +17 -5
- package/dist_rust/rustnetwork_linux_amd64 +0 -0
- package/dist_rust/rustnetwork_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/helpers/stats.js +1 -1
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/smartnetwork.classes.cloudflarespeed.js +32 -11
- package/dist_ts/smartnetwork.classes.ipintelligence.d.ts +101 -0
- package/dist_ts/smartnetwork.classes.ipintelligence.js +442 -0
- package/dist_ts/smartnetwork.classes.publicip.js +1 -1
- package/dist_ts/smartnetwork.classes.rustbridge.d.ts +100 -0
- package/dist_ts/smartnetwork.classes.rustbridge.js +98 -0
- package/dist_ts/smartnetwork.classes.smartnetwork.d.ts +40 -32
- package/dist_ts/smartnetwork.classes.smartnetwork.js +132 -152
- package/dist_ts/smartnetwork.plugins.d.ts +7 -10
- package/dist_ts/smartnetwork.plugins.js +9 -13
- package/package.json +19 -18
- package/readme.hints.md +60 -34
- package/readme.md +22 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/helpers/stats.ts +1 -1
- package/ts/index.ts +3 -0
- package/ts/smartnetwork.classes.cloudflarespeed.ts +32 -16
- package/ts/smartnetwork.classes.ipintelligence.ts +542 -0
- package/ts/smartnetwork.classes.publicip.ts +2 -2
- package/ts/smartnetwork.classes.rustbridge.ts +181 -0
- package/ts/smartnetwork.classes.smartnetwork.ts +156 -164
- package/ts/smartnetwork.plugins.ts +8 -12
package/readme.hints.md
CHANGED
|
@@ -1,73 +1,99 @@
|
|
|
1
1
|
# Project Analysis
|
|
2
2
|
|
|
3
3
|
## Architecture Overview
|
|
4
|
-
This is a comprehensive network diagnostics toolkit
|
|
4
|
+
This is a comprehensive network diagnostics toolkit. The main entry point is the `SmartNetwork` class which orchestrates all functionality. System-dependent operations are delegated to a Rust binary via JSON-over-stdin/stdout IPC using `@push.rocks/smartrust`.
|
|
5
5
|
|
|
6
6
|
Key features:
|
|
7
|
-
- Speed testing via Cloudflare (parallelizable with duration support)
|
|
8
|
-
-
|
|
9
|
-
- Port availability checks (local and remote)
|
|
10
|
-
- Network gateway discovery
|
|
11
|
-
- Public IP retrieval
|
|
12
|
-
- DNS resolution
|
|
13
|
-
- HTTP endpoint health checks
|
|
14
|
-
- Traceroute
|
|
7
|
+
- Speed testing via Cloudflare (parallelizable with duration support) — pure TS
|
|
8
|
+
- ICMP ping with statistics — Rust binary (surge-ping)
|
|
9
|
+
- Port availability checks (local and remote) — Rust binary (tokio TCP / socket2)
|
|
10
|
+
- Network gateway discovery — Rust binary (parses /proc/net/route on Linux)
|
|
11
|
+
- Public IP retrieval — pure TS
|
|
12
|
+
- DNS resolution via smartdns — pure TS
|
|
13
|
+
- HTTP endpoint health checks — pure TS
|
|
14
|
+
- Traceroute — Rust binary (raw ICMP sockets via socket2)
|
|
15
|
+
|
|
16
|
+
## Rust Binary Architecture (v4.5.0+)
|
|
17
|
+
|
|
18
|
+
### Binary: `rustnetwork`
|
|
19
|
+
- Located in `rust/crates/rustnetwork/`
|
|
20
|
+
- Cross-compiled for linux_amd64 and linux_arm64 via `@git.zone/tsrust`
|
|
21
|
+
- Output: `dist_rust/rustnetwork_linux_amd64`, `dist_rust/rustnetwork_linux_arm64`
|
|
22
|
+
- IPC mode: `--management` flag for JSON-over-stdin/stdout
|
|
23
|
+
|
|
24
|
+
### IPC Commands
|
|
25
|
+
| Method | Description |
|
|
26
|
+
|--------|-------------|
|
|
27
|
+
| `healthPing` | Liveness check (returns `{ pong: true }`) |
|
|
28
|
+
| `ping` | ICMP ping with count/timeout, returns stats |
|
|
29
|
+
| `traceroute` | Hop-by-hop latency via raw ICMP sockets |
|
|
30
|
+
| `tcpPortCheck` | TCP connect probe to remote host:port |
|
|
31
|
+
| `isLocalPortFree` | Bind test on IPv4 + IPv6 |
|
|
32
|
+
| `defaultGateway` | Parse /proc/net/route for default interface |
|
|
33
|
+
|
|
34
|
+
### TypeScript Bridge
|
|
35
|
+
- `ts/smartnetwork.classes.rustbridge.ts` — Singleton `RustNetworkBridge` wrapping `smartrust.RustBridge`
|
|
36
|
+
- `SmartNetwork` class has `start()`/`stop()` lifecycle for the bridge
|
|
37
|
+
- `ensureBridge()` auto-starts on first use
|
|
38
|
+
|
|
39
|
+
### Build Pipeline
|
|
40
|
+
- `pnpm build` = `tsbuild tsfolders --allowimplicitany && tsrust`
|
|
41
|
+
- Targets configured in `.smartconfig.json` under `@git.zone/tsrust`
|
|
15
42
|
|
|
16
43
|
## Key Components
|
|
17
44
|
|
|
18
45
|
### SmartNetwork Class
|
|
19
46
|
- Central orchestrator for all network operations
|
|
47
|
+
- Requires `start()` before using ping/traceroute/port/gateway operations
|
|
20
48
|
- Supports caching via `cacheTtl` option for gateway and public IP lookups
|
|
21
49
|
- Plugin architecture for extensibility
|
|
22
50
|
|
|
51
|
+
### RustNetworkBridge Class
|
|
52
|
+
- Singleton pattern via `getInstance()`
|
|
53
|
+
- Binary search: dist_rust/ (platform-suffixed) > rust/target/release/ > rust/target/debug/
|
|
54
|
+
- `searchSystemPath: false` — only looks in local paths
|
|
55
|
+
|
|
23
56
|
### CloudflareSpeed Class
|
|
24
57
|
- Handles internet speed testing using Cloudflare's infrastructure
|
|
25
58
|
- Supports parallel streams and customizable test duration
|
|
26
|
-
-
|
|
27
|
-
- Includes latency measurements (jitter, median, average)
|
|
59
|
+
- Upload speed measurement uses server-timing header with client-side timing fallback
|
|
28
60
|
|
|
29
61
|
### Error Handling
|
|
30
62
|
- Custom `NetworkError` and `TimeoutError` classes for better error context
|
|
31
63
|
- Error codes follow Node.js conventions (ENOTSUP, EINVAL, ETIMEOUT)
|
|
64
|
+
- Ping/port methods gracefully degrade on errors (return alive=false / false)
|
|
32
65
|
|
|
33
66
|
### Logging
|
|
34
67
|
- Global logger interface for consistent logging across the codebase
|
|
35
68
|
- Replaceable logger implementation (defaults to console)
|
|
36
|
-
- Used primarily for error reporting in speed tests
|
|
37
69
|
|
|
38
70
|
### Statistics Helpers
|
|
39
71
|
- Utility functions for statistical calculations (average, median, quartile, jitter)
|
|
40
|
-
- Used
|
|
72
|
+
- Used by speed testing; ping statistics now computed server-side in Rust
|
|
41
73
|
|
|
42
|
-
##
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
- Added global logging interface
|
|
47
|
-
- Improved connection management by disabling HTTP connection pooling
|
|
48
|
-
- Fixed memory leaks from listener accumulation
|
|
49
|
-
- Minor formatting fixes for consistency
|
|
74
|
+
## Dependencies
|
|
75
|
+
- **Runtime**: `@push.rocks/smartrust` (IPC bridge), `@push.rocks/smartdns` (DNS resolution)
|
|
76
|
+
- **Removed in v4.5.0**: `@push.rocks/smartping`, `@push.rocks/smartstring`, `isopen`, `systeminformation`
|
|
77
|
+
- **Dev**: `@git.zone/tsrust` (Rust cross-compilation)
|
|
50
78
|
|
|
51
79
|
## Testing
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
80
|
+
- `test/test.ts` — Core smoke tests (speed, ports, gateways, public IPs)
|
|
81
|
+
- `test/test.ping.ts` — ICMP ping tests (requires CAP_NET_RAW for alive=true)
|
|
82
|
+
- `test/test.ports.ts` — Comprehensive port testing (27 tests)
|
|
83
|
+
- `test/test.features.ts` — DNS, HTTP health check, traceroute, multi-ping, plugins, caching
|
|
84
|
+
- All tests require `start()`/`stop()` lifecycle for the Rust bridge
|
|
57
85
|
|
|
58
86
|
## Technical Details
|
|
59
87
|
- ESM-only package (module type)
|
|
60
88
|
- TypeScript with strict typing
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- systeminformation for network interface details
|
|
65
|
-
- isopen for remote port checking
|
|
66
|
-
- Uses native Node.js modules for DNS, HTTP/HTTPS, and network operations
|
|
89
|
+
- Node built-in imports use `node:` prefix throughout
|
|
90
|
+
- Uses native Node.js modules for HTTP/HTTPS and os.networkInterfaces()
|
|
91
|
+
- Rust binary requires no elevated privileges for port checks; ICMP ping needs CAP_NET_RAW or appropriate ping_group_range
|
|
67
92
|
|
|
68
93
|
## Design Patterns
|
|
94
|
+
- Singleton pattern for RustNetworkBridge
|
|
69
95
|
- Factory pattern for plugin registration
|
|
70
96
|
- Caching pattern with TTL for expensive operations
|
|
71
97
|
- Promise-based async/await throughout
|
|
72
|
-
-
|
|
73
|
-
-
|
|
98
|
+
- Error propagation with custom error types
|
|
99
|
+
- Graceful degradation when ICMP permissions unavailable
|
package/readme.md
CHANGED
|
@@ -37,6 +37,14 @@ import { SmartNetwork } from '@push.rocks/smartnetwork';
|
|
|
37
37
|
// Basic instance
|
|
38
38
|
const network = new SmartNetwork();
|
|
39
39
|
|
|
40
|
+
// Start the Rust bridge (auto-started on first use, but explicit start is recommended)
|
|
41
|
+
await network.start();
|
|
42
|
+
|
|
43
|
+
// ... use the network instance ...
|
|
44
|
+
|
|
45
|
+
// Clean up when done (stops the Rust bridge process)
|
|
46
|
+
await network.stop();
|
|
47
|
+
|
|
40
48
|
// With caching enabled (60 seconds TTL)
|
|
41
49
|
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
42
50
|
```
|
|
@@ -99,6 +107,19 @@ const findFreePort = async () => {
|
|
|
99
107
|
// Find a random free port in range (useful to avoid port conflicts)
|
|
100
108
|
const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
|
|
101
109
|
console.log(`🎲 Random free port: ${randomPort}`);
|
|
110
|
+
|
|
111
|
+
// Exclude specific ports from the search
|
|
112
|
+
const portWithExclusions = await network.findFreePort(3000, 3100, {
|
|
113
|
+
exclude: [3000, 3001, 3005] // Skip these ports even if they're free
|
|
114
|
+
});
|
|
115
|
+
console.log(`🚫 Free port (excluding specific ports): ${portWithExclusions}`);
|
|
116
|
+
|
|
117
|
+
// Combine randomize with exclude options
|
|
118
|
+
const randomWithExclusions = await network.findFreePort(3000, 3100, {
|
|
119
|
+
randomize: true,
|
|
120
|
+
exclude: [3000, 3001, 3005]
|
|
121
|
+
});
|
|
122
|
+
console.log(`🎲🚫 Random free port (with exclusions): ${randomWithExclusions}`);
|
|
102
123
|
};
|
|
103
124
|
```
|
|
104
125
|
|
|
@@ -333,6 +354,7 @@ interface SmartNetworkOptions {
|
|
|
333
354
|
|
|
334
355
|
interface IFindFreePortOptions {
|
|
335
356
|
randomize?: boolean; // If true, returns a random free port instead of the first one
|
|
357
|
+
exclude?: number[]; // Array of port numbers to exclude from the search
|
|
336
358
|
}
|
|
337
359
|
|
|
338
360
|
interface Hop {
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/helpers/stats.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function quartile(values: number[], percentile: number) {
|
|
|
33
33
|
|
|
34
34
|
export function jitter(values: number[]) {
|
|
35
35
|
// Average distance between consecutive latency measurements...
|
|
36
|
-
let jitters = [];
|
|
36
|
+
let jitters: number[] = [];
|
|
37
37
|
|
|
38
38
|
for (let i = 0; i < values.length - 1; i += 1) {
|
|
39
39
|
jitters.push(Math.abs(values[i] - values[i + 1]));
|
package/ts/index.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './smartnetwork.classes.smartnetwork.js';
|
|
2
2
|
export type { SmartNetworkOptions, Hop } from './smartnetwork.classes.smartnetwork.js';
|
|
3
|
+
export { RustNetworkBridge } from './smartnetwork.classes.rustbridge.js';
|
|
3
4
|
export { PublicIp } from './smartnetwork.classes.publicip.js';
|
|
5
|
+
export { IpIntelligence } from './smartnetwork.classes.ipintelligence.js';
|
|
6
|
+
export type { IIpIntelligenceResult, IIpIntelligenceOptions } from './smartnetwork.classes.ipintelligence.js';
|
|
4
7
|
export { setLogger, getLogger } from './logging.js';
|
|
5
8
|
export { NetworkError, TimeoutError } from './errors.js';
|
|
@@ -53,7 +53,7 @@ export class CloudflareSpeed {
|
|
|
53
53
|
const t5 = await measureDownloadParallel(100001000, 1);
|
|
54
54
|
downloadTests = [...t1, ...t2, ...t3, ...t4, ...t5];
|
|
55
55
|
}
|
|
56
|
-
const speedDownload = stats.quartile(downloadTests, 0.9).toFixed(2);
|
|
56
|
+
const speedDownload = downloadTests.length > 0 ? stats.quartile(downloadTests, 0.9).toFixed(2) : '0.00';
|
|
57
57
|
|
|
58
58
|
// lets test the upload speed with configurable parallel streams
|
|
59
59
|
const measureUploadParallel = (bytes: number, iterations: number) => {
|
|
@@ -84,7 +84,7 @@ export class CloudflareSpeed {
|
|
|
84
84
|
const u3 = await measureUploadParallel(1001000, 8);
|
|
85
85
|
uploadTests = [...u1, ...u2, ...u3];
|
|
86
86
|
}
|
|
87
|
-
const speedUpload = stats.quartile(uploadTests, 0.9).toFixed(2);
|
|
87
|
+
const speedUpload = uploadTests.length > 0 ? stats.quartile(uploadTests, 0.9).toFixed(2) : '0.00';
|
|
88
88
|
|
|
89
89
|
return {
|
|
90
90
|
...latency,
|
|
@@ -147,8 +147,14 @@ export class CloudflareSpeed {
|
|
|
147
147
|
for (let i = 0; i < iterations; i += 1) {
|
|
148
148
|
await this.upload(bytes).then(
|
|
149
149
|
async (response) => {
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
// Prefer server-timing duration; fall back to client-side transfer time
|
|
151
|
+
let transferTime = response[6];
|
|
152
|
+
if (!transferTime || !isFinite(transferTime)) {
|
|
153
|
+
transferTime = response[5] - response[4]; // ended - ttfb
|
|
154
|
+
}
|
|
155
|
+
if (transferTime > 0) {
|
|
156
|
+
measurements.push(await this.measureSpeed(bytes, transferTime));
|
|
157
|
+
}
|
|
152
158
|
},
|
|
153
159
|
(error) => {
|
|
154
160
|
getLogger().error('Error measuring upload chunk:', error);
|
|
@@ -164,17 +170,22 @@ export class CloudflareSpeed {
|
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
public async fetchServerLocations(): Promise<{ [key: string]: string }> {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
try {
|
|
174
|
+
const raw = await this.get('speed.cloudflare.com', '/locations');
|
|
175
|
+
const parsed = JSON.parse(raw);
|
|
176
|
+
if (!Array.isArray(parsed)) {
|
|
177
|
+
return {};
|
|
178
|
+
}
|
|
179
|
+
return (parsed as Array<{ iata: string; city: string }>).reduce(
|
|
180
|
+
(data: Record<string, string>, entry) => {
|
|
181
|
+
data[entry.iata] = entry.city;
|
|
182
|
+
return data;
|
|
183
|
+
},
|
|
184
|
+
{} as Record<string, string>,
|
|
185
|
+
);
|
|
186
|
+
} catch {
|
|
187
|
+
return {};
|
|
188
|
+
}
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
public async get(hostname: string, path: string): Promise<string> {
|
|
@@ -259,7 +270,12 @@ export class CloudflareSpeed {
|
|
|
259
270
|
sslHandshake,
|
|
260
271
|
ttfb,
|
|
261
272
|
ended,
|
|
262
|
-
|
|
273
|
+
(() => {
|
|
274
|
+
const serverTiming = res.headers['server-timing'] as string | undefined;
|
|
275
|
+
if (!serverTiming) return 0;
|
|
276
|
+
const match = serverTiming.match(/dur=([\d.]+)/);
|
|
277
|
+
return match ? parseFloat(match[1]) : parseFloat(serverTiming.slice(22)) || 0;
|
|
278
|
+
})(),
|
|
263
279
|
]);
|
|
264
280
|
});
|
|
265
281
|
});
|