UNPKG

lemon-core

Version:
261 lines 10.8 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()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MyDummySQSService = exports.AWSSQSService = void 0; /** * `aws-sqs-service.ts` * - sqs service for AWS `SQS`. * * * //TODO - move to `lemon-core` shared lib. * * @author Steve Jung <steve@lemoncloud.io> * @date 2019-09-27 initial version * * @copyright (C) lemoncloud.io 2019 - All Rights Reserved. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const engine_1 = require("../../engine/"); const NS = engine_1.$U.NS('SQSS', 'blue'); // NAMESPACE TO BE PRINTED. const aws_sdk_1 = __importDefault(require("aws-sdk")); /** * class: AWSSQSService * - support of AWS `SQS` Service */ class AWSSQSService { /** * default constructor. */ constructor(endpoint, region) { /** * hello */ this.hello = () => `aws-sqs-service:${this._endpoint || ''}`; region = region || engine_1.$engine.environ(AWSSQSService.SQS_REGION, 'ap-northeast-2') || ''; endpoint = endpoint || engine_1.$engine.environ(AWSSQSService.SQS_ENDPOINT, '') || ''; // const stage = $engine.environ('STAGE', '') as string; // if (!endpoint && stage != 'local') // throw new Error(`env.${AWSSQSService.SQS_ENDPOINT} is required w/ stage:${stage}`); (0, engine_1._log)(NS, `AWSSQSService(${endpoint}, ${region})...`); this._region = region; this._endpoint = endpoint; } region() { return this._region; } endpoint() { return this._endpoint; } /** * send message into SQS. * * @param data object data to be json. * @param attr attribute set. */ sendMessage(data, attr) { return __awaiter(this, void 0, void 0, function* () { if (!data) throw new Error('@data(object) is required!'); //! prepare params. const asAttr = (param) => Object.keys(param || {}).reduce((O, key) => { const val = param[key]; const isNum = typeof val === 'number' ? true : false; O[key] = { DataType: isNum ? 'Number' : 'String', StringValue: `${val}`, }; return O; }, {}); const params = { // DelaySeconds: 10, //NOTE - use SQS's configuration. MessageAttributes: asAttr(attr), MessageBody: engine_1.$U.json(data && typeof data == 'object' ? data : { data }), QueueUrl: this.endpoint(), }; (0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params)); const sqs = new aws_sdk_1.default.SQS({ region: this.region() }); const result = yield sqs.sendMessage(params).promise(); (0, engine_1._log)(NS, '> result =', result); return (result && result.MessageId) || ''; }); } /** * receive message by size. * * @param size (default 1) size of message */ receiveMessage(size = 1) { return __awaiter(this, void 0, void 0, function* () { size = size === undefined ? 1 : size; size = engine_1.$U.N(size, 0); if (!size) throw new Error('@size(number) is required!'); //! prepare param. const params = { AttributeNames: ['SentTimestamp'], MaxNumberOfMessages: size, MessageAttributeNames: ['All'], QueueUrl: this.endpoint(), // VisibilityTimeout: 0, //WARN! DUPLICATE MESSAGES CAN BE SEEN. WaitTimeSeconds: 0, //WARN! WAIT FOR EMPTY QUEUE. }; (0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params)); //! call api const sqs = new aws_sdk_1.default.SQS({ region: this.region() }); const result = yield sqs.receiveMessage(params).promise(); (0, engine_1._log)(NS, '> result =', engine_1.$U.json(result)); //! transform list. const list = (result && result.Messages).map(_ => { const N = {}; N.sent = _.Attributes.SentTimestamp; const $attr = _.MessageAttributes || {}; N.attr = Object.keys($attr).reduce((O, key) => { const V = $attr[key]; const type = (V && V.DataType) || ''; const val = (V && V.StringValue) || ''; O[key] = type == 'Number' ? Number(val) : val; return O; }, {}); N.data = JSON.parse(_.Body || '{}'); N.id = _.MessageId; N.handle = _.ReceiptHandle; return N; }); //! returns. return { list }; }); } /** * delete message by id * @param handle handle-id to delete. */ deleteMessage(handle) { return __awaiter(this, void 0, void 0, function* () { if (!handle) throw new Error('@handle(string) is required!'); //! prepare param const params = { QueueUrl: this.endpoint(), ReceiptHandle: handle, }; (0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params)); //! call delete. const sqs = new aws_sdk_1.default.SQS({ region: this.region() }); const result = yield sqs.deleteMessage(params).promise(); (0, engine_1._log)(NS, '> result =', engine_1.$U.json(result)); return; }); } /** * statistics for the given type. * * @param {*} TYPE */ statistics() { return __awaiter(this, void 0, void 0, function* () { const params = { QueueUrl: this.endpoint(), AttributeNames: ['All'], }; (0, engine_1._log)(NS, `> params[${this.endpoint()}] =`, engine_1.$U.json(params)); //! call delete. const sqs = new aws_sdk_1.default.SQS({ region: this.region() }); const result = yield sqs.getQueueAttributes(params).promise(); (0, engine_1._log)(NS, '> result =', engine_1.$U.json(result)); const attr = result.Attributes || {}; const stat = { available: engine_1.$U.N(attr.ApproximateNumberOfMessages, 0), inflight: engine_1.$U.N(attr.ApproximateNumberOfMessagesNotVisible, 0), delayed: engine_1.$U.N(attr.ApproximateNumberOfMessagesDelayed, 0), timeout: engine_1.$U.N(attr.VisibilityTimeout, 0), }; //! returns finally. return stat; }); } } exports.AWSSQSService = AWSSQSService; AWSSQSService.SQS_REGION = 'MY_SQS_REGION'; AWSSQSService.SQS_ENDPOINT = 'MY_SQS_ENDPOINT'; /** **************************************************************************************************************** * Dummy SQS Service ** ****************************************************************************************************************/ /** * class: MyDummySQSService * - simulated dummy `SQSService` which is identical to real-service. */ class MyDummySQSService { constructor(endpoint, timeout = 30) { this.buffer = []; this.hello = () => `dummy-sqs-service:${this.endpoint}`; (0, engine_1._log)(NS, `MyDummySQSService(${endpoint}, ${timeout})...`); this.endpoint = endpoint; this.timeout = timeout; } sendMessage(data, attr) { return __awaiter(this, void 0, void 0, function* () { if (!data) throw new Error('@data(object) is required!'); const fn = (n) => { const [S, s] = ['ff2cb2000000', `${n}`]; return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s; }; const payload = { sent: new Date().getTime(), attr, data, id: '', handle: '' }; this.buffer.push(payload); const len = this.buffer.length; const id = `aabbccdd-dummy-sqs-b29b-${fn(len)}`; (0, engine_1._inf)(NS, `> queue[${id}] :=`, engine_1.$U.json(payload)); if (this.timeout > 0) { setTimeout(() => { payload.id = id; }, this.timeout); } else if (this.timeout == 0) { payload.id = id; } return id; }); } receiveMessage(size) { return __awaiter(this, void 0, void 0, function* () { size = size === undefined ? 1 : size; const list = this.buffer.filter(data => (data.id && data.data ? true : false)); const list2 = list .filter((_data, index) => index < size) .map(data => { const data2 = Object.assign({}, data); // copy data2.handle = `${data.id}`; data.id = ''; // mark received. return data2; }); return { list: list2 }; }); } deleteMessage(handle) { return __awaiter(this, void 0, void 0, function* () { this.buffer.filter(data => data.handle == handle).map(data => delete data.data); }); } statistics() { return __awaiter(this, void 0, void 0, function* () { const available = this.buffer.filter(data => !!data.id).length; const inflight = 0; const delayed = 0; const timeout = this.timeout; return { available, inflight, delayed, timeout }; }); } } exports.MyDummySQSService = MyDummySQSService; //# sourceMappingURL=aws-sqs-service.js.map