UNPKG

@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

136 lines (112 loc) 5.04 kB
import express from 'express'; import _ from 'lodash'; import { Creative, CreativeResponse } from '../../../api/core/creative'; import { PluginProperty, PluginPropertyResponse } from '../../../api/core/plugin/PluginPropertyInterface'; import { EmailRendererPluginResponse } from '../../../api/plugin/emailtemplaterenderer/EmailRendererPluginResponse'; import { EmailRenderRequest } from '../../../api/plugin/emailtemplaterenderer/EmailRendererRequestInterface'; import { BasePlugin, PropertiesWrapper } from '../../common'; export interface EmailRendererBaseInstanceContext { creative: Creative; properties: PropertiesWrapper; } export abstract class EmailRendererPlugin< T extends EmailRendererBaseInstanceContext = EmailRendererBaseInstanceContext, > extends BasePlugin<T> { instanceContext: Promise<T>; constructor(enableThrottling = false) { super(enableThrottling); // We init the specific route to listen for email contents requests this.initEmailContents(); this.setErrorHandler(); } // Helper to fetch the creative resource with caching async fetchCreative(id: string, forceReload = false): Promise<Creative> { const response = await super.requestGatewayHelper<CreativeResponse>( 'GET', `${this.outboundPlatformUrl}/v1/creatives/${id}`, undefined, { 'force-reload': forceReload }, ); this.logger.debug(`Fetched Creative: ${id} - ${JSON.stringify(response.data)}`); return response.data; } // Method to build an instance context // To be overriden to get a cutom behavior async fetchCreativeProperties(id: string, forceReload = false): Promise<PluginProperty[]> { const response = await super.requestGatewayHelper<PluginPropertyResponse>( 'GET', `${this.outboundPlatformUrl}/v1/creatives/${id}/renderer_properties`, undefined, { 'force-reload': forceReload }, ); this.logger.debug(`Fetched Email Templates Properties: ${id} - ${JSON.stringify(response.data)}`); return response.data; } // Method to process an Activity Analysis // This is a default provided implementation protected async instanceContextBuilder(creativeId: string, forceReload = false): Promise<T> { const creativeP = this.fetchCreative(creativeId, forceReload); const creativePropsP = this.fetchCreativeProperties(creativeId, forceReload); const results = await Promise.all([creativeP, creativePropsP]); const creative = results[0]; const creativeProps = results[1]; const context = { creative: creative, properties: new PropertiesWrapper(creativeProps), } as T; return context; } protected async getInstanceContext(creativeId: string, forceReload = false): Promise<T> { if (!this.pluginCache.get(creativeId) || forceReload) { void this.pluginCache.put( creativeId, this.instanceContextBuilder(creativeId, forceReload).catch((err) => { this.logger.error(`Error while caching instance context: ${(err as Error).message}`); this.pluginCache.del(creativeId); throw err; }), this.getInstanceContextCacheExpiration(), ); } return this.pluginCache.get(creativeId) as Promise<T>; } // To be overriden by the Plugin to get a custom behavior protected abstract onEmailContents( request: EmailRenderRequest, instanceContext: T, ): Promise<EmailRendererPluginResponse>; private initEmailContents(): void { this.app.post( '/v1/email_contents', this.asyncMiddleware(async (req: express.Request, res: express.Response) => { if (!this.httpIsReady()) { const msg = { error: 'Plugin not initialized', }; this.logger.error('POST /v1/email_contents : %s', JSON.stringify(msg)); return res.status(500).json(msg); } else if (!req.body || _.isEmpty(req.body)) { const msg = { error: 'Missing request body', }; this.logger.error('POST /v1/email_contents : %s', JSON.stringify(msg)); return res.status(500).json(msg); } else { this.logger.debug(`POST /v1/email_contents ${JSON.stringify(req.body)}`); const emailRenderRequest = req.body as EmailRenderRequest; if (!this.onEmailContents) { const errMsg = 'No Email Renderer listener registered!'; this.logger.error(errMsg); return res.status(500).send({ error: errMsg }); } // We flush the Plugin Gateway cache during previews const forceReload = emailRenderRequest.context === 'PREVIEW' || emailRenderRequest.context === 'STAGE'; const instanceContext = await this.getInstanceContext(emailRenderRequest.creative_id, forceReload); const response = await this.onEmailContents(emailRenderRequest, instanceContext); this.logger.debug(`Returning: ${JSON.stringify(response)}`); return res.status(200).send(JSON.stringify(response)); } }), ); } }