@serve.zone/dcrouter 5.4.4 → 5.4.5

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.
@@ -52,8 +52,7 @@ export class OpsViewNetwork extends DeesElement {
52
52
  private requestCountHistory = new Map<number, number>(); // Track requests per time bucket
53
53
  private trafficUpdateTimer: any = null;
54
54
  private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
55
-
56
- // Removed byte tracking - now using real-time data from SmartProxy
55
+ private historyLoaded = false; // Whether server-side throughput history has been loaded
57
56
 
58
57
  constructor() {
59
58
  super();
@@ -95,7 +94,7 @@ export class OpsViewNetwork extends DeesElement {
95
94
  // Fixed 5 minute time range
96
95
  const range = 5 * 60 * 1000; // 5 minutes
97
96
  const bucketSize = range / 60; // 60 data points
98
-
97
+
99
98
  // Initialize with empty data points for both in and out
100
99
  const emptyData = Array.from({ length: 60 }, (_, i) => {
101
100
  const time = now - ((59 - i) * bucketSize);
@@ -104,13 +103,61 @@ export class OpsViewNetwork extends DeesElement {
104
103
  y: 0,
105
104
  };
106
105
  });
107
-
106
+
108
107
  this.trafficDataIn = [...emptyData];
109
108
  this.trafficDataOut = emptyData.map(point => ({ ...point }));
110
-
109
+
111
110
  this.lastTrafficUpdateTime = now;
112
111
  }
113
112
 
113
+ /**
114
+ * Load server-side throughput history into the chart.
115
+ * Called once when history data first arrives from the Rust engine.
116
+ * This pre-populates the chart so users see historical data immediately
117
+ * instead of starting from all zeros.
118
+ */
119
+ private loadThroughputHistory() {
120
+ const history = this.networkState.throughputHistory;
121
+ if (!history || history.length === 0) return;
122
+
123
+ this.historyLoaded = true;
124
+
125
+ // Convert history points to chart data format (bytes/sec → Mbit/s)
126
+ const historyIn = history.map(p => ({
127
+ x: new Date(p.timestamp).toISOString(),
128
+ y: Math.round((p.in * 8) / 1000000 * 10) / 10,
129
+ }));
130
+ const historyOut = history.map(p => ({
131
+ x: new Date(p.timestamp).toISOString(),
132
+ y: Math.round((p.out * 8) / 1000000 * 10) / 10,
133
+ }));
134
+
135
+ // Use history as the chart data, keeping the most recent 60 points (5 min window)
136
+ const sliceStart = Math.max(0, historyIn.length - 60);
137
+ this.trafficDataIn = historyIn.slice(sliceStart);
138
+ this.trafficDataOut = historyOut.slice(sliceStart);
139
+
140
+ // If fewer than 60 points, pad the front with zeros
141
+ if (this.trafficDataIn.length < 60) {
142
+ const now = Date.now();
143
+ const range = 5 * 60 * 1000;
144
+ const bucketSize = range / 60;
145
+ const padCount = 60 - this.trafficDataIn.length;
146
+ const firstTimestamp = this.trafficDataIn.length > 0
147
+ ? new Date(this.trafficDataIn[0].x).getTime()
148
+ : now;
149
+
150
+ const padIn = Array.from({ length: padCount }, (_, i) => ({
151
+ x: new Date(firstTimestamp - ((padCount - i) * bucketSize)).toISOString(),
152
+ y: 0,
153
+ }));
154
+ const padOut = padIn.map(p => ({ ...p }));
155
+
156
+ this.trafficDataIn = [...padIn, ...this.trafficDataIn];
157
+ this.trafficDataOut = [...padOut, ...this.trafficDataOut];
158
+ }
159
+ }
160
+
114
161
  public static styles = [
115
162
  cssManager.defaultStyles,
116
163
  viewHostCss,
@@ -352,21 +399,6 @@ export class OpsViewNetwork extends DeesElement {
352
399
  return `${size.toFixed(1)} ${units[unitIndex]}`;
353
400
  }
354
401
 
355
- private calculateRequestsPerSecond(): number {
356
- // Calculate from actual request data in the last minute
357
- const oneMinuteAgo = Date.now() - 60000;
358
- const recentRequests = this.networkRequests.filter(req => req.timestamp >= oneMinuteAgo);
359
- const reqPerSec = Math.round(recentRequests.length / 60);
360
-
361
- // Track history for trend (keep last 20 values)
362
- this.requestsPerSecHistory.push(reqPerSec);
363
- if (this.requestsPerSecHistory.length > 20) {
364
- this.requestsPerSecHistory.shift();
365
- }
366
-
367
- return reqPerSec;
368
- }
369
-
370
402
  private calculateThroughput(): { in: number; out: number } {
371
403
  // Use real throughput data from network state
372
404
  return {
@@ -376,16 +408,17 @@ export class OpsViewNetwork extends DeesElement {
376
408
  }
377
409
 
378
410
  private renderNetworkStats(): TemplateResult {
379
- const reqPerSec = this.calculateRequestsPerSecond();
411
+ // Use server-side requests/sec from SmartProxy's Rust engine
412
+ const reqPerSec = this.networkState.requestsPerSecond || 0;
380
413
  const throughput = this.calculateThroughput();
381
414
  const activeConnections = this.statsState.serverStats?.activeConnections || 0;
382
-
383
- // Throughput data is now available in the stats tiles
384
415
 
385
- // Use request count history for the requests/sec trend
416
+ // Track requests/sec history for the trend sparkline
417
+ this.requestsPerSecHistory.push(reqPerSec);
418
+ if (this.requestsPerSecHistory.length > 20) {
419
+ this.requestsPerSecHistory.shift();
420
+ }
386
421
  const trendData = [...this.requestsPerSecHistory];
387
-
388
- // If we don't have enough data, pad with zeros
389
422
  while (trendData.length < 20) {
390
423
  trendData.unshift(0);
391
424
  }
@@ -398,7 +431,7 @@ export class OpsViewNetwork extends DeesElement {
398
431
  type: 'number',
399
432
  icon: 'plug',
400
433
  color: activeConnections > 100 ? '#f59e0b' : '#22c55e',
401
- description: `Total: ${this.statsState.serverStats?.totalConnections || 0}`,
434
+ description: `Total: ${this.networkState.requestsTotal || this.statsState.serverStats?.totalConnections || 0}`,
402
435
  actions: [
403
436
  {
404
437
  name: 'View Details',
@@ -416,7 +449,7 @@ export class OpsViewNetwork extends DeesElement {
416
449
  icon: 'chartLine',
417
450
  color: '#3b82f6',
418
451
  trendData: trendData,
419
- description: `Average over last minute`,
452
+ description: `Total: ${this.formatNumber(this.networkState.requestsTotal || 0)} requests`,
420
453
  },
421
454
  {
422
455
  id: 'throughputIn',
@@ -462,20 +495,33 @@ export class OpsViewNetwork extends DeesElement {
462
495
  if (this.networkState.topIPs.length === 0) {
463
496
  return html``;
464
497
  }
465
-
498
+
499
+ // Build per-IP bandwidth lookup
500
+ const bandwidthByIP = new Map<string, { in: number; out: number }>();
501
+ if (this.networkState.throughputByIP) {
502
+ for (const entry of this.networkState.throughputByIP) {
503
+ bandwidthByIP.set(entry.ip, { in: entry.in, out: entry.out });
504
+ }
505
+ }
506
+
466
507
  // Calculate total connections across all top IPs
467
508
  const totalConnections = this.networkState.topIPs.reduce((sum, ipData) => sum + ipData.count, 0);
468
-
509
+
469
510
  return html`
470
511
  <dees-table
471
512
  .data=${this.networkState.topIPs}
472
- .displayFunction=${(ipData: { ip: string; count: number }) => ({
473
- 'IP Address': ipData.ip,
474
- 'Connections': ipData.count,
475
- 'Percentage': totalConnections > 0 ? ((ipData.count / totalConnections) * 100).toFixed(1) + '%' : '0%',
476
- })}
513
+ .displayFunction=${(ipData: { ip: string; count: number }) => {
514
+ const bw = bandwidthByIP.get(ipData.ip);
515
+ return {
516
+ 'IP Address': ipData.ip,
517
+ 'Connections': ipData.count,
518
+ 'Bandwidth In': bw ? this.formatBitsPerSecond(bw.in) : '0 bit/s',
519
+ 'Bandwidth Out': bw ? this.formatBitsPerSecond(bw.out) : '0 bit/s',
520
+ 'Share': totalConnections > 0 ? ((ipData.count / totalConnections) * 100).toFixed(1) + '%' : '0%',
521
+ };
522
+ }}
477
523
  heading1="Top Connected IPs"
478
- heading2="IPs with most active connections"
524
+ heading2="IPs with most active connections and bandwidth"
479
525
  .pagination=${false}
480
526
  dataName="ip"
481
527
  ></dees-table>
@@ -515,13 +561,10 @@ export class OpsViewNetwork extends DeesElement {
515
561
  }
516
562
  }
517
563
 
518
- // Generate traffic data based on request history
519
- this.updateTrafficData();
520
- }
521
-
522
- private updateTrafficData() {
523
- // This method is called when network data updates
524
- // The actual chart updates are handled by the timer calling addTrafficDataPoint()
564
+ // Load server-side throughput history into chart (once)
565
+ if (!this.historyLoaded && this.networkState.throughputHistory && this.networkState.throughputHistory.length > 0) {
566
+ this.loadThroughputHistory();
567
+ }
525
568
  }
526
569
 
527
570
  private startTrafficUpdateTimer() {