2026-02-16 11:25:16 +00:00
|
|
|
import * as plugins from '../../plugins.js';
|
|
|
|
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
|
|
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
|
|
|
|
|
|
|
|
export class RemoteIngressHandler {
|
|
|
|
|
public typedrouter = new plugins.typedrequest.TypedRouter();
|
|
|
|
|
|
|
|
|
|
constructor(private opsServerRef: OpsServer) {
|
|
|
|
|
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
|
|
|
|
|
this.registerHandlers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private registerHandlers(): void {
|
|
|
|
|
// Get all remote ingress edges
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetRemoteIngresses>(
|
|
|
|
|
'getRemoteIngresses',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const manager = this.opsServerRef.dcRouterRef.remoteIngressManager;
|
|
|
|
|
if (!manager) {
|
|
|
|
|
return { edges: [] };
|
|
|
|
|
}
|
2026-02-17 14:17:18 +00:00
|
|
|
// Return edges without secrets, enriched with effective listen ports and breakdown
|
|
|
|
|
const edges = manager.getAllEdges().map((e) => {
|
|
|
|
|
const breakdown = manager.getPortBreakdown(e);
|
|
|
|
|
return {
|
|
|
|
|
...e,
|
|
|
|
|
secret: '********', // Never expose secrets via API
|
|
|
|
|
effectiveListenPorts: manager.getEffectiveListenPorts(e),
|
|
|
|
|
manualPorts: breakdown.manual,
|
|
|
|
|
derivedPorts: breakdown.derived,
|
|
|
|
|
};
|
|
|
|
|
});
|
2026-02-16 11:25:16 +00:00
|
|
|
return { edges };
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Create a new remote ingress edge
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateRemoteIngress>(
|
|
|
|
|
'createRemoteIngress',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const manager = this.opsServerRef.dcRouterRef.remoteIngressManager;
|
|
|
|
|
const tunnelManager = this.opsServerRef.dcRouterRef.tunnelManager;
|
|
|
|
|
|
|
|
|
|
if (!manager) {
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
edge: null as any,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const edge = await manager.createEdge(
|
|
|
|
|
dataArg.name,
|
2026-02-17 10:55:31 +00:00
|
|
|
dataArg.listenPorts || [],
|
2026-02-16 11:25:16 +00:00
|
|
|
dataArg.tags,
|
2026-02-17 14:17:18 +00:00
|
|
|
dataArg.autoDerivePorts ?? true,
|
2026-02-16 11:25:16 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Sync allowed edges with the hub
|
|
|
|
|
if (tunnelManager) {
|
|
|
|
|
await tunnelManager.syncAllowedEdges();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { success: true, edge };
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Delete a remote ingress edge
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteRemoteIngress>(
|
|
|
|
|
'deleteRemoteIngress',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const manager = this.opsServerRef.dcRouterRef.remoteIngressManager;
|
|
|
|
|
const tunnelManager = this.opsServerRef.dcRouterRef.tunnelManager;
|
|
|
|
|
|
|
|
|
|
if (!manager) {
|
|
|
|
|
return { success: false, message: 'RemoteIngress not configured' };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deleted = await manager.deleteEdge(dataArg.id);
|
|
|
|
|
if (deleted && tunnelManager) {
|
|
|
|
|
await tunnelManager.syncAllowedEdges();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: deleted,
|
|
|
|
|
message: deleted ? undefined : 'Edge not found',
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Update a remote ingress edge
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateRemoteIngress>(
|
|
|
|
|
'updateRemoteIngress',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const manager = this.opsServerRef.dcRouterRef.remoteIngressManager;
|
|
|
|
|
const tunnelManager = this.opsServerRef.dcRouterRef.tunnelManager;
|
|
|
|
|
|
|
|
|
|
if (!manager) {
|
|
|
|
|
return { success: false, edge: null as any };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const edge = await manager.updateEdge(dataArg.id, {
|
|
|
|
|
name: dataArg.name,
|
|
|
|
|
listenPorts: dataArg.listenPorts,
|
2026-02-17 14:17:18 +00:00
|
|
|
autoDerivePorts: dataArg.autoDerivePorts,
|
2026-02-16 11:25:16 +00:00
|
|
|
enabled: dataArg.enabled,
|
|
|
|
|
tags: dataArg.tags,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!edge) {
|
|
|
|
|
return { success: false, edge: null as any };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sync allowed edges if enabled status changed
|
|
|
|
|
if (tunnelManager && dataArg.enabled !== undefined) {
|
|
|
|
|
await tunnelManager.syncAllowedEdges();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-17 14:17:18 +00:00
|
|
|
const breakdown = manager.getPortBreakdown(edge);
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
edge: {
|
|
|
|
|
...edge,
|
|
|
|
|
secret: '********',
|
|
|
|
|
effectiveListenPorts: manager.getEffectiveListenPorts(edge),
|
|
|
|
|
manualPorts: breakdown.manual,
|
|
|
|
|
derivedPorts: breakdown.derived,
|
|
|
|
|
},
|
|
|
|
|
};
|
2026-02-16 11:25:16 +00:00
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Regenerate secret for an edge
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RegenerateRemoteIngressSecret>(
|
|
|
|
|
'regenerateRemoteIngressSecret',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const manager = this.opsServerRef.dcRouterRef.remoteIngressManager;
|
|
|
|
|
const tunnelManager = this.opsServerRef.dcRouterRef.tunnelManager;
|
|
|
|
|
|
|
|
|
|
if (!manager) {
|
|
|
|
|
return { success: false, secret: '' };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const secret = await manager.regenerateSecret(dataArg.id);
|
|
|
|
|
if (!secret) {
|
|
|
|
|
return { success: false, secret: '' };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sync allowed edges since secret changed
|
|
|
|
|
if (tunnelManager) {
|
|
|
|
|
await tunnelManager.syncAllowedEdges();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { success: true, secret };
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Get runtime status of all edges
|
|
|
|
|
this.typedrouter.addTypedHandler(
|
|
|
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetRemoteIngressStatus>(
|
|
|
|
|
'getRemoteIngressStatus',
|
|
|
|
|
async (dataArg, toolsArg) => {
|
|
|
|
|
const tunnelManager = this.opsServerRef.dcRouterRef.tunnelManager;
|
|
|
|
|
if (!tunnelManager) {
|
|
|
|
|
return { statuses: [] };
|
|
|
|
|
}
|
|
|
|
|
return { statuses: tunnelManager.getEdgeStatuses() };
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|