UNPKG

lemon-core

Version:
158 lines 7.45 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LambdaNotificationHandler = void 0; /** * `lambda-notification-handler.ts` * - lambda handler to process SNS http/https Notification + Subscriptions. * * * @author Steve Jung <steve@lemoncloud.io> * @date 2019-12-17 initial version via backbone * * @copyright (C) 2019 LemonCloud Co Ltd. - All Rights Reserved. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const engine_1 = require("../../engine/"); const lambda_handler_1 = require("./lambda-handler"); const lambda_web_handler_1 = require("./lambda-web-handler"); const NS = engine_1.$U.NS('HNOT', 'yellow'); // NAMESPACE TO BE PRINTED. /** * class: `LambdaNotificationHandler` * - default Notification Handler via SNS http/https subscription. */ class LambdaNotificationHandler extends lambda_handler_1.LambdaSubHandler { /** * default constructor w/ registering self. */ constructor(lambda, register) { super(lambda, register ? 'notification' : undefined); this.listeners = []; /** * Notification Handler. */ this.handle = (event, context) => __awaiter(this, void 0, void 0, function* () { (0, engine_1._log)(NS, `handle()....`); // _log(NS, '! event =', $U.json(event)); // _log(NS, '> event =', $U.json(event)); const $doReportError = (0, lambda_handler_1.buildReportError)(LambdaNotificationHandler.REPORT_ERROR); // _inf(NS, '! event.headers =', $U.json(event.headers)); // _inf(NS, '! context =', $U.json(context)); (0, engine_1._log)(NS, '! path =', event.path); const id = `${event.path}`; const { param, body } = this.packNotificationParamBody(event); //* call all listeners in parrallel. const asyncNext = (fn, i) => new Promise(resolve => { resolve(fn(id, param, body, context)); }).catch(e => $doReportError(e, null, null, { param, body, i })); const res = yield Promise.all(this.listeners.map(asyncNext)); const ret = (0, lambda_web_handler_1.success)(res.join(',')); return ret; }); // _log(NS, `LambdaNotificationHandler(${register})..`); } /** * add listener. * @param handler */ addListener(handler) { this.listeners.push(handler); } /** * Pack context as `NextContext` * @param event origin lambda event * @param $ctx origin context. */ packContext(event, $ctx) { return __awaiter(this, void 0, void 0, function* () { (0, engine_1._log)(NS, `packContext()....`); // _log(NS, '! event =', $U.json(event)); (0, engine_1._log)(NS, '! $ctx =', engine_1.$U.json($ctx)); const headers = (event && event.headers) || {}; const reqContext = event && event.requestContext; //* - extract original request infor. const clientIp = reqContext && reqContext.identity && reqContext.identity.sourceIp; const requestId = reqContext && reqContext.requestId; const accountId = reqContext && reqContext.accountId; const domain = (reqContext && reqContext.domainName) || headers['Host'] || headers['host']; //* save into headers and returns. const context = { clientIp, requestId, accountId, domain }; return context; }); } /** * pack to notification-param via origin event. * @param event origin lambda event */ packNotificationParamBody(event) { (0, engine_1._log)(NS, `packNotificationParam()....`); // _log(NS, '! event =', $U.json(event)); (0, engine_1._inf)(NS, '! event.headers =', engine_1.$U.json(event.headers)); const headers = (event && event.headers) || {}; const $ctx = event && event.requestContext; const method = ($ctx && $ctx.httpMethod) || event.httpMethod || ''; if (method != 'POST') throw new Error(`.httpMethod (${method}) is not valid`); //* parse message body. const hasRaw = headers['x-amz-sns-rawdelivery'] !== undefined ? true : false; const isRaw = headers['x-amz-sns-rawdelivery'] === 'true' ? true : false; const isBase64Encoded = event.isBase64Encoded; const ctype = `${headers['content-type'] || headers['Content-Type'] || ''}`; const json = (body) => { const text = !body ? '' : typeof body == 'string' ? body : engine_1.$U.json(body); if (text.startsWith('{') && text.endsWith('}')) { try { return JSON.parse(text); } catch (e) { return { text }; } } return { text }; }; const data = json(event.body); //* body must be string formatted json. (0, engine_1._log)(NS, `> data[${ctype}][${isBase64Encoded ? 'base64' : typeof event.body}] =`, engine_1.$U.json(data)); //* prepare param via headers. const param = { snsMessageType: headers['x-amz-sns-message-type'], snsMessageId: headers['x-amz-sns-message-id'], snsTopicArn: headers['x-amz-sns-topic-arn'], snsSubscriptionArn: headers['x-amz-sns-subscription-arn'], // only for Notification. }; const body = hasRaw && isRaw ? Object.assign({}, data) : Object.assign({}, json(data.Message || '')); //* parse message-attribute of SNS if (!isRaw) { if (param.snsMessageType == 'SubscriptionConfirmation') { param.subscribeURL = data.SubscribeURL; param.signature = data.Signature; } else if (data.MessageAttributes) { //* retrieve message-attributes as `param` const attrs = Object.keys(data.MessageAttributes).reduce((O, key) => { const V = data.MessageAttributes[key]; if (!V) return O; O[key] = V.Type == 'Number' ? Number(V.Value) : `${V.Value}`; return O; }, {}); const subject = data.Subject || ''; Object.assign(param, attrs); // merge attributes to param. param.subject = subject; } } //* returns... return { param, body }; } } exports.LambdaNotificationHandler = LambdaNotificationHandler; //* shared config. LambdaNotificationHandler.REPORT_ERROR = lambda_handler_1.LambdaHandler.REPORT_ERROR; //# sourceMappingURL=lambda-notification-handler.js.map