@mediarithmics/plugins-nodejs-sdk
Version:
This is the mediarithmics nodejs to help plugin developers bootstrapping their plugin without having to deal with most of the plugin boilerplate
159 lines (134 loc) • 5.21 kB
text/typescript
/* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/unbound-method */
import express from 'express';
import _ from 'lodash';
import { PluginProperty, PluginPropertyResponse } from '../../api/core/plugin/PluginPropertyInterface';
import { BasePlugin, PropertiesWrapper } from '../common';
import {
CustomAction,
CustomActionPluginResponse,
CustomActionRequest,
CustomActionResponse,
} from './CustomActionInterface';
export interface CustomActionBaseInstanceContext {
customAction: CustomAction;
properties: PropertiesWrapper;
}
export abstract class CustomActionBasePlugin extends BasePlugin<CustomActionBaseInstanceContext> {
constructor(enableThrottling = false) {
super(enableThrottling);
this.initCustomAction();
this.setErrorHandler();
}
/**
*
* @param customActionId
*/
async fetchCustomAction(customActionId: string): Promise<CustomAction> {
const customActionResponse = await super.requestGatewayHelper<CustomActionResponse>(
'GET',
`${this.outboundPlatformUrl}/v1/scenario_custom_actions/${customActionId}`,
);
this.logger.debug(`Fetched Custom Action: ${customActionId} - %j`, customActionResponse.data);
return customActionResponse.data;
}
/**
*
* @param customActionId
*/
async fetchCustomActionProperties(customActionId: string): Promise<PluginProperty[]> {
const customActionPropertiesResponse = await super.requestGatewayHelper<PluginPropertyResponse>(
'GET',
`${this.outboundPlatformUrl}/v1/scenario_custom_actions/${customActionId}/properties`,
);
this.logger.debug(`Fetched Custom Action Properties: ${customActionId} - %j`, customActionPropertiesResponse.data);
return customActionPropertiesResponse.data;
}
protected async instanceContextBuilder(customActionId: string): Promise<CustomActionBaseInstanceContext> {
const [customAction, properties] = await Promise.all([
this.fetchCustomAction(customActionId),
this.fetchCustomActionProperties(customActionId),
]);
const context: CustomActionBaseInstanceContext = {
customAction: customAction,
properties: new PropertiesWrapper(properties),
};
return context;
}
/**
*
* @param request
* @param instanceContext
*/
protected abstract onCustomActionCall(
request: CustomActionRequest,
instanceContext: CustomActionBaseInstanceContext,
): Promise<CustomActionPluginResponse>;
protected async getInstanceContext(customActionId: string): Promise<CustomActionBaseInstanceContext> {
if (!this.pluginCache.get(customActionId)) {
void this.pluginCache.put(
customActionId,
this.instanceContextBuilder(customActionId).catch((err) => {
this.logger.error(`Error while caching instance context: ${(err as Error).message}`);
this.pluginCache.del(customActionId);
throw err;
}),
this.getInstanceContextCacheExpiration(),
);
}
return this.pluginCache.get(customActionId) as Promise<CustomActionBaseInstanceContext>;
}
private emptyBodyFilter(req: express.Request, res: express.Response, next: express.NextFunction) {
if (!req.body || _.isEmpty(req.body)) {
const msg = {
error: 'Missing request body',
};
this.logger.error(`POST /v1/${req.url} : %j`, msg);
res.status(500).json(msg);
} else {
next();
}
}
private initCustomAction(): void {
// route /v1/scenario_custom_actions
this.app.post(
'/v1/scenario_custom_actions',
this.emptyBodyFilter,
async (req: express.Request, res: express.Response) => {
try {
this.logger.debug(`POST /v1/scenario_custom_actions %j`, req.body);
const request = req.body as CustomActionRequest;
if (!this.onCustomActionCall) {
throw new Error('No Scenario Custom Action listener registered!');
}
const instanceContext = await this.getInstanceContext(request.custom_action_id);
const response = await this.onCustomActionCall(request, instanceContext);
this.logger.debug(`CustomActionId: ${request.custom_action_id} - Plugin impl returned: %j`, response);
const pluginResponse: CustomActionPluginResponse = {
status: response.status,
};
let statusCode;
switch (response.status) {
case 'ok':
statusCode = 200;
break;
case 'ko':
statusCode = 500;
break;
default:
statusCode = 500;
}
this.logger.debug(`CustomActionId: ${request.custom_action_id} - Returning : ${statusCode} - %j`, response);
return res.status(statusCode).send(JSON.stringify(pluginResponse));
} catch (err) {
this.logger.error(
`Something bad happened : ${(err as Error).message} - ${
(err as Error).stack ? ((err as Error).stack as string) : 'stack undefined'
}`,
);
return res.status(500).send({ status: 'error', message: `${(err as Error).message}` });
}
},
);
}
}