UNPKG

kubemq-js

Version:

kubemq js/ts library for KubeMQ Message Broker

289 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueuesMessagesPulledResponse = exports.QueuesPollRequest = exports.QueueMessageReceived = void 0; const pb = require("../protos"); const uuid_1 = require("uuid"); class QueueMessageReceived { constructor(id, channel, metadata, body, fromClientId, tags, timestamp, sequence, receiveCount, isReRouted, reRouteFromQueue, expiredAt, delayedTo, transactionId, isTransactionCompleted, responseHandler, receiverClientId, visibilitySeconds, isAutoAcked) { this.messageCompleted = false; this.timerExpired = false; this.id = id; this.channel = channel; this.metadata = metadata; this.body = body; this.fromClientId = fromClientId; this.tags = tags; this.timestamp = timestamp; this.sequence = sequence; this.receiveCount = receiveCount; this.isReRouted = isReRouted; this.reRouteFromQueue = reRouteFromQueue; this.expiredAt = expiredAt; this.delayedTo = delayedTo; this.transactionId = transactionId; this.isTransactionCompleted = isTransactionCompleted; this.responseHandler = responseHandler; this.receiverClientId = receiverClientId; this.visibilitySeconds = visibilitySeconds; this.isAutoAcked = isAutoAcked; if (this.visibilitySeconds > 0) { this.startVisibilityTimer(); } } startVisibilityTimer() { if (this.visibilitySeconds > 0 && !this.timerExpired && !this.messageCompleted) { this.visibilityTimer = setTimeout(() => this.onVisibilityExpired(), this.visibilitySeconds * 1000); } } onVisibilityExpired() { this.timerExpired = true; this.clearVisibilityTimer(); this.reject().catch((err) => { console.error('Visibility expired, failed to reject message:', err); }); } extendVisibilityTimer(additionalSeconds) { if (additionalSeconds <= 0) throw new Error('Additional seconds must be greater than 0'); if (!this.visibilityTimer) throw new Error('Cannot extend, timer not active'); if (this.timerExpired) throw new Error('Cannot extend, timer has expired'); if (this.messageCompleted) throw new Error('Message transaction is already completed'); clearTimeout(this.visibilityTimer); this.visibilitySeconds += additionalSeconds; this.startVisibilityTimer(); } ack() { if (this.messageCompleted || this.isTransactionCompleted) { return Promise.reject(new Error('Transaction is already completed')); } if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, Channel: this.channel, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.AckRange, RefTransactionId: this.transactionId, SequenceRange: [this.sequence], }); return this.writeToStream(request); } reject() { if (this.messageCompleted || this.isTransactionCompleted) { return Promise.reject(new Error('Transaction is already completed')); } if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, Channel: this.channel, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.NAckRange, RefTransactionId: this.transactionId, SequenceRange: [this.sequence], }); return this.writeToStream(request); } reQueue(newChannel) { if (!newChannel) throw new Error('Re-queue channel cannot be empty'); if (this.messageCompleted || this.isTransactionCompleted) { return Promise.reject(new Error('Transaction is already completed')); } if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, Channel: this.channel, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.ReQueueRange, RefTransactionId: this.transactionId, SequenceRange: [this.sequence], ReQueueChannel: newChannel, }); return this.writeToStream(request); } async writeToStream(request) { return new Promise((resolve, reject) => { const success = this.responseHandler.write(request, (err) => { if (err) { reject(err); } else { this.markTransactionCompleted(); resolve(); } }); if (!success) { this.responseHandler.once('drain', () => resolve()); } }); } markTransactionCompleted() { this.messageCompleted = true; this.isTransactionCompleted = true; this.clearVisibilityTimer(); } clearVisibilityTimer() { if (this.visibilityTimer) { clearTimeout(this.visibilityTimer); this.visibilityTimer = undefined; } } static decode(message, transactionId, transactionIsCompleted, receiverClientId, responseHandler, visibilitySeconds, isAutoAcked) { return new QueueMessageReceived(message.MessageID, message.Channel, message.Metadata, typeof message.Body === 'string' ? new TextEncoder().encode(message.Body) : message.Body, message.ClientID, new Map(Object.entries(message.Tags)), new Date(message.Attributes.Timestamp / 1000000000), message.Attributes.Sequence, message.Attributes.ReceiveCount, message.Attributes.ReRouted, message.Attributes.ReRoutedFromQueue, message.Attributes.ExpirationAt ? new Date(message.Attributes.ExpirationAt / 1000000) : undefined, message.Attributes.DelayedTo ? new Date(message.Attributes.DelayedTo / 1000000) : undefined, transactionId, transactionIsCompleted, responseHandler, receiverClientId, visibilitySeconds, isAutoAcked); } } exports.QueueMessageReceived = QueueMessageReceived; class QueuesPollRequest { constructor(data) { var _a, _b, _c, _d; this.channel = data.channel; this.pollMaxMessages = (_a = data.pollMaxMessages) !== null && _a !== void 0 ? _a : 1; // Default to 1 if not provided this.pollWaitTimeoutInSeconds = (_b = data.pollWaitTimeoutInSeconds) !== null && _b !== void 0 ? _b : 60; // Default to 60 seconds if not provided this.autoAckMessages = (_c = data.autoAckMessages) !== null && _c !== void 0 ? _c : false; // Default to false if not provided this.visibilitySeconds = (_d = data.visibilitySeconds) !== null && _d !== void 0 ? _d : 0; this.validate(); // Validate inputs during initialization } validate() { // Channel validation if (!this.channel || this.channel.trim() === '') { throw new Error('Queue subscription must have a valid channel.'); } // pollMaxMessages validation if (this.pollMaxMessages < 1) { throw new Error('pollMaxMessages must be greater than 0.'); } // pollWaitTimeoutInSeconds validation if (this.pollWaitTimeoutInSeconds < 1) { throw new Error('pollWaitTimeoutInSeconds must be greater than 0.'); } // visibilitySeconds validation if (this.visibilitySeconds < 0) { throw new Error('Visibility timeout must be a non-negative integer.'); } // autoAckMessages and visibilitySeconds should not conflict if (this.autoAckMessages && this.visibilitySeconds > 0) { throw new Error('autoAckMessages and visibilitySeconds cannot be set together.'); } } encode(clientId) { // Encodes the request into a protobuf message after validation return new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), // Generate a random UUID ClientID: clientId, Channel: this.channel, MaxItems: this.pollMaxMessages, WaitTimeout: this.pollWaitTimeoutInSeconds * 1000, // Convert seconds to milliseconds AutoAck: this.autoAckMessages, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.Get, // Assuming this is the correct request type }); } // Factory method to create an instance from a plain object, ensuring proper validation static from(data) { return new QueuesPollRequest(data); } } exports.QueuesPollRequest = QueuesPollRequest; /** * queue messages pull/peek response */ class QueuesMessagesPulledResponse { constructor(id, messages = [], messagesReceived = 0, messagesExpired = 0, isPeek = false, isError = false, error = '', visibilitySeconds = 0, isAutoAcked = false) { this.id = id; this.messages = messages; this.messagesReceived = messagesReceived; this.messagesExpired = messagesExpired; this.activeOffsets = []; this.responseHandler = null; this.receiverClientId = ''; this.transactionId = ''; this.isPeek = isPeek; this.isError = isError; this.error = error; this.visibilitySeconds = visibilitySeconds; this.isAutoAcked = isAutoAcked; } ackAll() { if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.AckAll, RefTransactionId: this.transactionId, SequenceRange: this.activeOffsets, }); return this.writeToStream(request); } rejectAll() { if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.NAckAll, RefTransactionId: this.transactionId, SequenceRange: this.activeOffsets, }); return this.writeToStream(request); } reQueueAll(newChannel) { if (!newChannel) throw new Error('Re-queue channel cannot be empty'); if (this.isAutoAcked) { return Promise.reject(new Error('Auto-acked message, operations are not allowed')); } const request = new pb.kubemq.QueuesDownstreamRequest({ RequestID: (0, uuid_1.v4)(), ClientID: this.receiverClientId, RequestTypeData: pb.kubemq.QueuesDownstreamRequestType.ReQueueAll, RefTransactionId: this.transactionId, SequenceRange: this.activeOffsets, ReQueueChannel: newChannel, }); return this.writeToStream(request); } async writeToStream(request) { return new Promise((resolve, reject) => { const success = this.responseHandler.write(request, (err) => { if (err) { reject(err); } else { this.markTransactionCompleted(); resolve(); } }); if (!success) { this.responseHandler.once('drain', () => resolve()); } }); } /** * Loops through the messages and marks each transaction as completed. */ markTransactionCompleted() { this.messages.forEach((message) => { message.markTransactionCompleted(); }); } } exports.QueuesMessagesPulledResponse = QueuesMessagesPulledResponse; //# sourceMappingURL=queuesTypes.js.map