127 lines
3.5 KiB
TypeScript
127 lines
3.5 KiB
TypeScript
|
|
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;
|
||
|
|
}
|
||
|
|
}
|