Files
coreflow/ts/coreflow.connector.externalgateway.ts

138 lines
3.8 KiB
TypeScript

import * as plugins from './coreflow.plugins.js';
import { Coreflow } from './coreflow.classes.coreflow.js';
import { logger } from './coreflow.logging.js';
export interface IExternalGatewayConfig {
url: string;
apiToken: string;
workHosterType: 'cloudly';
workHosterId: string;
targetHost?: string;
targetPort?: number;
}
interface IWorkAppRouteSyncResult {
success: boolean;
action?: 'created' | 'updated' | 'deleted' | 'unchanged';
routeId?: string;
message?: string;
}
interface IDcRouterCertificateExport {
success: boolean;
cert?: {
id: string;
domainName: string;
created: number;
validUntil: number;
privateKey: string;
publicKey: string;
csr: string;
};
message?: string;
}
export class ExternalGatewayConnector {
constructor(public coreflowRef: Coreflow) {}
public isConfigured(configArg?: IExternalGatewayConfig): configArg is IExternalGatewayConfig {
return Boolean(
configArg?.url
&& configArg.apiToken
&& configArg.workHosterId
&& configArg.targetHost
&& configArg.targetPort,
);
}
public async syncWorkAppRoute(optionsArg: {
config: IExternalGatewayConfig | undefined;
service: plugins.servezoneInterfaces.data.IService;
hostname: string;
}): Promise<void> {
const config = optionsArg.config;
if (!this.isConfigured(config)) return;
const result = await this.fireDcRouterRequest<IWorkAppRouteSyncResult>(
config,
'syncWorkAppRoute',
{
ownership: {
workHosterType: 'cloudly',
workHosterId: config.workHosterId,
workAppId: optionsArg.service.id || optionsArg.service.data.name,
hostname: optionsArg.hostname,
},
route: {
name: this.routeName(optionsArg.hostname),
match: {
ports: [443],
domains: [optionsArg.hostname],
},
action: {
type: 'forward',
targets: [{ host: config.targetHost!, port: config.targetPort! }],
tls: {
mode: 'terminate',
certificate: 'auto',
},
websocket: {
enabled: true,
},
},
},
enabled: true,
},
);
if (!result.success) {
throw new Error(result.message || `dcrouter route sync failed for ${optionsArg.hostname}`);
}
logger.log('success', `external gateway route ${result.action || 'synced'} for ${optionsArg.hostname}`);
}
public async exportCertificateForDomain(
configArg: IExternalGatewayConfig | undefined,
hostnameArg: string,
): Promise<plugins.tsclass.network.ICert | undefined> {
if (!configArg?.url || !configArg.apiToken) return undefined;
const result = await this.fireDcRouterRequest<IDcRouterCertificateExport>(
configArg,
'exportCertificate',
{ domain: hostnameArg },
);
if (!result.success || !result.cert) return undefined;
return {
id: result.cert.id,
domainName: result.cert.domainName,
created: result.cert.created,
validUntil: result.cert.validUntil,
privateKey: result.cert.privateKey,
publicKey: result.cert.publicKey,
csr: result.cert.csr,
};
}
private routeName(hostnameArg: string): string {
return `cloudly-${hostnameArg.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-|-$/g, '')}`;
}
private async fireDcRouterRequest<TResponse>(
configArg: IExternalGatewayConfig,
methodArg: string,
requestDataArg: Record<string, unknown>,
): Promise<TResponse> {
const typedRequest = new plugins.typedrequest.TypedRequest<any>(
`${configArg.url.replace(/\/+$/, '')}/typedrequest`,
methodArg,
);
return await typedRequest.fire({
...requestDataArg,
apiToken: configArg.apiToken,
}) as TResponse;
}
}