feat(remoteingress): add Remote Ingress hub and management for edge tunnel nodes, including backend managers, tunnel hub integration, opsserver handlers, typedrequest APIs, and web UI
This commit is contained in:
126
ts/remoteingress/classes.tunnel-manager.ts
Normal file
126
ts/remoteingress/classes.tunnel-manager.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import type { IRemoteIngressStatus } from '../../ts_interfaces/data/remoteingress.js';
|
||||
import type { RemoteIngressManager } from './classes.remoteingress-manager.js';
|
||||
|
||||
export interface ITunnelManagerConfig {
|
||||
tunnelPort?: number;
|
||||
targetHost?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the RemoteIngressHub instance and tracks connected edge statuses.
|
||||
*/
|
||||
export class TunnelManager {
|
||||
private hub: InstanceType<typeof plugins.remoteingress.RemoteIngressHub>;
|
||||
private manager: RemoteIngressManager;
|
||||
private config: ITunnelManagerConfig;
|
||||
private edgeStatuses: Map<string, IRemoteIngressStatus> = new Map();
|
||||
|
||||
constructor(manager: RemoteIngressManager, config: ITunnelManagerConfig = {}) {
|
||||
this.manager = manager;
|
||||
this.config = config;
|
||||
this.hub = new plugins.remoteingress.RemoteIngressHub();
|
||||
|
||||
// Listen for edge connect/disconnect events
|
||||
this.hub.on('edgeConnected', (data: { edgeId: string }) => {
|
||||
const existing = this.edgeStatuses.get(data.edgeId);
|
||||
this.edgeStatuses.set(data.edgeId, {
|
||||
edgeId: data.edgeId,
|
||||
connected: true,
|
||||
publicIp: existing?.publicIp ?? null,
|
||||
activeTunnels: 0,
|
||||
lastHeartbeat: Date.now(),
|
||||
connectedAt: Date.now(),
|
||||
});
|
||||
});
|
||||
|
||||
this.hub.on('edgeDisconnected', (data: { edgeId: string }) => {
|
||||
const existing = this.edgeStatuses.get(data.edgeId);
|
||||
if (existing) {
|
||||
existing.connected = false;
|
||||
existing.activeTunnels = 0;
|
||||
}
|
||||
});
|
||||
|
||||
this.hub.on('streamOpened', (data: { edgeId: string; streamId: number }) => {
|
||||
const existing = this.edgeStatuses.get(data.edgeId);
|
||||
if (existing) {
|
||||
existing.activeTunnels++;
|
||||
existing.lastHeartbeat = Date.now();
|
||||
}
|
||||
});
|
||||
|
||||
this.hub.on('streamClosed', (data: { edgeId: string; streamId: number }) => {
|
||||
const existing = this.edgeStatuses.get(data.edgeId);
|
||||
if (existing && existing.activeTunnels > 0) {
|
||||
existing.activeTunnels--;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the tunnel hub and load allowed edges.
|
||||
*/
|
||||
public async start(): Promise<void> {
|
||||
await this.hub.start({
|
||||
tunnelPort: this.config.tunnelPort ?? 8443,
|
||||
targetHost: this.config.targetHost ?? '127.0.0.1',
|
||||
});
|
||||
|
||||
// Send allowed edges to the hub
|
||||
await this.syncAllowedEdges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the tunnel hub.
|
||||
*/
|
||||
public async stop(): Promise<void> {
|
||||
await this.hub.stop();
|
||||
this.edgeStatuses.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync allowed edges from the manager to the hub.
|
||||
* Call this after creating/deleting/updating edges.
|
||||
*/
|
||||
public async syncAllowedEdges(): Promise<void> {
|
||||
const edges = this.manager.getAllowedEdges();
|
||||
await this.hub.updateAllowedEdges(edges);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get runtime statuses for all known edges.
|
||||
*/
|
||||
public getEdgeStatuses(): IRemoteIngressStatus[] {
|
||||
return Array.from(this.edgeStatuses.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status for a specific edge.
|
||||
*/
|
||||
public getEdgeStatus(edgeId: string): IRemoteIngressStatus | undefined {
|
||||
return this.edgeStatuses.get(edgeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of connected edges.
|
||||
*/
|
||||
public getConnectedCount(): number {
|
||||
let count = 0;
|
||||
for (const status of this.edgeStatuses.values()) {
|
||||
if (status.connected) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of active tunnels across all edges.
|
||||
*/
|
||||
public getTotalActiveTunnels(): number {
|
||||
let total = 0;
|
||||
for (const status of this.edgeStatuses.values()) {
|
||||
total += status.activeTunnels;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user