feat(dcrouter): add managed local dcrouter mode with status controls and gateway integration

This commit is contained in:
2026-05-09 20:04:02 +00:00
parent 595e84cdb6
commit dc37a71802
19 changed files with 873 additions and 31 deletions
+2
View File
@@ -23,6 +23,7 @@ export class OpsServer {
public backupsHandler!: handlers.BackupsHandler;
public schedulesHandler!: handlers.SchedulesHandler;
public settingsHandler!: handlers.SettingsHandler;
public managedDcRouterHandler!: handlers.ManagedDcRouterHandler;
public logsHandler!: handlers.LogsHandler;
public workspaceHandler!: handlers.WorkspaceHandler;
public appStoreHandler!: handlers.AppStoreHandler;
@@ -66,6 +67,7 @@ export class OpsServer {
this.backupsHandler = new handlers.BackupsHandler(this);
this.schedulesHandler = new handlers.SchedulesHandler(this);
this.settingsHandler = new handlers.SettingsHandler(this);
this.managedDcRouterHandler = new handlers.ManagedDcRouterHandler(this);
this.logsHandler = new handlers.LogsHandler(this);
this.workspaceHandler = new handlers.WorkspaceHandler(this);
this.appStoreHandler = new handlers.AppStoreHandler(this);
+1
View File
@@ -10,6 +10,7 @@ export * from './network.handler.ts';
export * from './backups.handler.ts';
export * from './schedules.handler.ts';
export * from './settings.handler.ts';
export * from './managed-dcrouter.handler.ts';
export * from './logs.handler.ts';
export * from './workspace.handler.ts';
export * from './appstore.handler.ts';
@@ -0,0 +1,59 @@
import * as plugins from '../../plugins.ts';
import type { OpsServer } from '../classes.opsserver.ts';
import * as interfaces from '../../../ts_interfaces/index.ts';
import { requireAdminIdentity } from '../helpers/guards.ts';
export class ManagedDcRouterHandler {
public typedrouter = new plugins.typedrequest.TypedRouter();
constructor(private opsServerRef: OpsServer) {
this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
this.registerHandlers();
}
private registerHandlers(): void {
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetManagedDcRouterStatus>(
'getManagedDcRouterStatus',
async (dataArg) => {
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
const status = await this.opsServerRef.oneboxRef.managedDcRouter.getStatus();
return { status };
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StartManagedDcRouter>(
'startManagedDcRouter',
async (dataArg) => {
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
const status = await this.opsServerRef.oneboxRef.managedDcRouter.start();
return { status };
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_StopManagedDcRouter>(
'stopManagedDcRouter',
async (dataArg) => {
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
const status = await this.opsServerRef.oneboxRef.managedDcRouter.stop();
return { status };
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RestartManagedDcRouter>(
'restartManagedDcRouter',
async (dataArg) => {
await requireAdminIdentity(this.opsServerRef.adminHandler, dataArg);
const status = await this.opsServerRef.oneboxRef.managedDcRouter.restart();
return { status };
},
),
);
}
}
+22 -3
View File
@@ -18,10 +18,17 @@ export class SettingsHandler {
const cloudflareToken = await db.getSecretSetting('cloudflareToken');
const dcrouterGatewayApiToken = await db.getSecretSetting('dcrouterGatewayApiToken');
const settingsMap = db.getAllSettings();
const managedDcRouter = this.opsServerRef.oneboxRef.managedDcRouter;
return {
cloudflareToken: cloudflareToken || '',
cloudflareZoneId: settingsMap['cloudflareZoneId'] || '',
dcrouterMode: managedDcRouter.getMode(),
dcrouterManagedImage: managedDcRouter.getImage(),
dcrouterManagedOpsPort: managedDcRouter.getOpsPort(),
dcrouterManagedHttpPort: managedDcRouter.getHttpPort(),
dcrouterManagedHttpsPort: managedDcRouter.getHttpsPort(),
dcrouterManagedDataDir: managedDcRouter.getDataDir(),
dcrouterGatewayUrl: settingsMap['dcrouterGatewayUrl'] || '',
dcrouterGatewayApiToken: dcrouterGatewayApiToken || '',
dcrouterGatewayClientId: settingsMap['dcrouterGatewayClientId'] || settingsMap['dcrouterWorkHosterId'] || '',
@@ -69,8 +76,8 @@ export class SettingsHandler {
}
if (this.hasExternalGatewaySetting(updates)) {
this.refreshExternalGateway().catch((error) => {
logger.warn(`External gateway settings refresh failed: ${getErrorMessage(error)}`);
this.refreshDcRouterGateway().catch((error) => {
logger.warn(`dcrouter gateway settings refresh failed: ${getErrorMessage(error)}`);
});
}
@@ -105,6 +112,12 @@ export class SettingsHandler {
private hasExternalGatewaySetting(settings: Partial<interfaces.data.ISettings>): boolean {
return [
'dcrouterMode',
'dcrouterManagedImage',
'dcrouterManagedOpsPort',
'dcrouterManagedHttpPort',
'dcrouterManagedHttpsPort',
'dcrouterManagedDataDir',
'dcrouterGatewayUrl',
'dcrouterGatewayApiToken',
'dcrouterGatewayClientId',
@@ -114,8 +127,14 @@ export class SettingsHandler {
].some((key) => Object.prototype.hasOwnProperty.call(settings, key));
}
private async refreshExternalGateway(): Promise<void> {
private async refreshDcRouterGateway(): Promise<void> {
const onebox = this.opsServerRef.oneboxRef;
if (onebox.managedDcRouter.getMode() === 'managed') {
await onebox.managedDcRouter.restart();
} else {
await onebox.managedDcRouter.stop();
}
await onebox.externalGateway.syncDomains();
const services = onebox.database.getAllServices().filter((service) => service.domain);