UNPKG

lemon-core

Version:
250 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 _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.MyDummySQSService = exports.QueuesService = void 0; /** * `aws-sqs-service.ts` * - sqs service for AWS `SQS`. * * * //TODO - move to `lemon-core` shared lib. * * @author Ian Kim <ian@lemoncloud.io> * @date 2023-09-25 initial azure service bus queues service * * @copyright (C) lemoncloud.io 2023 - All Rights Reserved. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const engine_1 = require("../../engine"); // import { KeyVaultService } from '../azure' require("dotenv/config"); const NS = engine_1.$U.NS('AZQU', 'blue'); // NAMESPACE TO BE PRINTED. /** * class: AZSbQueueService * - support of AWS `SQS` Service */ class QueuesService { // protected $kv: KeyVaultService; /** * default constructor. */ constructor(endpoint, region) { // public static $kv: KeyVaultService = new KeyVaultService(); this.instance = () => __awaiter(this, void 0, void 0, function* () { // eslint-disable-next-line @typescript-eslint/no-var-requires const { ServiceBusClient, ServiceBusAdministrationClient } = require('@azure/service-bus'); // const connectionString = await QueuesService.$kv.decrypt(process.env.SERVICEBUS_CONNECTION_STRING) const connectionString = process.env.SERVICEBUS_CONNECTION_STRING; const serviceBusClient = new ServiceBusClient(connectionString); const serviceBusAdministrationClient = new ServiceBusAdministrationClient(connectionString); return { serviceBusClient, serviceBusAdministrationClient }; }); /** * hello */ this.hello = () => `az-sb-queues-service:${this._endpoint || ''}`; endpoint = endpoint !== null && endpoint !== void 0 ? endpoint : QueuesService.SB_QUEUES_ENDPOINT; // const stage = $engine.environ('STAGE', '') as string; // if (!endpoint && stage != 'local') // throw new Error(`env.${QueuesService.SB_QUEUES_ENDPOINT} is required w/ stage:${stage}`); (0, engine_1._log)(NS, `QueuesService(${endpoint}, ${region})...`); this._region = region; this._endpoint = endpoint; } region() { return this._region; } endpoint() { return this._endpoint; } iso8601DurationToSeconds(durationString) { const matches = durationString.match(/^PT(\d+)M$/); if (matches) { const mins = parseInt(matches[1], 10); return mins * 60; } else { throw new Error('Invalid ISO 8601 duration format'); } } /** * send message into SQS. * * @param data object data to be json. * @param attr attribute set. */ sendMessage(data) { return __awaiter(this, void 0, void 0, function* () { if (!data) throw new Error('@data(object) is required!'); const { serviceBusClient } = yield this.instance(); const sender = serviceBusClient.createSender(this._endpoint); const messages = [ { contentType: 'application/json', body: data, }, ]; let batch = yield sender.createMessageBatch(); for (const message of messages) { if (!batch.tryAddMessage(message)) { // Send the current batch as it is full and create a new one yield sender.sendMessages(batch); batch = yield sender.createMessageBatch(); if (!batch.tryAddMessage(message)) { throw new Error('Message too big to fit in a batch'); } } } yield sender.sendMessages(batch); yield sender.close(); return; }); } /** * 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!'); const { serviceBusClient } = yield this.instance(); const receiver = yield serviceBusClient.createReceiver(this._endpoint); const messages = yield receiver.receiveMessages(size); // it defaults to the "peekLock" mode const list = []; for (let i = 0; i < messages.length; i++) { const message = messages[i]; try { list.push(message); } catch (error) { console.error('Error occurred:', error); yield receiver.abandonMessage(message); // If an error occurs, return the message back to the queue } return { list }; } }); } /** * delete message by id * @param handle handle-id to delete. */ deleteMessage(message) { return __awaiter(this, void 0, void 0, function* () { if (!message) throw new Error('@handle(string) is required!'); const { serviceBusClient } = yield this.instance(); const receiver = yield serviceBusClient.createReceiver(this._endpoint); yield receiver.completeMessage(message); // Process the message and delete it return; }); } /** * statistics for the given type. * * @param {*} TYPE */ statistics() { return __awaiter(this, void 0, void 0, function* () { const { serviceBusAdministrationClient } = yield this.instance(); const queueProperties = yield serviceBusAdministrationClient.getQueue(this._endpoint); const queueRuntimeProperties = yield serviceBusAdministrationClient.getQueueRuntimeProperties(this._endpoint); // The number of active messages in the entity. // If a message is successfully delivered to a subscription, // the number of active messages in the topic itself is 0. const available = queueRuntimeProperties.activeMessageCount; const inflight = queueRuntimeProperties.totalMessageCount - queueRuntimeProperties.activeMessageCount; //The number of messages which are yet to be transferred/forwarded to destination entity. const delayed = queueRuntimeProperties.transferMessageCount; // Delayed //The number of messages transfer-messages which are dead-lettered into transfer-dead-letter subqueue. const timeout = this.iso8601DurationToSeconds(queueProperties.lockDuration); // Timeout return { available, inflight, delayed, timeout }; }); } } exports.QueuesService = QueuesService; QueuesService.SB_QUEUES_ENDPOINT = (_a = process.env.SERVICEBUS_QUEUE_RESOURCE) !== null && _a !== void 0 ? _a : 'queue-lemon'; /** **************************************************************************************************************** * 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=azure-sb-queues-service.js.map