lemon-core
Version:
Lemon Serverless Micro-Service Platform
158 lines • 7.45 kB
JavaScript
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
;