Files
cloudly/ts/manager.platform/classes.platformmanager.ts
T

229 lines
8.6 KiB
TypeScript
Raw Normal View History

2026-04-28 12:18:12 +00:00
import type { Cloudly } from '../classes.cloudly.js';
import * as plugins from '../plugins.js';
import { PlatformBinding } from './classes.platformbinding.js';
import { PlatformProviderConfig } from './classes.platformproviderconfig.js';
export class CloudlyPlatformManager {
public typedrouter = new plugins.typedrequest.TypedRouter();
public cloudlyRef: Cloudly;
public capabilities: plugins.servezoneInterfaces.platform.IPlatformCapability[] = [
{ id: 'email', title: 'Email', accessMode: 'rpc', defaultProviderType: 'cloudly' },
{ id: 'sms', title: 'SMS', accessMode: 'rpc', defaultProviderType: 'cloudly' },
{ id: 'pushnotification', title: 'Push Notifications', accessMode: 'rpc', defaultProviderType: 'cloudly' },
{ id: 'letter', title: 'Letters', accessMode: 'rpc', defaultProviderType: 'cloudly' },
{ id: 'ai', title: 'AI', accessMode: 'rpc', defaultProviderType: 'cloudly' },
{ id: 'database', title: 'Database', accessMode: 'binding', defaultProviderType: 'docker' },
{ id: 'objectstorage', title: 'Object Storage', accessMode: 'binding', defaultProviderType: 's3' },
{ id: 'logging', title: 'Logging', accessMode: 'sidecar', defaultProviderType: 'corelog' },
{ id: 'backup', title: 'Backup', accessMode: 'internal', defaultProviderType: 'corebackup' },
{ id: 'sip', title: 'SIP', accessMode: 'rpc', defaultProviderType: 'cloudly' },
];
get db() {
return this.cloudlyRef.mongodbConnector.smartdataDb;
}
public CPlatformProviderConfig = plugins.smartdata.setDefaultManagerForDoc(
this,
PlatformProviderConfig,
);
public CPlatformBinding = plugins.smartdata.setDefaultManagerForDoc(this, PlatformBinding);
constructor(cloudlyRefArg: Cloudly) {
this.cloudlyRef = cloudlyRefArg;
this.cloudlyRef.typedrouter.addTypedRouter(this.typedrouter);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_GetPlatformDesiredState>(
'getPlatformDesiredState',
async (requestData) => {
await this.passValidIdentity(requestData);
return await this.getPlatformDesiredState();
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_GetPlatformCapabilities>(
'getPlatformCapabilities',
async (requestData) => {
await this.passValidIdentity(requestData);
return {
capabilities: this.capabilities,
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_GetPlatformProviderConfigs>(
'getPlatformProviderConfigs',
async (requestData) => {
await this.passValidIdentity(requestData);
const query = requestData.capability ? { capability: requestData.capability } : {};
return {
providerConfigs: await this.getProviderConfigs(query),
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_UpsertPlatformProviderConfig>(
'upsertPlatformProviderConfig',
async (requestData) => {
await this.passAdminIdentity(requestData);
const providerConfig = await PlatformProviderConfig.upsertProviderConfig(
requestData.providerConfig,
);
return {
providerConfig: await providerConfig.createSavableObject(),
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_DeletePlatformProviderConfigById>(
'deletePlatformProviderConfigById',
async (requestData) => {
await this.passAdminIdentity(requestData);
const providerConfig = await PlatformProviderConfig.getInstance({
id: requestData.providerConfigId,
});
if (providerConfig) {
await providerConfig.delete();
}
return {
success: true,
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_GetPlatformBindings>(
'getPlatformBindings',
async (requestData) => {
await this.passValidIdentity(requestData);
return {
bindings: await this.getBindings({
...(requestData.serviceId ? { serviceId: requestData.serviceId } : {}),
...(requestData.capability ? { capability: requestData.capability } : {}),
}),
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_UpsertPlatformBinding>(
'upsertPlatformBinding',
async (requestData) => {
await this.passAdminIdentity(requestData);
const binding = await PlatformBinding.upsertBinding(requestData.binding);
return {
binding: await binding.createSavableObject(),
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_UpdatePlatformBindingStatus>(
'updatePlatformBindingStatus',
async (requestData) => {
await this.passAdminOrClusterIdentity(requestData);
const binding = await PlatformBinding.getInstance({
id: requestData.bindingId,
});
if (!binding) {
throw new plugins.typedrequest.TypedResponseError(
`Platform binding ${requestData.bindingId} not found`,
);
}
binding.status = requestData.status;
binding.updatedAt = Date.now();
if (requestData.endpoints) {
binding.endpoints = requestData.endpoints;
}
if (requestData.credentials) {
binding.credentials = requestData.credentials;
}
if (requestData.errorText !== undefined) {
binding.errorText = requestData.errorText;
}
await binding.save();
return {
binding: await binding.createSavableObject(),
};
},
),
);
this.typedrouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.platform.IReq_Any_Cloudly_DeletePlatformBindingById>(
'deletePlatformBindingById',
async (requestData) => {
await this.passAdminIdentity(requestData);
const binding = await PlatformBinding.getInstance({
id: requestData.bindingId,
});
if (binding) {
await binding.delete();
}
return {
success: true,
};
},
),
);
}
public async start() {}
public async stop() {}
public async getPlatformDesiredState() {
return {
capabilities: this.capabilities,
providerConfigs: await this.getProviderConfigs(),
bindings: await this.getBindings(),
};
}
public async getProviderConfigs(queryArg: Record<string, unknown> = {}) {
const providerConfigs = await this.CPlatformProviderConfig.getInstances(queryArg);
return await Promise.all(
providerConfigs.map((providerConfig) => providerConfig.createSavableObject()),
);
}
public async getBindings(queryArg: Record<string, unknown> = {}) {
const bindings = await this.CPlatformBinding.getInstances(queryArg);
return await Promise.all(bindings.map((binding) => binding.createSavableObject()));
}
private async passValidIdentity(requestData: { identity: plugins.servezoneInterfaces.data.IIdentity }) {
await plugins.smartguard.passGuardsOrReject(requestData, [
this.cloudlyRef.authManager.validIdentityGuard,
]);
}
private async passAdminIdentity(requestData: { identity: plugins.servezoneInterfaces.data.IIdentity }) {
await plugins.smartguard.passGuardsOrReject(requestData, [
this.cloudlyRef.authManager.adminIdentityGuard,
]);
}
private async passAdminOrClusterIdentity(requestData: {
identity: plugins.servezoneInterfaces.data.IIdentity;
}) {
await this.passValidIdentity(requestData);
if (requestData.identity.role !== 'admin' && requestData.identity.role !== 'cluster') {
throw new plugins.typedrequest.TypedResponseError('identity must be admin or cluster');
}
}
}