@serve.zone/dcrouter 9.1.3 → 9.1.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.
- package/dist_serve/bundle.js +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +6 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.js +45 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/remoteingress/classes.tunnel-manager.ts +47 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
package/dist_serve/bundle.js
CHANGED
|
@@ -39317,4 +39317,4 @@ ibantools/jsnext/ibantools.js:
|
|
|
39317
39317
|
* @preferred
|
|
39318
39318
|
*)
|
|
39319
39319
|
*/
|
|
39320
|
-
//# sourceMappingURL=bundle-
|
|
39320
|
+
//# sourceMappingURL=bundle-1772110212956.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/dcrouter',
|
|
6
|
-
version: '9.1.
|
|
6
|
+
version: '9.1.5',
|
|
7
7
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDBFQUEwRTtDQUN4RixDQUFBIn0=
|
|
@@ -12,6 +12,7 @@ export declare class TunnelManager {
|
|
|
12
12
|
private manager;
|
|
13
13
|
private config;
|
|
14
14
|
private edgeStatuses;
|
|
15
|
+
private reconcileInterval;
|
|
15
16
|
constructor(manager: RemoteIngressManager, config?: ITunnelManagerConfig);
|
|
16
17
|
/**
|
|
17
18
|
* Start the tunnel hub and load allowed edges.
|
|
@@ -21,6 +22,11 @@ export declare class TunnelManager {
|
|
|
21
22
|
* Stop the tunnel hub.
|
|
22
23
|
*/
|
|
23
24
|
stop(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Reconcile TS-side edge statuses with the authoritative Rust hub status.
|
|
27
|
+
* Overwrites event-derived activeTunnels with the real activeStreams count.
|
|
28
|
+
*/
|
|
29
|
+
private reconcile;
|
|
24
30
|
/**
|
|
25
31
|
* Sync allowed edges from the manager to the hub.
|
|
26
32
|
* Call this after creating/deleting/updating edges.
|
|
@@ -7,6 +7,7 @@ export class TunnelManager {
|
|
|
7
7
|
manager;
|
|
8
8
|
config;
|
|
9
9
|
edgeStatuses = new Map();
|
|
10
|
+
reconcileInterval = null;
|
|
10
11
|
constructor(manager, config = {}) {
|
|
11
12
|
this.manager = manager;
|
|
12
13
|
this.config = config;
|
|
@@ -50,14 +51,57 @@ export class TunnelManager {
|
|
|
50
51
|
});
|
|
51
52
|
// Send allowed edges to the hub
|
|
52
53
|
await this.syncAllowedEdges();
|
|
54
|
+
// Periodically reconcile with authoritative Rust hub status
|
|
55
|
+
this.reconcileInterval = setInterval(() => {
|
|
56
|
+
this.reconcile().catch(() => { });
|
|
57
|
+
}, 15_000);
|
|
53
58
|
}
|
|
54
59
|
/**
|
|
55
60
|
* Stop the tunnel hub.
|
|
56
61
|
*/
|
|
57
62
|
async stop() {
|
|
63
|
+
if (this.reconcileInterval) {
|
|
64
|
+
clearInterval(this.reconcileInterval);
|
|
65
|
+
this.reconcileInterval = null;
|
|
66
|
+
}
|
|
58
67
|
await this.hub.stop();
|
|
59
68
|
this.edgeStatuses.clear();
|
|
60
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Reconcile TS-side edge statuses with the authoritative Rust hub status.
|
|
72
|
+
* Overwrites event-derived activeTunnels with the real activeStreams count.
|
|
73
|
+
*/
|
|
74
|
+
async reconcile() {
|
|
75
|
+
const hubStatus = await this.hub.getStatus();
|
|
76
|
+
if (!hubStatus || !hubStatus.connectedEdges)
|
|
77
|
+
return;
|
|
78
|
+
const rustEdgeIds = new Set();
|
|
79
|
+
for (const rustEdge of hubStatus.connectedEdges) {
|
|
80
|
+
rustEdgeIds.add(rustEdge.edgeId);
|
|
81
|
+
const existing = this.edgeStatuses.get(rustEdge.edgeId);
|
|
82
|
+
if (existing) {
|
|
83
|
+
existing.activeTunnels = rustEdge.activeStreams;
|
|
84
|
+
existing.lastHeartbeat = Date.now();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Missed edgeConnected event — add entry
|
|
88
|
+
this.edgeStatuses.set(rustEdge.edgeId, {
|
|
89
|
+
edgeId: rustEdge.edgeId,
|
|
90
|
+
connected: true,
|
|
91
|
+
publicIp: null,
|
|
92
|
+
activeTunnels: rustEdge.activeStreams,
|
|
93
|
+
lastHeartbeat: Date.now(),
|
|
94
|
+
connectedAt: rustEdge.connectedAt * 1000,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Remove entries for edges no longer connected in Rust (missed edgeDisconnected)
|
|
99
|
+
for (const edgeId of this.edgeStatuses.keys()) {
|
|
100
|
+
if (!rustEdgeIds.has(edgeId)) {
|
|
101
|
+
this.edgeStatuses.delete(edgeId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
61
105
|
/**
|
|
62
106
|
* Sync allowed edges from the manager to the hub.
|
|
63
107
|
* Call this after creating/deleting/updating edges.
|
|
@@ -100,4 +144,4 @@ export class TunnelManager {
|
|
|
100
144
|
return total;
|
|
101
145
|
}
|
|
102
146
|
}
|
|
103
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50dW5uZWwtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3JlbW90ZWluZ3Jlc3MvY2xhc3Nlcy50dW5uZWwtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQVN6Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxhQUFhO0lBQ2hCLEdBQUcsQ0FBOEQ7SUFDakUsT0FBTyxDQUF1QjtJQUM5QixNQUFNLENBQXVCO0lBQzdCLFlBQVksR0FBc0MsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUM1RCxpQkFBaUIsR0FBMEMsSUFBSSxDQUFDO0lBRXhFLFlBQVksT0FBNkIsRUFBRSxTQUErQixFQUFFO1FBQzFFLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxPQUFPLENBQUMsYUFBYSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEQsNENBQTRDO1FBQzVDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLGVBQWUsRUFBRSxDQUFDLElBQXdCLEVBQUUsRUFBRTtZQUN4RCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDcEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtnQkFDakMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO2dCQUNuQixTQUFTLEVBQUUsSUFBSTtnQkFDZixRQUFRLEVBQUUsUUFBUSxFQUFFLFFBQVEsSUFBSSxJQUFJO2dCQUNwQyxhQUFhLEVBQUUsQ0FBQztnQkFDaEIsYUFBYSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7Z0JBQ3pCLFdBQVcsRUFBRSxJQUFJLENB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
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/dcrouter',
|
|
6
|
-
version: '9.1.
|
|
6
|
+
version: '9.1.5',
|
|
7
7
|
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfd2ViLzAwX2NvbW1pdGluZm9fZGF0YS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRztJQUN4QixJQUFJLEVBQUUsc0JBQXNCO0lBQzVCLE9BQU8sRUFBRSxPQUFPO0lBQ2hCLFdBQVcsRUFBRSwwRUFBMEU7Q0FDeEYsQ0FBQSJ9
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serve.zone/dcrouter",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "9.1.
|
|
4
|
+
"version": "9.1.5",
|
|
5
5
|
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@push.rocks/smartnetwork": "^4.4.0",
|
|
50
50
|
"@push.rocks/smartpath": "^6.0.0",
|
|
51
51
|
"@push.rocks/smartpromise": "^4.2.3",
|
|
52
|
-
"@push.rocks/smartproxy": "^25.8.
|
|
52
|
+
"@push.rocks/smartproxy": "^25.8.1",
|
|
53
53
|
"@push.rocks/smartradius": "^1.1.1",
|
|
54
54
|
"@push.rocks/smartrequest": "^5.0.1",
|
|
55
55
|
"@push.rocks/smartrx": "^3.0.10",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@push.rocks/smartunique": "^3.0.9",
|
|
58
58
|
"@serve.zone/catalog": "^2.5.0",
|
|
59
59
|
"@serve.zone/interfaces": "^5.3.0",
|
|
60
|
-
"@serve.zone/remoteingress": "^4.0.
|
|
60
|
+
"@serve.zone/remoteingress": "^4.0.1",
|
|
61
61
|
"@tsclass/tsclass": "^9.3.0",
|
|
62
62
|
"lru-cache": "^11.2.6",
|
|
63
63
|
"uuid": "^13.0.0"
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -15,6 +15,7 @@ export class TunnelManager {
|
|
|
15
15
|
private manager: RemoteIngressManager;
|
|
16
16
|
private config: ITunnelManagerConfig;
|
|
17
17
|
private edgeStatuses: Map<string, IRemoteIngressStatus> = new Map();
|
|
18
|
+
private reconcileInterval: ReturnType<typeof setInterval> | null = null;
|
|
18
19
|
|
|
19
20
|
constructor(manager: RemoteIngressManager, config: ITunnelManagerConfig = {}) {
|
|
20
21
|
this.manager = manager;
|
|
@@ -65,16 +66,62 @@ export class TunnelManager {
|
|
|
65
66
|
|
|
66
67
|
// Send allowed edges to the hub
|
|
67
68
|
await this.syncAllowedEdges();
|
|
69
|
+
|
|
70
|
+
// Periodically reconcile with authoritative Rust hub status
|
|
71
|
+
this.reconcileInterval = setInterval(() => {
|
|
72
|
+
this.reconcile().catch(() => {});
|
|
73
|
+
}, 15_000);
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
/**
|
|
71
77
|
* Stop the tunnel hub.
|
|
72
78
|
*/
|
|
73
79
|
public async stop(): Promise<void> {
|
|
80
|
+
if (this.reconcileInterval) {
|
|
81
|
+
clearInterval(this.reconcileInterval);
|
|
82
|
+
this.reconcileInterval = null;
|
|
83
|
+
}
|
|
74
84
|
await this.hub.stop();
|
|
75
85
|
this.edgeStatuses.clear();
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Reconcile TS-side edge statuses with the authoritative Rust hub status.
|
|
90
|
+
* Overwrites event-derived activeTunnels with the real activeStreams count.
|
|
91
|
+
*/
|
|
92
|
+
private async reconcile(): Promise<void> {
|
|
93
|
+
const hubStatus = await this.hub.getStatus();
|
|
94
|
+
if (!hubStatus || !hubStatus.connectedEdges) return;
|
|
95
|
+
|
|
96
|
+
const rustEdgeIds = new Set<string>();
|
|
97
|
+
|
|
98
|
+
for (const rustEdge of hubStatus.connectedEdges) {
|
|
99
|
+
rustEdgeIds.add(rustEdge.edgeId);
|
|
100
|
+
const existing = this.edgeStatuses.get(rustEdge.edgeId);
|
|
101
|
+
if (existing) {
|
|
102
|
+
existing.activeTunnels = rustEdge.activeStreams;
|
|
103
|
+
existing.lastHeartbeat = Date.now();
|
|
104
|
+
} else {
|
|
105
|
+
// Missed edgeConnected event — add entry
|
|
106
|
+
this.edgeStatuses.set(rustEdge.edgeId, {
|
|
107
|
+
edgeId: rustEdge.edgeId,
|
|
108
|
+
connected: true,
|
|
109
|
+
publicIp: null,
|
|
110
|
+
activeTunnels: rustEdge.activeStreams,
|
|
111
|
+
lastHeartbeat: Date.now(),
|
|
112
|
+
connectedAt: rustEdge.connectedAt * 1000,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Remove entries for edges no longer connected in Rust (missed edgeDisconnected)
|
|
118
|
+
for (const edgeId of this.edgeStatuses.keys()) {
|
|
119
|
+
if (!rustEdgeIds.has(edgeId)) {
|
|
120
|
+
this.edgeStatuses.delete(edgeId);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
78
125
|
/**
|
|
79
126
|
* Sync allowed edges from the manager to the hub.
|
|
80
127
|
* Call this after creating/deleting/updating edges.
|