UNPKG

@citrineos/util

Version:

The OCPP util module which supplies helpful utilities like cache and queue connectors, etc.

136 lines 6.02 kB
"use strict"; // Copyright (c) 2023 S44, LLC // Copyright Contributors to the CitrineOS Project // // SPDX-License-Identifier: Apache 2.0 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.KafkaReceiver = void 0; const base_1 = require("@citrineos/base"); const class_transformer_1 = require("class-transformer"); const kafkajs_1 = require("kafkajs"); /** * Implementation of a {@link IMessageHandler} using Kafka as the underlying transport. */ class KafkaReceiver extends base_1.AbstractMessageHandler { constructor(config, logger, module) { var _a, _b, _c, _d, _e; super(config, logger, module); this._consumerMap = new Map(); this._client = new kafkajs_1.Kafka({ brokers: ((_a = this._config.util.messageBroker.kafka) === null || _a === void 0 ? void 0 : _a.brokers) || [], ssl: true, sasl: { mechanism: 'plain', username: ((_b = this._config.util.messageBroker.kafka) === null || _b === void 0 ? void 0 : _b.sasl.username) || '', password: ((_c = this._config.util.messageBroker.kafka) === null || _c === void 0 ? void 0 : _c.sasl.password) || '', }, }); this._topicName = `${(_d = this._config.util.messageBroker.kafka) === null || _d === void 0 ? void 0 : _d.topicPrefix}-${(_e = this._config.util.messageBroker.kafka) === null || _e === void 0 ? void 0 : _e.topicName}`; const admin = this._client.admin(); admin .connect() .then(() => admin.listTopics()) .then((topics) => { this._logger.debug('Topics:', topics); if (!topics || topics.filter((topic) => topic === this._topicName).length === 0) { this._client .admin() .createTopics({ topics: [{ topic: this._topicName }] }) .then(() => { this._logger.debug(`Topic ${this._topicName} created.`); }) .catch((err) => { this._logger.error('Error creating topic', err); }); } else { this._logger.debug(`Topic ${this._topicName} already exists.`); } }) .then(() => admin.disconnect()) .catch((err) => { this._logger.error(err); }); } subscribe(identifier, actions, filter) { this._logger.debug(`Subscribing to ${this._topicName}...`, identifier, actions, filter); const consumer = this._client.consumer({ groupId: 'test-group' }); return consumer .connect() .then(() => consumer.subscribe({ topic: this._topicName, fromBeginning: false })) .then(() => consumer.run({ autoCommit: false, eachMessage: (payload) => this._onMessage(payload, consumer), })) // TODO: Add filter .then(() => this._consumerMap.set(identifier, consumer)) .then(() => true) .catch((err) => { this._logger.error(err); return false; }); } unsubscribe(identifier) { const consumer = this._consumerMap.get(identifier); if (!consumer) { this._logger.error('Consumer not found', identifier); return Promise.resolve(false); } return consumer .disconnect() .then(() => this._consumerMap.delete(identifier)) .catch((err) => { this._logger.error(err); return false; }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { for (const consumer of this._consumerMap.values()) { yield consumer.disconnect(); } }); } /** * Private Methods */ /** * Underlying Kafka message handler. * * @param message The kafka message to process */ _onMessage(_a, consumer_1) { return __awaiter(this, arguments, void 0, function* ({ topic, partition, message }, consumer) { var _b, _c; this._logger.debug(`Received message ${(_b = message.value) === null || _b === void 0 ? void 0 : _b.toString()} on topic ${topic} partition ${partition}`); try { const messageValue = message.value; if (messageValue) { const parsed = (0, class_transformer_1.plainToInstance)((base_1.Message), messageValue.toString()); yield this.handle(parsed, (_c = message.key) === null || _c === void 0 ? void 0 : _c.toString()); } } catch (error) { if (error instanceof base_1.RetryMessageError) { this._logger.warn('Retrying message: ', error.message); // Retryable error, usually ongoing call with station when trying to send new call return; } else { this._logger.error('Error while processing message:', error, message); } } yield consumer.commitOffsets([{ topic, partition, offset: message.offset }]); }); } } exports.KafkaReceiver = KafkaReceiver; //# sourceMappingURL=receiver.js.map