lemon-core
Version:
Lemon Serverless Micro-Service Platform
220 lines • 8.6 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.FunctionHandler = exports.FunctionSubHandler = void 0;
/**
* `lambda-handler.ts`
* - main lambda handler.
*
*
* @author Ian Kim <ian@lemoncloud.io>
* @date 2023-10-30 initial version
*
* @copyright (C) lemoncloud.io 2023 - All Rights Reserved.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const engine_1 = require("../../engine");
const test_helper_1 = require("../../common/test-helper");
const NS = engine_1.$U.NS('FUNC', 'green'); // NAMESPACE TO BE PRINTED.
class FunctionSubHandler {
constructor(functions, type) {
if (!functions)
throw new Error('@functions (functions-handler) is required!');
this.functions = functions;
this.type = type;
if (functions && type)
functions.setHandler(type, this);
}
}
exports.FunctionSubHandler = FunctionSubHandler;
/**
* build reprot-error function in safe.
*
* @param isReport flag to report-error via sns
* @return the last error message
*/
const buildReportError = (isReport) => (e, ctx, req, data) => {
return (isReport ? (0, engine_1.doReportError)(e, ctx, req, data) : Promise.resolve(data))
.then(() => (0, test_helper_1.GETERR)(e))
.catch(test_helper_1.GETERR);
};
/**
* class: `LambdaHandler`
* - general lambda handler so that routes to proper target handlers.
*/
class FunctionHandler {
//! protected constructor.
constructor(config) {
//! handler map.
this._map = {};
//! Find Service By Event
this.findService = (ctx) => {
const headers = (ctx && ctx.headers) || {};
(0, engine_1._log)(NS, `> headers =`, engine_1.$U.json(headers));
//! check if AZURE SB TOPICS Notification Subscription -> notification controller.
if (ctx.invocationId) {
for (const binding of ctx.bindingDefinitions) {
if (binding.type === 'httpTrigger') {
return 'web';
}
else {
if (binding.type === 'serviceBusTrigger' && binding.name === 'queue') {
return 'sqs';
}
if (binding.type === 'serviceBusTrigger' && binding.name === 'topic') {
return 'sns';
}
}
}
}
else {
if (ctx.requestContext && ctx.pathParameters !== undefined) {
return 'web';
}
}
};
this.config = config;
}
/**
* set service lambda handler.
* @param type name of type
* @param handler handler of service
*/
setHandler(type, handler) {
let key = `${type || ''}`.toLowerCase().trim();
key = key === 'dynamo-stream' ? 'dds' : key;
// console.info(`! set-handler[${type}] =`, typeof handler);
if (key)
this._map[key] = handler;
}
/**
* decode event to proper handler.
* - NOTE! - returns promised results with `async`
*
* @returns boolean
*/
handle(ctx, req) {
return __awaiter(this, void 0, void 0, function* () {
if (!ctx)
throw new Error('@ctx is required!');
//! Check API parameters.
const main = (ctx, req, callback) => {
const type = this.findService(ctx);
(0, engine_1._log)(NS, `main(${type})...`);
const handler = this._map[type];
if (handler && typeof handler == 'function') {
//! low level handler function.
return handler(ctx, req, callback);
}
else if (handler && typeof handler == 'object') {
//! must be `LambdaHandlerService`.
const $svc = handler;
return $svc.handle(ctx, req);
}
//! raise error if not found.
(0, engine_1._inf)(NS, `WARN! unknown[${type}].event =`, engine_1.$U.json(event));
callback && callback(new Error(`400 UNKNOWN - service:${type}`));
};
//! call promised.
const promise = (main, ctx, req) => new Promise((resolve, reject) => {
try {
let resolved = false;
const R = main(ctx, req, (error, result) => {
error && (0, engine_1._err)(NS, '! err@cb =', error);
// !error && _inf(NS, '! res@cb =', result);
if (error)
reject(error);
else if (!resolved)
resolve(result);
});
if (R !== undefined) {
resolved = true;
resolve(R);
}
}
catch (e) {
return reject(e);
}
});
//! call main.. (it will return result or promised)
return promise(main, ctx, req)
.then(_ => {
// if (_ !== undefined) _log(NS, '! res =', $U.json(_));
if (_ !== undefined)
(0, engine_1._log)(NS, '! res =', engine_1.$U.S(_, 320, 64, ' .... ')); //! cut result string.
// ((context && context.done) || callback)(null, _);
// return true;
try {
ctx.res = {
status: _.statusCode,
body: _.body,
};
}
catch (error) {
ctx.res = {
status: 500,
body: error,
};
}
return _;
})
.catch(e => {
(0, engine_1._err)(NS, '! err =', e);
if (!FunctionHandler.REPORT_ERROR) {
// ((context && context.done) || callback)(e, null);
// return false;
throw e;
}
//! report this error.
return (0, engine_1.doReportError)(e, ctx, req)
.catch(_ => _) // safe call w/o error.
.then(() => {
// ((context && context.done) || callback)(e, null);
// return false;
throw e;
});
});
});
}
/**
* handle param via protocol-service.
* - sub-service could call this method() to bypass request.
*
* @param param protocol parameters
*/
handleProtocol(param) {
return __awaiter(this, void 0, void 0, function* () {
//! if valid API Request, then use $web's function.
const $web = this._map['web'];
if (!$web || typeof $web != 'object')
throw new Error(`500 NO WEB HANDLER - name:web`);
return $web.handleProtocol(param);
});
}
/**
* (default) pack the origin context to application context.
* - override this function if required!
*
* @param event origin event
* @param $ctx origin context of lambda
*/
packContext($ctx, req) {
return __awaiter(this, void 0, void 0, function* () {
const context = {};
$ctx && (0, engine_1._log)(NS, `! context[${$ctx || ''}] =`, engine_1.$U.json($ctx));
return context;
});
}
}
exports.FunctionHandler = FunctionHandler;
//! shared config.
FunctionHandler.REPORT_ERROR = engine_1.$U.env('REPORT_ERROR', '1') == '1';
//# sourceMappingURL=functions-handler.js.map
;