UNPKG

eip-cloud-services

Version:

Houses a collection of helpers for connecting with Cloud services.

114 lines (97 loc) 5.17 kB
const { CloudFrontClient, CreateInvalidationCommand } = require ( '@aws-sdk/client-cloudfront' ); const { GoogleAuth } = require ( 'google-auth-library' ); const { initialiseGoogleAuth } = require ( './gcp' ); const fs = require ( 'fs' ); let config = {}; const configDirPath = `${ process.cwd ()}/config`; if ( fs.existsSync ( configDirPath ) && fs.statSync ( configDirPath ).isDirectory () ) { config = require ( 'config' ); // require the config directory if it exists } const packageJson = require ( '../package.json' ); const { cwd } = require ( 'process' ); const { log } = config?.s3?.logsFunction ? require ( `${ cwd ()}/${config.s3.logsFunction}` ) : console; const redis = require('./redis'); /** * Create a CDN invalidation for the specified key(s) and environment. * * @param {string} cdn - The CDN provider to be used (e.g., 'google', 'amazon'). * @param {string|string[]} key - The key(s) representing the file(s) to invalidate. * @param {string} environment - The environment (e.g., 'staging', 'production'). * @returns {Promise<void>} A promise that resolves when the invalidation is created. * @description Creates a CDN invalidation for the specified key(s) in the specified environment. * - The `cdn` parameter specifies the CDN provider (e.g., 'google', 'amazon'). * - The `key` parameter can be a single string or an array of strings representing the file(s) to invalidate. * - The `environment` parameter specifies the environment (e.g., 'staging', 'production'). * - The function validates the `key` argument and throws an error if it is not a string or an array of strings. * - The function constructs the invalidation paths based on the provided keys. * - The CDN client (either Google or Amazon CloudFront) is used to send the invalidation command. * - Returns a promise that resolves when the invalidation is created. * - The function initializes Google Auth if Google CDN is used. * - If Google CDN is used, the function makes a POST request to Google's 'invalidateCache' endpoint for each provided path. * - If Amazon CloudFront is used, the function sends an invalidation command to CloudFront. * - If the CDN type is not 'google' or 'amazon', the function throws an error. * - The function uses the 'config' module to access the CDN settings based on the CDN provider and environment. */ exports.createInvalidation = async ( cdn, key, environment = 'production' ) => { const cdnSettings = config.cdn[ cdn ][ environment ]; // Ensure paths is an array and sanitize paths const paths = ( Array.isArray ( key ) ? key : [ key ] ) .filter ( item => typeof item === 'string' ) .map ( item => item.charAt ( 0 ) !== '/' ? '/' + item : item ); if ( paths.length === 0 ) { throw new Error ( 'Invalid key argument. Expected a string or an array of strings.' ); } if ( config?.redis?.host ) { const redisKey = `cdn-invalidation:${cdn}:${environment}:${key}`; const redisValue = await redis.get(redisKey); if(redisValue) { if ( config.cdn.log ) log ( `CDN [INVALIDATE]: Invalidation already in progress - skipping: ${paths.map ( path => `https://${cdn}${environment !== 'production' ? '-test' : ''}.eip.telegraph.co.uk${path}` ).join ( ', ' )}\n` ); await redis.increment(redisKey); return; } else{ await redis.set(redisKey, 1, cdnSettings.type === 'google' ? 300 : 120); // 5 minutes for google, 2 minutes for amazon } } if ( config.cdn.log ) log ( `CDN [INVALIDATE]: ${paths.map ( path => `https://${cdn}${environment !== 'production' ? '-test' : ''}.eip.telegraph.co.uk${path}` ).join ( ', ' )}\n` ); switch ( cdnSettings.type ) { case 'google': await invalidateGoogleCDN ( cdnSettings, paths ); break; case 'amazon': await invalidateAmazonCDN ( cdnSettings, paths ); break; default: throw new Error ( `Invalid cdn type: ${cdnSettings.type}` ); } }; async function invalidateGoogleCDN ( cdnSettings, paths ) { await initialiseGoogleAuth (); const auth = new GoogleAuth ( { scopes: 'https://www.googleapis.com/auth/cloud-platform' } ); const client = await auth.getClient (); const url = `https://compute.googleapis.com/compute/v1/projects/${cdnSettings.projectId}/global/urlMaps/${cdnSettings.urlMapName}/invalidateCache`; const headers = await client.getRequestHeaders ( url ); await Promise.all ( paths.map ( path => fetch ( url, { method: 'POST', headers, body: JSON.stringify ( { path } ) } ) ) ); } async function invalidateAmazonCDN ( cdnSettings, paths ) { const client = new CloudFrontClient (); const command = new CreateInvalidationCommand ( { DistributionId: cdnSettings.distributionId, InvalidationBatch: { CallerReference: `${packageJson.name}-${Date.now ()}`, Paths: { Quantity: paths.length, Items: paths, }, }, } ); await client.send ( command ); }