@serve.zone/dcrouter 17.2.1 → 17.2.3
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/deno.json +1 -1
- package/dist_serve/bundle.js +1509 -1478
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/network/network-activity-history.js +24 -9
- package/dist_ts_web/elements/network/network-activity-visuals.d.ts +27 -0
- package/dist_ts_web/elements/network/network-activity-visuals.js +73 -0
- package/dist_ts_web/elements/network/ops-view-network-activity.d.ts +0 -1
- package/dist_ts_web/elements/network/ops-view-network-activity.js +37 -44
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/network/network-activity-history.ts +32 -9
- package/ts_web/elements/network/network-activity-visuals.ts +93 -0
- package/ts_web/elements/network/ops-view-network-activity.ts +49 -40
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NETWORK_ACTIVITY_PROTOCOL_ORDER,
|
|
3
|
+
orderNetworkActivityProtocolNames,
|
|
4
|
+
} from './network-activity-visuals.js';
|
|
5
|
+
|
|
1
6
|
export interface IChartPoint {
|
|
2
7
|
x: string | number;
|
|
3
8
|
y: number;
|
|
@@ -14,9 +19,19 @@ export type TProtocolChartSeries = Array<{
|
|
|
14
19
|
data: IChartPoint[];
|
|
15
20
|
}>;
|
|
16
21
|
|
|
17
|
-
export const PROTOCOL_ORDER =
|
|
22
|
+
export const PROTOCOL_ORDER = NETWORK_ACTIVITY_PROTOCOL_ORDER;
|
|
18
23
|
export const PROTOCOL_SERIES_ORDER = ['Total Active', ...PROTOCOL_ORDER] as const;
|
|
19
24
|
|
|
25
|
+
const getProtocolSeriesOrder = (
|
|
26
|
+
protocolNamesArg: string[],
|
|
27
|
+
): string[] => [
|
|
28
|
+
'Total Active',
|
|
29
|
+
...orderNetworkActivityProtocolNames([
|
|
30
|
+
...PROTOCOL_ORDER,
|
|
31
|
+
...protocolNamesArg,
|
|
32
|
+
]),
|
|
33
|
+
];
|
|
34
|
+
|
|
20
35
|
const toEpochSecond = (timestampArg: string | number): number => {
|
|
21
36
|
const timestampMs = typeof timestampArg === 'number'
|
|
22
37
|
? timestampArg
|
|
@@ -59,7 +74,9 @@ export const mergeChartPoints = (
|
|
|
59
74
|
|
|
60
75
|
export const createProtocolConnectionSeries = (
|
|
61
76
|
historyArg: IProtocolConnectionHistoryPointLike[] = [],
|
|
62
|
-
): TProtocolChartSeries =>
|
|
77
|
+
): TProtocolChartSeries => getProtocolSeriesOrder(
|
|
78
|
+
historyArg.flatMap((point) => Object.keys(point.protocols)),
|
|
79
|
+
).map((seriesName) => ({
|
|
63
80
|
name: seriesName,
|
|
64
81
|
data: historyArg.map((point) => ({
|
|
65
82
|
x: new Date(point.timestamp).toISOString(),
|
|
@@ -79,8 +96,12 @@ export const mergeProtocolConnectionHistory = (
|
|
|
79
96
|
createProtocolConnectionSeries(canonicalHistoryArg)
|
|
80
97
|
.map((series) => [series.name, series]),
|
|
81
98
|
);
|
|
99
|
+
const seriesOrder = getProtocolSeriesOrder([
|
|
100
|
+
...localSeriesArg.map((series) => series.name),
|
|
101
|
+
...canonicalHistoryArg.flatMap((point) => Object.keys(point.protocols)),
|
|
102
|
+
]);
|
|
82
103
|
|
|
83
|
-
return
|
|
104
|
+
return seriesOrder.map((seriesName) => ({
|
|
84
105
|
name: seriesName,
|
|
85
106
|
data: mergeChartPoints(
|
|
86
107
|
localSeriesByName.get(seriesName)?.data ?? [],
|
|
@@ -92,10 +113,9 @@ export const mergeProtocolConnectionHistory = (
|
|
|
92
113
|
|
|
93
114
|
export const getProtocolConnectionTotal = (
|
|
94
115
|
protocolsArg: Record<string, number>,
|
|
95
|
-
): number => (protocolsArg
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
+ (protocolsArg.Other ?? 0);
|
|
116
|
+
): number => Object.entries(protocolsArg)
|
|
117
|
+
.filter(([name]) => name !== 'WebSocket')
|
|
118
|
+
.reduce((total, [, count]) => total + count, 0);
|
|
99
119
|
|
|
100
120
|
export const appendProtocolConnectionSample = (
|
|
101
121
|
localSeriesArg: TProtocolChartSeries,
|
|
@@ -104,7 +124,11 @@ export const appendProtocolConnectionSample = (
|
|
|
104
124
|
maximumPointsArg: number,
|
|
105
125
|
): TProtocolChartSeries => {
|
|
106
126
|
const localSeriesByName = new Map(localSeriesArg.map((series) => [series.name, series]));
|
|
107
|
-
|
|
127
|
+
const seriesOrder = getProtocolSeriesOrder([
|
|
128
|
+
...localSeriesArg.map((series) => series.name),
|
|
129
|
+
...Object.keys(protocolsArg),
|
|
130
|
+
]);
|
|
131
|
+
return seriesOrder.map((seriesName) => ({
|
|
108
132
|
name: seriesName,
|
|
109
133
|
data: mergeChartPoints(
|
|
110
134
|
localSeriesByName.get(seriesName)?.data ?? [],
|
|
@@ -123,4 +147,3 @@ export const shouldRestartNetworkActivityTimer = (
|
|
|
123
147
|
isConnectedArg: boolean,
|
|
124
148
|
documentHiddenArg: boolean,
|
|
125
149
|
): boolean => isConnectedArg && !documentHiddenArg;
|
|
126
|
-
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const NETWORK_ACTIVITY_COLORS = {
|
|
2
|
+
'Total Active': '#64748b',
|
|
3
|
+
'HTTP/1.1': '#1976d2',
|
|
4
|
+
'HTTP/2': '#388e3c',
|
|
5
|
+
'HTTP/3': '#7b1fa2',
|
|
6
|
+
'WebSocket': '#f57c00',
|
|
7
|
+
'Other': '#757575',
|
|
8
|
+
'Inbound': '#22c55e',
|
|
9
|
+
'Outbound': '#8b5cf6',
|
|
10
|
+
'Requests/sec': '#3b82f6',
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export const NETWORK_ACTIVITY_PROTOCOL_ORDER = [
|
|
14
|
+
'HTTP/1.1',
|
|
15
|
+
'HTTP/2',
|
|
16
|
+
'HTTP/3',
|
|
17
|
+
'WebSocket',
|
|
18
|
+
'Other',
|
|
19
|
+
] as const;
|
|
20
|
+
|
|
21
|
+
export const PROTOCOL_CONNECTION_LEGEND_STATS: Array<'latest'> = ['latest'];
|
|
22
|
+
export const PROTOCOL_CONNECTION_CHART_LINES: Array<'avg' | 'max'> = [];
|
|
23
|
+
|
|
24
|
+
export const NETWORK_ACTIVITY_FALLBACK_COLORS = [
|
|
25
|
+
'#007aff',
|
|
26
|
+
'#32ade6',
|
|
27
|
+
'#af52de',
|
|
28
|
+
'#ff9500',
|
|
29
|
+
'#34c759',
|
|
30
|
+
'#ff2d55',
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
const knownProtocolNames = new Set<string>(NETWORK_ACTIVITY_PROTOCOL_ORDER);
|
|
34
|
+
|
|
35
|
+
export const getNetworkActivityColor = (
|
|
36
|
+
nameArg: string,
|
|
37
|
+
fallbackIndexArg = 0,
|
|
38
|
+
): string => {
|
|
39
|
+
const canonicalColor = NETWORK_ACTIVITY_COLORS[
|
|
40
|
+
nameArg as keyof typeof NETWORK_ACTIVITY_COLORS
|
|
41
|
+
];
|
|
42
|
+
if (canonicalColor) return canonicalColor;
|
|
43
|
+
const fallbackIndex = Math.max(0, Math.trunc(fallbackIndexArg));
|
|
44
|
+
return NETWORK_ACTIVITY_FALLBACK_COLORS[
|
|
45
|
+
fallbackIndex % NETWORK_ACTIVITY_FALLBACK_COLORS.length
|
|
46
|
+
];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const orderNetworkActivityProtocolNames = (
|
|
50
|
+
namesArg: string[],
|
|
51
|
+
): string[] => {
|
|
52
|
+
const names = new Set(namesArg.filter((name) => name && name !== 'Total Active'));
|
|
53
|
+
const orderedKnown = NETWORK_ACTIVITY_PROTOCOL_ORDER
|
|
54
|
+
.filter((name) => name !== 'Other' && names.has(name));
|
|
55
|
+
const orderedUnknown = [...names]
|
|
56
|
+
.filter((name) => !knownProtocolNames.has(name))
|
|
57
|
+
.sort((nameA, nameB) => nameA.localeCompare(nameB));
|
|
58
|
+
return [
|
|
59
|
+
...orderedKnown,
|
|
60
|
+
...orderedUnknown,
|
|
61
|
+
...(names.has('Other') ? ['Other'] : []),
|
|
62
|
+
];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const createNetworkProtocolDonutData = (
|
|
66
|
+
countsArg: Record<string, number>,
|
|
67
|
+
paletteProtocolNamesArg: string[] = [],
|
|
68
|
+
): Array<{ name: string; value: number; color: string }> => {
|
|
69
|
+
const orderedNames = orderNetworkActivityProtocolNames(Object.keys(countsArg));
|
|
70
|
+
const paletteNames = orderNetworkActivityProtocolNames([
|
|
71
|
+
...orderedNames,
|
|
72
|
+
...paletteProtocolNamesArg,
|
|
73
|
+
]);
|
|
74
|
+
const unknownNames = paletteNames.filter((name) => !knownProtocolNames.has(name));
|
|
75
|
+
return orderedNames
|
|
76
|
+
.filter((name) => (countsArg[name] ?? 0) > 0)
|
|
77
|
+
.map((name) => ({
|
|
78
|
+
name,
|
|
79
|
+
value: countsArg[name] ?? 0,
|
|
80
|
+
color: getNetworkActivityColor(name, unknownNames.indexOf(name)),
|
|
81
|
+
}));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const colorNetworkProtocolSeries = <T extends { name: string }>(
|
|
85
|
+
seriesArg: T[],
|
|
86
|
+
): Array<T & { color: string }> => {
|
|
87
|
+
const orderedNames = orderNetworkActivityProtocolNames(seriesArg.map((series) => series.name));
|
|
88
|
+
const unknownNames = orderedNames.filter((name) => !knownProtocolNames.has(name));
|
|
89
|
+
return seriesArg.map((series) => ({
|
|
90
|
+
...series,
|
|
91
|
+
color: getNetworkActivityColor(series.name, unknownNames.indexOf(series.name)),
|
|
92
|
+
}));
|
|
93
|
+
};
|
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
type IChartPoint,
|
|
15
15
|
type TProtocolChartSeries,
|
|
16
16
|
} from './network-activity-history.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
17
|
+
import {
|
|
18
|
+
NETWORK_ACTIVITY_COLORS,
|
|
19
|
+
PROTOCOL_CONNECTION_CHART_LINES,
|
|
20
|
+
PROTOCOL_CONNECTION_LEGEND_STATS,
|
|
21
|
+
colorNetworkProtocolSeries,
|
|
22
|
+
createNetworkProtocolDonutData,
|
|
23
|
+
getNetworkActivityColor,
|
|
24
|
+
} from './network-activity-visuals.js';
|
|
25
25
|
|
|
26
26
|
declare global {
|
|
27
27
|
interface HTMLElementTagNameMap {
|
|
@@ -181,13 +181,6 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
private getProtocolSeriesWithColors(seriesArg: TProtocolChartSeries) {
|
|
185
|
-
return seriesArg.map((series) => ({
|
|
186
|
-
...series,
|
|
187
|
-
color: series.name === 'Total Active' ? '#ef4444' : (PROTOCOL_COLORS[series.name] ?? '#757575'),
|
|
188
|
-
}));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
184
|
private mergeProtocolConnectionHistories(): void {
|
|
192
185
|
const frontendHistory = this.networkState.frontendConnectionHistory || [];
|
|
193
186
|
const latestFrontendEpochSecond = getLatestHistoryEpochSecond(frontendHistory);
|
|
@@ -239,6 +232,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
239
232
|
display: flex;
|
|
240
233
|
flex-direction: column;
|
|
241
234
|
gap: 24px;
|
|
235
|
+
container-type: inline-size;
|
|
242
236
|
}
|
|
243
237
|
|
|
244
238
|
|
|
@@ -345,8 +339,9 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
345
339
|
|
|
346
340
|
.protocolChartGrid {
|
|
347
341
|
display: grid;
|
|
348
|
-
grid-template-columns: 1fr;
|
|
342
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
349
343
|
gap: 16px;
|
|
344
|
+
min-width: 0;
|
|
350
345
|
}
|
|
351
346
|
|
|
352
347
|
.protocolChartColumn {
|
|
@@ -356,6 +351,19 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
356
351
|
min-width: 0;
|
|
357
352
|
}
|
|
358
353
|
|
|
354
|
+
.protocolChartColumn > dees-chart-donut,
|
|
355
|
+
.protocolChartColumn > dees-chart-area {
|
|
356
|
+
width: 100%;
|
|
357
|
+
max-width: 100%;
|
|
358
|
+
min-width: 0;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@container (max-width: 800px) {
|
|
362
|
+
.protocolChartGrid {
|
|
363
|
+
grid-template-columns: minmax(0, 1fr);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
359
367
|
`,
|
|
360
368
|
];
|
|
361
369
|
|
|
@@ -374,12 +382,12 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
374
382
|
{
|
|
375
383
|
name: 'Inbound',
|
|
376
384
|
data: this.trafficDataIn,
|
|
377
|
-
color:
|
|
385
|
+
color: NETWORK_ACTIVITY_COLORS.Inbound,
|
|
378
386
|
},
|
|
379
387
|
{
|
|
380
388
|
name: 'Outbound',
|
|
381
389
|
data: this.trafficDataOut,
|
|
382
|
-
color:
|
|
390
|
+
color: NETWORK_ACTIVITY_COLORS.Outbound,
|
|
383
391
|
}
|
|
384
392
|
]}
|
|
385
393
|
.realtimeMode=${true}
|
|
@@ -587,7 +595,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
587
595
|
value: activeConnections,
|
|
588
596
|
type: 'number',
|
|
589
597
|
icon: 'lucide:Plug',
|
|
590
|
-
color:
|
|
598
|
+
color: NETWORK_ACTIVITY_COLORS['Total Active'],
|
|
591
599
|
description: `Total: ${this.formatNumber(this.statsState.serverStats?.totalConnections || 0)} connections`,
|
|
592
600
|
actions: [
|
|
593
601
|
{
|
|
@@ -604,7 +612,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
604
612
|
value: reqPerSec,
|
|
605
613
|
type: 'trend',
|
|
606
614
|
icon: 'lucide:ChartLine',
|
|
607
|
-
color: '
|
|
615
|
+
color: NETWORK_ACTIVITY_COLORS['Requests/sec'],
|
|
608
616
|
trendData: trendData,
|
|
609
617
|
description: `Total: ${this.formatNumber(this.networkState.requestsTotal || 0)} requests`,
|
|
610
618
|
},
|
|
@@ -615,7 +623,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
615
623
|
unit: '',
|
|
616
624
|
type: 'number',
|
|
617
625
|
icon: 'lucide:Download',
|
|
618
|
-
color:
|
|
626
|
+
color: NETWORK_ACTIVITY_COLORS.Inbound,
|
|
619
627
|
description: `Total: ${this.formatBytes(this.networkState.totalBytes?.in || 0)}`,
|
|
620
628
|
},
|
|
621
629
|
{
|
|
@@ -625,7 +633,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
625
633
|
unit: '',
|
|
626
634
|
type: 'number',
|
|
627
635
|
icon: 'lucide:Upload',
|
|
628
|
-
color:
|
|
636
|
+
color: NETWORK_ACTIVITY_COLORS.Outbound,
|
|
629
637
|
description: `Total: ${this.formatBytes(this.networkState.totalBytes?.out || 0)}`,
|
|
630
638
|
},
|
|
631
639
|
];
|
|
@@ -642,28 +650,25 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
642
650
|
const fp = this.networkState.frontendProtocols;
|
|
643
651
|
const bp = this.networkState.backendProtocols;
|
|
644
652
|
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
if (dist.otherActive > 0) items.push({ name: 'Other', value: dist.otherActive, color: protoColors['Other'] });
|
|
655
|
-
return items;
|
|
656
|
-
};
|
|
653
|
+
const buildDonutData = (
|
|
654
|
+
dist: interfaces.data.IProtocolDistribution | null,
|
|
655
|
+
historySeries: TProtocolChartSeries,
|
|
656
|
+
) => dist
|
|
657
|
+
? createNetworkProtocolDonutData(
|
|
658
|
+
this.getProtocolCounts(dist),
|
|
659
|
+
historySeries.map((series) => series.name),
|
|
660
|
+
)
|
|
661
|
+
: [];
|
|
657
662
|
|
|
658
|
-
const frontendData = buildDonutData(fp);
|
|
659
|
-
const backendData = buildDonutData(bp);
|
|
663
|
+
const frontendData = buildDonutData(fp, this.frontendConnectionSeries);
|
|
664
|
+
const backendData = buildDonutData(bp, this.backendConnectionSeries);
|
|
660
665
|
|
|
661
666
|
return html`
|
|
662
667
|
<div class="protocolChartGrid">
|
|
663
668
|
<div class="protocolChartColumn">
|
|
664
669
|
<dees-chart-donut
|
|
665
670
|
.label=${'Frontend Protocols'}
|
|
666
|
-
.data=${frontendData.length > 0 ? frontendData : [{ name: 'No Traffic', value: 1, color: '
|
|
671
|
+
.data=${frontendData.length > 0 ? frontendData : [{ name: 'No Traffic', value: 1, color: getNetworkActivityColor('Other') }]}
|
|
667
672
|
.showLegend=${true}
|
|
668
673
|
.showLabels=${true}
|
|
669
674
|
.innerRadiusPercent=${'55%'}
|
|
@@ -671,7 +676,9 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
671
676
|
></dees-chart-donut>
|
|
672
677
|
<dees-chart-area
|
|
673
678
|
.label=${'Frontend Active Connections'}
|
|
674
|
-
.series=${
|
|
679
|
+
.series=${colorNetworkProtocolSeries(this.frontendConnectionSeries)}
|
|
680
|
+
.legendStats=${PROTOCOL_CONNECTION_LEGEND_STATS}
|
|
681
|
+
.chartLines=${PROTOCOL_CONNECTION_CHART_LINES}
|
|
675
682
|
.realtimeMode=${true}
|
|
676
683
|
.rollingWindow=${OpsViewNetworkActivity.CHART_WINDOW_MS}
|
|
677
684
|
.yAxisFormatter=${(val: number) => `${Math.round(val)} active`}
|
|
@@ -680,7 +687,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
680
687
|
<div class="protocolChartColumn">
|
|
681
688
|
<dees-chart-donut
|
|
682
689
|
.label=${'Backend Protocols'}
|
|
683
|
-
.data=${backendData.length > 0 ? backendData : [{ name: 'No Traffic', value: 1, color: '
|
|
690
|
+
.data=${backendData.length > 0 ? backendData : [{ name: 'No Traffic', value: 1, color: getNetworkActivityColor('Other') }]}
|
|
684
691
|
.showLegend=${true}
|
|
685
692
|
.showLabels=${true}
|
|
686
693
|
.innerRadiusPercent=${'55%'}
|
|
@@ -688,7 +695,9 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
688
695
|
></dees-chart-donut>
|
|
689
696
|
<dees-chart-area
|
|
690
697
|
.label=${'Backend Active Connections'}
|
|
691
|
-
.series=${
|
|
698
|
+
.series=${colorNetworkProtocolSeries(this.backendConnectionSeries)}
|
|
699
|
+
.legendStats=${PROTOCOL_CONNECTION_LEGEND_STATS}
|
|
700
|
+
.chartLines=${PROTOCOL_CONNECTION_CHART_LINES}
|
|
692
701
|
.realtimeMode=${true}
|
|
693
702
|
.rollingWindow=${OpsViewNetworkActivity.CHART_WINDOW_MS}
|
|
694
703
|
.yAxisFormatter=${(val: number) => `${Math.round(val)} active`}
|