vulcain-corejs
Version: 
Vulcain micro-service framework
138 lines (136 loc) • 5.21 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments)).next());
    });
};
const amqp = require("amqplib");
const system_1 = require("./../configurations/globals/system");
class RabbitAdapter {
    constructor(address) {
        this.address = address;
        this.domainHandlers = new Map();
        this.initialized = false;
        if (!this.address)
            throw new Error("Address is required for RabbitAdapter");
        if (!address.startsWith("amqp://"))
            this.address = "amqp://" + address;
        this.address += "/" + system_1.System.environment;
    }
    startAsync() {
        let self = this;
        return new Promise((resolve, reject) => {
            if (self.initialized) {
                return resolve(self);
            }
            // TODO connection error
            self.initialized = true;
            system_1.System.log.info(null, "Open rabbitmq connexion on " + system_1.System.removePasswordFromUrl(this.address)); // TODO remove password
            amqp.connect(this.address).then((conn) => {
                conn.createChannel().then((ch) => {
                    self.channel = ch;
                    resolve(self);
                });
            })
                .catch(err => {
                system_1.System.log.error(null, err, "Unable to open rabbit connexion");
                resolve(self);
            });
        });
    }
    /**
     * Send domain event (event raises by an action)
     * Domain events are shared by all services of any domains
     *
     * @param {string} domain
     * @param {EventData} event
     *
     * @memberOf RabbitAdapter
     */
    sendEvent(domain, event) {
        if (!this.channel)
            return;
        domain = domain.toLowerCase() + "_events";
        this.channel.assertExchange(domain, 'fanout', { durable: false });
        this.channel.publish(domain, '', new Buffer(JSON.stringify(event)));
    }
    /**
     * Listening for domain events
     *
     * @param {string} domain
     * @param {Function} handler
     *
     * @memberOf RabbitAdapter
     */
    consumeEvents(domain, handler) {
        if (!this.channel)
            return;
        let self = this;
        // Since this method can be called many times for a same domain
        // all handlers are aggragated on only one binding
        domain = domain.toLowerCase() + "_events";
        let handlers = this.domainHandlers.get[domain];
        if (handlers) {
            handlers.push(handler);
            return;
        }
        // First time for this domain, create the binding
        handlers = [handler];
        this.domainHandlers.set(domain, handlers);
        this.channel.assertExchange(domain, 'fanout', { durable: false });
        this.channel.assertQueue('', { exclusive: true }).then(queue => {
            self.channel.bindQueue(queue.queue, domain, '');
            self.channel.consume(queue.queue, (msg) => __awaiter(this, void 0, void 0, function* () {
                let obj = JSON.parse(msg.content.toString());
                handlers.forEach(h => h(obj));
            }), { noAck: true });
        });
    }
    /**
     * Task = asynchronous action
     * Shared by service instances
     *
     * @param {string} domain
     * @param {string} serviceId
     * @param {ActionData} command
     *
     * @memberOf RabbitAdapter
     */
    publishTask(domain, serviceId, command) {
        if (!this.channel)
            return;
        domain = domain.toLowerCase();
        this.channel.assertExchange(domain, 'direct', { durable: false });
        this.channel.publish(domain, serviceId, new Buffer(JSON.stringify(command)), { persistent: true });
    }
    /**
     * Listening for asynchronous task
     *
     * @param {string} domain
     * @param {string} serviceId
     * @param {Function} handler
     *
     * @memberOf RabbitAdapter
     */
    consumeTask(domain, serviceId, handler) {
        if (!this.channel)
            return;
        let self = this;
        domain = domain.toLowerCase();
        this.channel.assertExchange(domain, 'direct', { durable: false });
        this.channel.assertQueue(domain, { durable: true }).then(queue => {
            // Channel name = serviceId
            self.channel.bindQueue(queue.queue, domain, serviceId);
            self.channel.prefetch(1);
            self.channel.consume(queue.queue, (msg) => __awaiter(this, void 0, void 0, function* () {
                yield handler(JSON.parse(msg.content.toString()));
                self.channel.ack(msg);
            }), { noAck: false });
        });
    }
}
exports.RabbitAdapter = RabbitAdapter;
//# sourceMappingURL=rabbitAdapter.js.map