lemon-core
Version:
Lemon Serverless Micro-Service Platform
250 lines • 10.8 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());
});
};
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
;