@ddd-qc/lit-happ 0.34.0 → 0.34.1
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/dist/NetworkCaller.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AppProxy, CellAddress } from "@ddd-qc/cell-proxy";
|
|
1
|
+
import { AgentId, AppProxy, CellAddress } from "@ddd-qc/cell-proxy";
|
|
2
2
|
import { NetworkMetrics, Timestamp } from "@holochain/client";
|
|
3
3
|
import { TransportStats } from "@holochain/client/lib/api/admin/types";
|
|
4
4
|
export declare class NetworkCaller {
|
|
@@ -10,6 +10,7 @@ export declare class NetworkCaller {
|
|
|
10
10
|
private _networkStatsLogs;
|
|
11
11
|
private _intervalId;
|
|
12
12
|
private _callbacks;
|
|
13
|
+
private _transportToAgentMap;
|
|
13
14
|
setCellAddr(cellAddr: CellAddress): void;
|
|
14
15
|
setCapacity(n: number): void;
|
|
15
16
|
get networkMetricsLogs(): [Timestamp, NetworkMetrics][];
|
|
@@ -20,6 +21,9 @@ export declare class NetworkCaller {
|
|
|
20
21
|
clearAllCallbacks(): void;
|
|
21
22
|
stopCallLoop(): void;
|
|
22
23
|
clear(): void;
|
|
24
|
+
peerKeyToAgentId(transportKey: string): Promise<AgentId | undefined>;
|
|
25
|
+
dumpTransportToAgentMap(): void;
|
|
26
|
+
updateTransportToAgentMap(): Promise<void>;
|
|
23
27
|
callNetworkMetrics(): Promise<NetworkMetrics>;
|
|
24
28
|
dumpNetworkMetricsLogs(n?: number): void;
|
|
25
29
|
callNetworkStats(): Promise<TransportStats>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkCaller.d.ts","sourceRoot":"","sources":["../src/NetworkCaller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAyB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"NetworkCaller.d.ts","sourceRoot":"","sources":["../src/NetworkCaller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAyB,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAKH,cAAc,EACd,SAAS,EACZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,cAAc,EAAC,MAAM,uCAAuC,CAAC;AAQrE,qBAAa,aAAa;IAGZ,OAAO,CAAC,QAAQ;IAAY,OAAO,CAAC,QAAQ,CAAC;gBAArC,QAAQ,EAAE,QAAQ,EAAU,QAAQ,CAAC,EAAE,WAAW,YAAA;IAKtE,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,mBAAmB,CAA+D;IAC1F,OAAO,CAAC,iBAAiB,CAA+D;IAExF,OAAO,CAAC,WAAW,CAA8B;IAEjD,OAAO,CAAC,UAAU,CAAuB;IAGzC,OAAO,CAAC,oBAAoB,CAAmC;IAK/D,WAAW,CAAC,QAAQ,EAAE,WAAW;IAEjC,WAAW,CAAC,CAAC,EAAE,MAAM;IAKrB,IAAI,kBAAkB,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAA6C;IAEpG,IAAI,gBAAgB,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAA2C;IAMhG,SAAS,IAAI,OAAO;IAMpB,aAAa,CAAC,QAAQ,EAAE,MAAM;IAgB9B,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,KAAK,IAAI;IAKpE,iBAAiB;IAKjB,YAAY;IAOZ,KAAK;IAMG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAW1E,uBAAuB;IASjB,yBAAyB;IAwC3B,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC;IAuBnD,sBAAsB,CAAC,CAAC,CAAC,EAAE,MAAM;IA6BzB,gBAAgB,IAAI,OAAO,CAAC,cAAc,CAAC;IAajD,oBAAoB,CAAC,CAAC,CAAC,EAAE,MAAM;CAYlC"}
|
package/dist/NetworkCaller.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { prettyDate, RingBuffer } from "@ddd-qc/cell-proxy";
|
|
1
|
+
import { AgentId, prettyDate, RingBuffer } from "@ddd-qc/cell-proxy";
|
|
2
|
+
import { hashFrom32AndType, HoloHashType } from "@holochain/client";
|
|
2
3
|
export class NetworkCaller {
|
|
3
4
|
constructor(appProxy, cellAddr) {
|
|
4
5
|
this.appProxy = appProxy;
|
|
@@ -8,6 +9,7 @@ export class NetworkCaller {
|
|
|
8
9
|
this._networkStatsLogs = new RingBuffer(50);
|
|
9
10
|
this._intervalId = undefined;
|
|
10
11
|
this._callbacks = [];
|
|
12
|
+
this._transportToAgentMap = new Map();
|
|
11
13
|
}
|
|
12
14
|
setCellAddr(cellAddr) { this.cellAddr = cellAddr; }
|
|
13
15
|
;
|
|
@@ -47,6 +49,43 @@ export class NetworkCaller {
|
|
|
47
49
|
this._networkMetricsLogs.clear();
|
|
48
50
|
this._networkStatsLogs.clear();
|
|
49
51
|
}
|
|
52
|
+
async peerKeyToAgentId(transportKey) {
|
|
53
|
+
const maybe = this._transportToAgentMap.get(transportKey);
|
|
54
|
+
if (maybe) {
|
|
55
|
+
return maybe;
|
|
56
|
+
}
|
|
57
|
+
await this.updateTransportToAgentMap();
|
|
58
|
+
return this._transportToAgentMap.get(transportKey);
|
|
59
|
+
}
|
|
60
|
+
dumpTransportToAgentMap() {
|
|
61
|
+
this.updateTransportToAgentMap().then(() => console.table(this._transportToAgentMap));
|
|
62
|
+
}
|
|
63
|
+
async updateTransportToAgentMap() {
|
|
64
|
+
if (!this.cellAddr) {
|
|
65
|
+
throw Promise.reject("buildTransportToAgentMap() aborted. cellAddr not specified.");
|
|
66
|
+
}
|
|
67
|
+
const agentInfoResponse = await this.appProxy.agentInfo({ dna_hashes: [this.cellAddr.dnaId.hash] });
|
|
68
|
+
for (const agentInfoItem of agentInfoResponse) {
|
|
69
|
+
try {
|
|
70
|
+
const parsed = typeof agentInfoItem === 'string' ? JSON.parse(agentInfoItem) : agentInfoItem;
|
|
71
|
+
const agentInfoData = typeof parsed.agentInfo === 'string' ? JSON.parse(parsed.agentInfo) : parsed.agentInfo;
|
|
72
|
+
const partialAgentId = agentInfoData.agent;
|
|
73
|
+
const peerUrl = agentInfoData.url;
|
|
74
|
+
if (!partialAgentId || !peerUrl) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const transportKey = extractTransportKeyFromUrl(peerUrl);
|
|
78
|
+
if (!transportKey) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const bytes = decodeUrlSafeBase64(partialAgentId);
|
|
82
|
+
const fullAgentKey = hashFrom32AndType(bytes, HoloHashType.Agent);
|
|
83
|
+
this._transportToAgentMap.set(transportKey, new AgentId(fullAgentKey));
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
50
89
|
async callNetworkMetrics() {
|
|
51
90
|
if (!this.cellAddr) {
|
|
52
91
|
throw Promise.reject("callNetworkMetrics() aborted. cellAddr not specified.");
|
|
@@ -122,4 +161,36 @@ function arc_size(arc) {
|
|
|
122
161
|
}
|
|
123
162
|
return arc[1] - arc[0];
|
|
124
163
|
}
|
|
164
|
+
function extractTransportKeyFromUrl(peerUrl) {
|
|
165
|
+
try {
|
|
166
|
+
const urlObj = new URL(peerUrl);
|
|
167
|
+
const pathParts = urlObj.pathname.split('/').filter((p) => p.length > 0);
|
|
168
|
+
if (pathParts.length > 0) {
|
|
169
|
+
const lastPart = pathParts[pathParts.length - 1];
|
|
170
|
+
if (lastPart.length >= 40) {
|
|
171
|
+
return lastPart;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
const parts = peerUrl.split('/');
|
|
177
|
+
const lastPart = parts[parts.length - 1];
|
|
178
|
+
if (lastPart && lastPart.length >= 40) {
|
|
179
|
+
return lastPart;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
function decodeUrlSafeBase64(urlSafeBase64) {
|
|
185
|
+
let standardBase64 = urlSafeBase64.replace(/-/g, '+').replace(/_/g, '/');
|
|
186
|
+
while (standardBase64.length % 4 !== 0) {
|
|
187
|
+
standardBase64 += '=';
|
|
188
|
+
}
|
|
189
|
+
const binaryString = atob(standardBase64);
|
|
190
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
191
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
192
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
193
|
+
}
|
|
194
|
+
return bytes;
|
|
195
|
+
}
|
|
125
196
|
//# sourceMappingURL=NetworkCaller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkCaller.js","sourceRoot":"","sources":["../src/NetworkCaller.ts"],"names":[],"mappings":"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","sourcesContent":["import {AppProxy, CellAddress, prettyDate, RingBuffer} from \"@ddd-qc/cell-proxy\";\r\nimport {DhtArc, DumpNetworkMetricsRequest, FetchStateSummary, NetworkMetrics, Timestamp} from \"@holochain/client\";\r\nimport {TransportStats} from \"@holochain/client/lib/api/admin/types\";\r\n\r\ntype NetworkInfoCb = (info:NetworkMetrics, m: TransportStats) => void;\r\n\r\n\r\n/**\r\n * Class handling network info calling and result storing\r\n */\r\nexport class NetworkCaller {\r\n\r\n /** */\r\n constructor(private appProxy: AppProxy, private cellAddr?: CellAddress) {\r\n // N/A\r\n }\r\n\r\n\r\n private _lastTimeQueried: Timestamp = 0;\r\n private _networkMetricsLogs: RingBuffer<[Timestamp, NetworkMetrics]> = new RingBuffer(50);\r\n private _networkStatsLogs: RingBuffer<[Timestamp, TransportStats]> = new RingBuffer(50);\r\n\r\n\r\n private _intervalId: any | undefined = undefined;\r\n\r\n private _callbacks: NetworkInfoCb[] = [];\r\n\r\n /** -- Getters & Setters -- */\r\n\r\n setCellAddr(cellAddr: CellAddress) { this.cellAddr = cellAddr};\r\n\r\n setCapacity(n: number) {\r\n this._networkMetricsLogs.resize(n);\r\n this._networkStatsLogs.resize(n);\r\n }\r\n\r\n get networkMetricsLogs(): [Timestamp, NetworkMetrics][] {return this._networkMetricsLogs.toArray();}\r\n\r\n get networkStatsLogs(): [Timestamp, TransportStats][] {return this._networkStatsLogs.toArray();}\r\n\r\n\r\n /** -- Methods -- */\r\n\r\n /** */\r\n isLooping(): boolean {\r\n const isUnd = this._intervalId === undefined;\r\n return !isUnd;\r\n }\r\n\r\n /** */\r\n startCallLoop(interval: number) {\r\n if (this.isLooping()) {\r\n this.stopCallLoop();\r\n }\r\n this._intervalId = setInterval(async () => {\r\n //console.log(\"Requesting network info...\");\r\n const res = await this.callNetworkMetrics();\r\n const res2 = await this.callNetworkStats();\r\n for (const callback of this._callbacks) {\r\n callback(res, res2);\r\n }\r\n }, interval);\r\n }\r\n\r\n\r\n /** */\r\n addCallback(callback: (n: NetworkMetrics, m: TransportStats) => void) {\r\n this._callbacks.push(callback);\r\n }\r\n\r\n /** */\r\n clearAllCallbacks() {\r\n this._callbacks = [];\r\n }\r\n\r\n /** */\r\n stopCallLoop() {\r\n clearInterval(this._intervalId);\r\n this._intervalId = undefined;\r\n }\r\n\r\n\r\n /** */\r\n clear() {\r\n this._networkMetricsLogs.clear();\r\n this._networkStatsLogs.clear();\r\n }\r\n\r\n\r\n /** */\r\n async callNetworkMetrics(): Promise<NetworkMetrics> {\r\n if (!this.cellAddr) {\r\n throw Promise.reject(\"callNetworkMetrics() aborted. cellAddr not specified.\");\r\n }\r\n /* Call networkInfo */\r\n const request: DumpNetworkMetricsRequest = {\r\n dna_hash: this.cellAddr.dnaId.hash,\r\n include_dht_summary: true, // ???\r\n };\r\n const response = await this.appProxy.dumpNetworkMetrics(request);\r\n if (!response || !response[this.cellAddr.dnaId.b64]) {\r\n throw Promise.reject(\"No network metrics response for dna\");\r\n }\r\n /* Store */\r\n const dnaResp = response[this.cellAddr.dnaId.b64]!;\r\n this._lastTimeQueried = Date.now();\r\n this._networkMetricsLogs.add([this._lastTimeQueried, dnaResp]);\r\n /** */\r\n return dnaResp;\r\n }\r\n\r\n\r\n /** */\r\n dumpNetworkMetricsLogs(n?: number) {\r\n console.log(`dumpNetworkMetricsLogs()`, this.cellAddr);\r\n if (!this.cellAddr) {\r\n throw Error(\"dumpNetworkMetricsLogs() aborted. cellAddr not specified.\");\r\n }\r\n const nn = n? n : this._networkMetricsLogs.getBufferLength();\r\n let logs = this._networkMetricsLogs.getLastN(nn).map(([ts, metrics]) => {\r\n if (metrics.local_agents.length == 0) {\r\n throw Error(\"No local agents found in NetworkMetrics\");\r\n }\r\n if (metrics.local_agents.length == 0) {\r\n console.warn(\"dumpNetworkMetricsLogs() More than one local_agent found\");\r\n }\r\n const local_agent = metrics.local_agents[0]!;\r\n return {\r\n //ts,\r\n ts: prettyDate(new Date(ts)),\r\n current_arc: arc_size(local_agent.storage_arc),\r\n target_arc: arc_size(local_agent.target_arc),\r\n peers: Object.keys(metrics.gossip_state_summary.peer_meta).length,\r\n //total_peers: Object.keys(metrics.gossip_state_summary.peer_meta).length,\r\n rounds: metrics.gossip_state_summary.accepted_rounds.length,\r\n pending_requests: count_pending_requests(metrics.fetch_state_summary),\r\n }\r\n })\r\n console.table(logs);\r\n }\r\n\r\n /** */\r\n async callNetworkStats(): Promise<TransportStats> {\r\n const response = await this.appProxy.dumpNetworkStats();\r\n if (!response) {\r\n throw Promise.reject(\"No network stats response for dna\");\r\n }\r\n /* Store */\r\n this._networkStatsLogs.add([this._lastTimeQueried, response]);\r\n /** */\r\n return response;\r\n }\r\n\r\n\r\n /** */\r\n dumpNetworkStatsLogs(n?: number) {\r\n console.log(`dumpNetworkStatsLogs()`);\r\n const nn = n ? n : this._networkStatsLogs.getBufferLength();\r\n this._networkStatsLogs.getLastN(nn).map(([ts, stats]) => {\r\n console.log(`[${prettyDate(new Date(ts))}] Backend: ${stats.backend} ; Peers: ${stats.peer_urls.length}`);\r\n const logs = stats.connections.map((connection) => {\r\n return connection;\r\n });\r\n console.table(logs);\r\n });\r\n }\r\n\r\n}\r\n\r\n\r\n/** */\r\nfunction count_pending_requests(fetchSummary: FetchStateSummary): number {\r\n let total = 0;\r\n for (const peerUrls of Object.values(fetchSummary.pending_requests)) {\r\n total += peerUrls.length;\r\n }\r\n return total;\r\n}\r\n\r\n\r\n/** */\r\nfunction arc_size(arc: DhtArc): number {\r\n if (arc == null) {\r\n return 0;\r\n }\r\n return arc[1] - arc[0];\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"NetworkCaller.js","sourceRoot":"","sources":["../src/NetworkCaller.ts"],"names":[],"mappings":"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","sourcesContent":["import {AgentId, AppProxy, CellAddress, prettyDate, RingBuffer} from \"@ddd-qc/cell-proxy\";\r\nimport {\r\n DhtArc,\r\n DumpNetworkMetricsRequest,\r\n FetchStateSummary,\r\n hashFrom32AndType, HoloHashType,\r\n NetworkMetrics,\r\n Timestamp\r\n} from \"@holochain/client\";\r\nimport {TransportStats} from \"@holochain/client/lib/api/admin/types\";\r\n\r\ntype NetworkInfoCb = (info:NetworkMetrics, m: TransportStats) => void;\r\n\r\n\r\n/**\r\n * Class handling network info calling and result storing\r\n */\r\nexport class NetworkCaller {\r\n\r\n /** */\r\n constructor(private appProxy: AppProxy, private cellAddr?: CellAddress) {\r\n // N/A\r\n }\r\n\r\n\r\n private _lastTimeQueried: Timestamp = 0;\r\n private _networkMetricsLogs: RingBuffer<[Timestamp, NetworkMetrics]> = new RingBuffer(50);\r\n private _networkStatsLogs: RingBuffer<[Timestamp, TransportStats]> = new RingBuffer(50);\r\n\r\n private _intervalId: any | undefined = undefined;\r\n\r\n private _callbacks: NetworkInfoCb[] = [];\r\n\r\n /** peer pub key to AgentId */\r\n private _transportToAgentMap: Map<string, AgentId> = new Map();\r\n\r\n\r\n /** -- Getters & Setters -- */\r\n\r\n setCellAddr(cellAddr: CellAddress) { this.cellAddr = cellAddr};\r\n\r\n setCapacity(n: number) {\r\n this._networkMetricsLogs.resize(n);\r\n this._networkStatsLogs.resize(n);\r\n }\r\n\r\n get networkMetricsLogs(): [Timestamp, NetworkMetrics][] {return this._networkMetricsLogs.toArray();}\r\n\r\n get networkStatsLogs(): [Timestamp, TransportStats][] {return this._networkStatsLogs.toArray();}\r\n\r\n\r\n /** -- Methods -- */\r\n\r\n /** */\r\n isLooping(): boolean {\r\n const isUnd = this._intervalId === undefined;\r\n return !isUnd;\r\n }\r\n\r\n /** */\r\n startCallLoop(interval: number) {\r\n if (this.isLooping()) {\r\n this.stopCallLoop();\r\n }\r\n this._intervalId = setInterval(async () => {\r\n //console.log(\"Requesting network info...\");\r\n const res = await this.callNetworkMetrics();\r\n const res2 = await this.callNetworkStats();\r\n for (const callback of this._callbacks) {\r\n callback(res, res2);\r\n }\r\n }, interval);\r\n }\r\n\r\n\r\n /** */\r\n addCallback(callback: (n: NetworkMetrics, m: TransportStats) => void) {\r\n this._callbacks.push(callback);\r\n }\r\n\r\n /** */\r\n clearAllCallbacks() {\r\n this._callbacks = [];\r\n }\r\n\r\n /** */\r\n stopCallLoop() {\r\n clearInterval(this._intervalId);\r\n this._intervalId = undefined;\r\n }\r\n\r\n\r\n /** */\r\n clear() {\r\n this._networkMetricsLogs.clear();\r\n this._networkStatsLogs.clear();\r\n }\r\n\r\n\r\n async peerKeyToAgentId(transportKey: string): Promise<AgentId | undefined> {\r\n const maybe = this._transportToAgentMap.get(transportKey);\r\n if (maybe) {\r\n return maybe;\r\n }\r\n await this.updateTransportToAgentMap();\r\n return this._transportToAgentMap.get(transportKey);\r\n }\r\n\r\n\r\n /** debug */\r\n dumpTransportToAgentMap() {\r\n this.updateTransportToAgentMap().then(() => console.table(this._transportToAgentMap));\r\n }\r\n\r\n /**\r\n * Build a mapping from transport pub_key to AgentPubKey by fetching agentInfo.\r\n * AgentInfo returns both the kitsune agent ID and the peer URL, allowing us to\r\n * map the transport key (from URL) to the actual AgentPubKey.\r\n */\r\n async updateTransportToAgentMap() {\r\n if (!this.cellAddr) {\r\n throw Promise.reject(\"buildTransportToAgentMap() aborted. cellAddr not specified.\");\r\n }\r\n\r\n // Fetch agentInfo for these DNAs\r\n const agentInfoResponse = await this.appProxy.agentInfo({ dna_hashes: [this.cellAddr.dnaId.hash] });\r\n\r\n for (const agentInfoItem of agentInfoResponse) {\r\n try {\r\n // Parse the structure: { agentInfo: \"{...json...}\", signature: \"...\" }\r\n const parsed =\r\n typeof agentInfoItem === 'string' ? JSON.parse(agentInfoItem) : agentInfoItem;\r\n const agentInfoData =\r\n typeof parsed.agentInfo === 'string' ? JSON.parse(parsed.agentInfo) : parsed.agentInfo;\r\n const partialAgentId = agentInfoData.agent;\r\n const peerUrl = agentInfoData.url;\r\n if (!partialAgentId || !peerUrl) {\r\n continue;\r\n }\r\n // Extract transport key from the peer URL\r\n const transportKey = extractTransportKeyFromUrl(peerUrl);\r\n if (!transportKey) {\r\n continue;\r\n }\r\n // Convert partial agent ID to full AgentPubKey\r\n const bytes = decodeUrlSafeBase64(partialAgentId);\r\n // Convert the 32-byte core to a full agent pub key (adds type prefix and DHT location)\r\n const fullAgentKey = hashFrom32AndType(bytes, HoloHashType.Agent);\r\n // Update Map\r\n this._transportToAgentMap.set(transportKey, new AgentId(fullAgentKey));\r\n\r\n } catch (e) {\r\n // Skip invalid entries\r\n }\r\n }\r\n }\r\n \r\n\r\n /** */\r\n async callNetworkMetrics(): Promise<NetworkMetrics> {\r\n if (!this.cellAddr) {\r\n throw Promise.reject(\"callNetworkMetrics() aborted. cellAddr not specified.\");\r\n }\r\n /* Call networkInfo */\r\n const request: DumpNetworkMetricsRequest = {\r\n dna_hash: this.cellAddr.dnaId.hash,\r\n include_dht_summary: true, // ???\r\n };\r\n const response = await this.appProxy.dumpNetworkMetrics(request);\r\n if (!response || !response[this.cellAddr.dnaId.b64]) {\r\n throw Promise.reject(\"No network metrics response for dna\");\r\n }\r\n /* Store */\r\n const dnaResp = response[this.cellAddr.dnaId.b64]!;\r\n this._lastTimeQueried = Date.now();\r\n this._networkMetricsLogs.add([this._lastTimeQueried, dnaResp]);\r\n /** */\r\n return dnaResp;\r\n }\r\n\r\n\r\n /** */\r\n dumpNetworkMetricsLogs(n?: number) {\r\n console.log(`dumpNetworkMetricsLogs()`, this.cellAddr);\r\n if (!this.cellAddr) {\r\n throw Error(\"dumpNetworkMetricsLogs() aborted. cellAddr not specified.\");\r\n }\r\n const nn = n? n : this._networkMetricsLogs.getBufferLength();\r\n let logs = this._networkMetricsLogs.getLastN(nn).map(([ts, metrics]) => {\r\n if (metrics.local_agents.length == 0) {\r\n throw Error(\"No local agents found in NetworkMetrics\");\r\n }\r\n if (metrics.local_agents.length == 0) {\r\n console.warn(\"dumpNetworkMetricsLogs() More than one local_agent found\");\r\n }\r\n const local_agent = metrics.local_agents[0]!;\r\n return {\r\n //ts,\r\n ts: prettyDate(new Date(ts)),\r\n current_arc: arc_size(local_agent.storage_arc),\r\n target_arc: arc_size(local_agent.target_arc),\r\n peers: Object.keys(metrics.gossip_state_summary.peer_meta).length,\r\n //total_peers: Object.keys(metrics.gossip_state_summary.peer_meta).length,\r\n rounds: metrics.gossip_state_summary.accepted_rounds.length,\r\n pending_requests: count_pending_requests(metrics.fetch_state_summary),\r\n }\r\n })\r\n console.table(logs);\r\n }\r\n\r\n /** */\r\n async callNetworkStats(): Promise<TransportStats> {\r\n const response = await this.appProxy.dumpNetworkStats();\r\n if (!response) {\r\n throw Promise.reject(\"No network stats response for dna\");\r\n }\r\n /* Store */\r\n this._networkStatsLogs.add([this._lastTimeQueried, response]);\r\n /** */\r\n return response;\r\n }\r\n\r\n\r\n /** */\r\n dumpNetworkStatsLogs(n?: number) {\r\n console.log(`dumpNetworkStatsLogs()`);\r\n const nn = n ? n : this._networkStatsLogs.getBufferLength();\r\n this._networkStatsLogs.getLastN(nn).map(([ts, stats]) => {\r\n console.log(`[${prettyDate(new Date(ts))}] Backend: ${stats.backend} ; Peers: ${stats.peer_urls.length}`);\r\n const logs = stats.connections.map((connection) => {\r\n return connection;\r\n });\r\n console.table(logs);\r\n });\r\n }\r\n\r\n}\r\n\r\n\r\n/** */\r\nfunction count_pending_requests(fetchSummary: FetchStateSummary): number {\r\n let total = 0;\r\n for (const peerUrls of Object.values(fetchSummary.pending_requests)) {\r\n total += peerUrls.length;\r\n }\r\n return total;\r\n}\r\n\r\n\r\n/** */\r\nfunction arc_size(arc: DhtArc): number {\r\n if (arc == null) {\r\n return 0;\r\n }\r\n return arc[1] - arc[0];\r\n}\r\n\r\n\r\n/**\r\n * Extract the transport pub_key from a peer URL.\r\n * Peer URLs typically have format: wss://host/tx5-ws/sig/<transport_pub_key>\r\n * The transport pub_key is the last path segment.\r\n */\r\nfunction extractTransportKeyFromUrl(peerUrl: string): string | null {\r\n try {\r\n const urlObj = new URL(peerUrl);\r\n const pathParts = urlObj.pathname.split('/').filter((p) => p.length > 0);\r\n // The transport key is the last segment after /tx5-ws/sig/ or similar\r\n if (pathParts.length > 0) {\r\n const lastPart = pathParts[pathParts.length - 1]!;\r\n // Transport keys are typically 40+ characters in URL-safe base64\r\n if (lastPart.length >= 40) {\r\n return lastPart;\r\n }\r\n }\r\n } catch {\r\n // If URL parsing fails, try direct string splitting\r\n const parts = peerUrl.split('/');\r\n const lastPart = parts[parts.length - 1];\r\n if (lastPart && lastPart.length >= 40) {\r\n return lastPart;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Decode URL-safe base64 string to Uint8Array.\r\n * URL-safe base64 uses - and _ instead of + and /.\r\n */\r\nfunction decodeUrlSafeBase64(urlSafeBase64: string): Uint8Array {\r\n // Convert URL-safe base64 to standard base64\r\n let standardBase64 = urlSafeBase64.replace(/-/g, '+').replace(/_/g, '/');\r\n // Add padding if necessary\r\n while (standardBase64.length % 4 !== 0) {\r\n standardBase64 += '=';\r\n }\r\n // Decode base64 to bytes\r\n const binaryString = atob(standardBase64);\r\n const bytes = new Uint8Array(binaryString.length);\r\n for (let i = 0; i < binaryString.length; i++) {\r\n bytes[i] = binaryString.charCodeAt(i);\r\n }\r\n return bytes;\r\n}"]}
|