"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.amqpwrapper = exports.amqpexchange = exports.amqpqueue = exports.Deferred = void 0;
const amqplib = require("amqplib");
const Config_1 = require("./Config");
const Crypt_1 = require("./Crypt");
const openflow_api_1 = require("@openiap/openflow-api");
const WebSocketServer_1 = require("./WebSocketServer");
const Logger_1 = require("./Logger");
const events = require("events");
const Message_1 = require("./Messages/Message");
class Deferred {
    constructor() {
        const me = this;
        this.promise = new Promise((resolve, reject) => {
            me.reject = reject;
            me.resolve = resolve;
        });
    }
}
exports.Deferred = Deferred;
class amqpqueue {
}
exports.amqpqueue = amqpqueue;
class amqpexchange {
}
exports.amqpexchange = amqpexchange;
// tslint:disable-next-line: class-name
class amqpwrapper extends events.EventEmitter {
    constructor(connectionstring) {
        super();
        this.connected = false;
        this.AssertExchangeOptions = { durable: false, confirm: true };
        this.AssertQueueOptions = { durable: true };
        this.activecalls = {};
        this.queues = [];
        this.exchanges = [];
        this.timeout = null;
        this.queuemessagecounter = {};
        this.connectionstring = connectionstring;
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.amqp_dlx)) {
            this.AssertQueueOptions.arguments = {};
            this.AssertQueueOptions.arguments['x-dead-letter-exchange'] = Config_1.Config.amqp_dlx;
        }
        this.setMaxListeners(1500);
    }
    static waitFor(condition, callback) {
        if (!condition()) {
            setTimeout(amqpwrapper.waitFor.bind(null, condition, callback), 100); /* this checks the flag every 100 milliseconds*/
        }
        else {
            callback();
        }
    }
    // async version of static waitFor
    static async asyncWaitFor(condition) {
        return new Promise((resolve) => {
            this.waitFor(condition, resolve);
        });
    }
    static Instance() {
        return this._instance;
    }
    static SetInstance(instance) {
        this._instance = instance;
    }
    incqueuemessagecounter(queuename) {
        let result = 0;
        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(this.queuemessagecounter[queuename]))
            result = this.queuemessagecounter[queuename];
        result++;
        this.queuemessagecounter[queuename] = result;
        return result;
    }
    async connect(parent) {
        const span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.connect", parent);
        try {
            if (this.timeout != null) {
                clearTimeout(this.timeout);
                this.timeout = null;
            }
            if (this.conn == null) {
                span === null || span === void 0 ? void 0 : span.addEvent("connect");
                Logger_1.Logger.instanse.info("amqpwrapper", "connect", "Connecting to rabbitmq");
                this.conn = await amqplib.connect(this.connectionstring);
                Logger_1.Logger.instanse.info("amqpwrapper", "connect", "Connected to rabbitmq");
                this.conn.on('error', (error) => {
                    if (error.code != 404) {
                        Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
                    }
                });
                this.conn.on("close", () => {
                    Logger_1.Logger.instanse.info("amqpwrapper", "connect", "econnecting");
                    this.conn = null;
                    if (this.timeout != null) {
                        clearTimeout(this.timeout);
                        this.timeout = null;
                    }
                    this.timeout = setTimeout(this.connect.bind(this), 1000);
                    this.emit("disconnected");
                });
            }
            try {
                span === null || span === void 0 ? void 0 : span.addEvent("AddReplyQueue");
                await this.AddReplyQueue(span);
                this.channel.on('error', (error) => {
                    if (error.code != 404) {
                        Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
                    }
                });
            }
            catch (error) {
                Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
                if (Config_1.Config.NODE_ENV == "production") {
                    Logger_1.Logger.instanse.error("amqpwrapper", "connect", "Exit, when we cannot create reply queue");
                    process.exit(405);
                }
            }
            try {
                await this.Adddlx(span);
                await this.AddOFExchange(span);
            }
            catch (error) {
                Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
                if (Config_1.Config.NODE_ENV == "production") {
                    Logger_1.Logger.instanse.error("amqpwrapper", "connect", "Exit, when we cannot create dead letter exchange and/or Openflow exchange");
                    process.exit(406);
                }
            }
            span === null || span === void 0 ? void 0 : span.addEvent("emit connected");
            this.emit("connected");
            this.connected = true;
        }
        catch (error) {
            span === null || span === void 0 ? void 0 : span.recordException(error);
            Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
            if (this.timeout != null) {
                clearTimeout(this.timeout);
                this.timeout = null;
            }
            if (error.message.startsWith("Expected amqp: or amqps:")) {
                throw error;
            }
            Logger_1.Logger.instanse.error("amqpwrapper", "connect", error);
            this.timeout = setTimeout(this.connect.bind(this), 1000);
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    shutdown() {
        this.connected = false;
        try {
            if (this.channel != null) {
                this.channel.removeAllListeners();
            }
        }
        catch (error) {
        }
        try {
            if (this.conn != null) {
                this.conn.removeAllListeners();
                this.conn.close();
            }
        }
        catch (error) {
        }
        this.channel = null;
        if (this.timeout != null) {
            clearTimeout(this.timeout);
            this.timeout = null;
        }
    }
    async AddReplyQueue(parent) {
        const span = Logger_1.Logger.otel.startSubSpan("AddReplyQueue", parent);
        try {
            this.channel = await this.conn.createConfirmChannel();
            this.channel.prefetch(Config_1.Config.amqp_prefetch);
            this.replyqueue = await this.AddQueueConsumer(Crypt_1.Crypt.rootUser(), "", null, null, (msg, options, ack, done) => {
                ack();
                try {
                    if (this.replyqueue) {
                        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                            WebSocketServer_1.WebSocketServer.websocket_queue_message_count.add(1, { ...Logger_1.Logger.otel.defaultlabels, queuename: this.replyqueue.queue });
                        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(this.activecalls[options.correlationId])) {
                            this.activecalls[options.correlationId].resolve(msg);
                            delete this.activecalls[options.correlationId];
                        }
                    }
                }
                catch (error) {
                    Logger_1.Logger.instanse.error("amqpwrapper", "AddReplyQueue", error);
                }
                done();
            }, undefined);
            // We don't want to recreate this
            this.queues = this.queues.filter(q => q.consumerTag != this.replyqueue.consumerTag);
            this.channel.on('return', async (e1) => {
                try {
                    let msg = e1.content.toString();
                    let exchange = "";
                    let routingKey = "";
                    let replyTo = "";
                    let correlationId = "";
                    let errormsg = "Send timeout";
                    if (e1.fields && e1.fields.replyText)
                        errormsg = e1.fields.replyText;
                    if (e1.fields && e1.fields.exchange)
                        exchange = e1.fields.exchange;
                    if (e1.fields && e1.fields.routingKey)
                        routingKey = e1.fields.routingKey;
                    if (e1.properties && e1.properties.replyTo)
                        replyTo = e1.properties.replyTo;
                    if (e1.properties && e1.properties.correlationId)
                        correlationId = e1.properties.correlationId;
                    if (typeof msg === "string" || msg instanceof String) {
                        try {
                            msg = JSON.parse(msg);
                        }
                        catch (error) {
                        }
                    }
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(replyTo)) {
                        if (typeof msg === "string" || msg instanceof String) {
                            msg = "timeout";
                        }
                        else {
                            msg.command = "timeout";
                        }
                        Logger_1.Logger.instanse.debug("amqpwrapper", "AddReplyQueue", "[" + routingKey + "] notify " + replyTo + " " + errormsg + " to " + routingKey);
                        await amqpwrapper.Instance().send("", replyTo, msg, 20000, correlationId, "");
                    }
                }
                catch (error) {
                }
            });
            this.channel.on('close', async () => {
                Logger_1.Logger.instanse.error("amqpwrapper", "AddReplyQueue", "Exit, when we cannot create dead letter exchange and/or Openflow exchange");
                process.exit(406);
            });
        }
        catch (error) {
            span === null || span === void 0 ? void 0 : span.recordException(error);
            Logger_1.Logger.instanse.error("amqpwrapper", "AddReplyQueue", error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async RemoveQueueConsumer(user, queue, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.RemoveQueueConsumer", parent);
        try {
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(queue))
                throw new Error("queue is mandatory");
            if (queue != null) {
                Logger_1.Logger.instanse.debug("amqpwrapper", "AddReplyQueue", "[" + (user === null || user === void 0 ? void 0 : user.username) + "] Remove queue consumer " + queue.queue + "/" + queue.consumerTag);
                var exc = this.exchanges.filter(x => { var _a; return ((_a = x.queue) === null || _a === void 0 ? void 0 : _a.consumerTag) == queue.consumerTag; });
                if (exc.length > 0) {
                    try {
                        await this.channel.unbindQueue(exc[0].queue.queue, exc[0].exchange, exc[0].routingkey);
                    }
                    catch (error) {
                        Logger_1.Logger.instanse.error("amqpwrapper", "AddReplyQueue", error);
                    }
                    if (this.channel != null) {
                        if (exc[0].queue)
                            await this.channel.cancel(exc[0].queue.consumerTag);
                    }
                    this.exchanges = this.exchanges.filter(q => q.queue.consumerTag != queue.consumerTag);
                }
                var q = this.queues.filter(x => x.consumerTag == queue.consumerTag);
                if (q.length > 0) {
                    if (this.channel != null)
                        await this.channel.cancel(queue.consumerTag);
                    this.queues = this.queues.filter(q => q.consumerTag != queue.consumerTag);
                }
            }
        }
        catch (error) {
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async AddQueueConsumer(user, queuename, QueueOptions, jwt, callback, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.AddQueueConsumer", parent);
        try {
            if (this.channel == null || this.conn == null)
                throw new Error("Cannot Add new Queue Consumer, not connected to rabbitmq");
            let queue = (openflow_api_1.NoderedUtil.IsNullEmpty(queuename) ? "" : queuename);
            const q = new amqpqueue();
            q.callback = callback;
            q.QueueOptions = Object.assign({}, (QueueOptions != null ? QueueOptions : this.AssertQueueOptions));
            if (openflow_api_1.NoderedUtil.IsNullEmpty(queue))
                queue = "";
            if (queue.startsWith("amq."))
                queue = "";
            // if (NoderedUtil.IsNullEmpty(queue)) q.QueueOptions.exclusive = true;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(queue))
                q.QueueOptions.autoDelete = true;
            q.ok = await this.channel.assertQueue(queue, q.QueueOptions);
            if (q && q.ok) {
                this.queues.push(q);
                q.queue = q.ok.queue;
                q.queuename = queuename;
                const consumeresult = await this.channel.consume(q.ok.queue, (msg) => {
                    this.OnMessage(q, msg, q.callback);
                }, { noAck: false });
                q.consumerTag = consumeresult.consumerTag;
                Logger_1.Logger.instanse.debug("amqpwrapper", "AddQueueConsumer", "[" + (user === null || user === void 0 ? void 0 : user.username) + "] Added queue consumer " + q.queue + "/" + q.consumerTag);
            }
            else {
                throw new Error("Failed asserting Queue " + queue);
            }
            return q;
        }
        catch (error) {
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async AddExchangeConsumer(user, exchange, algorithm, routingkey, ExchangeOptions, jwt, addqueue, callback, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.AddExchangeConsumer", parent);
        try {
            if (openflow_api_1.NoderedUtil.IsNullEmpty(exchange))
                throw new Error("exchange name cannot be empty");
            if (this.channel == null || this.conn == null)
                throw new Error("Cannot Add new Exchange Consumer, not connected to rabbitmq");
            const q = new amqpexchange();
            q.ExchangeOptions = Object.assign({}, (ExchangeOptions != null ? ExchangeOptions : this.AssertExchangeOptions));
            if (exchange != Config_1.Config.amqp_dlx && exchange != "openflow")
                q.ExchangeOptions.autoDelete = true;
            q.exchange = exchange;
            q.algorithm = algorithm;
            q.routingkey = routingkey;
            q.callback = callback;
            const _ok = await this.channel.assertExchange(q.exchange, q.algorithm, q.ExchangeOptions);
            if (addqueue) {
                let AssertQueueOptions = null;
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.amqp_dlx) && exchange == Config_1.Config.amqp_dlx) {
                    AssertQueueOptions = Object.create(this.AssertQueueOptions);
                    delete AssertQueueOptions.arguments;
                }
                q.queue = await this.AddQueueConsumer(user, "", AssertQueueOptions, jwt, q.callback, span);
                if (q.queue) {
                    this.channel.bindQueue(q.queue.queue, q.exchange, q.routingkey);
                    Logger_1.Logger.instanse.debug("amqpwrapper", "AddExchangeConsumer", "[" + (user === null || user === void 0 ? void 0 : user.username) + "] Added exchange consumer " + q.exchange + ' to queue ' + q.queue.queue);
                }
            }
            this.exchanges.push(q);
            return q;
        }
        catch (error) {
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    OnMessage(sender, msg, callback) {
        try {
            const now = new Date();
            if (msg == null) {
                return;
            }
            const correlationId = msg.properties.correlationId;
            const replyTo = msg.properties.replyTo;
            const consumerTag = msg.fields.consumerTag;
            const routingKey = msg.fields.routingKey;
            const priority = (msg.properties.priority ? msg.properties.priority : 0);
            const exchangename = msg.fields.exchange;
            const options = {
                correlationId,
                replyTo,
                consumerTag,
                routingKey,
                exchangename,
                priority
            };
            const data = msg.content.toString();
            callback(data, options, (nack) => {
                try {
                    if (nack == false) {
                        this.channel.nack(msg);
                        // this.channel.nack(msg, false, true);
                        msg = null;
                        return;
                    }
                    this.channel.ack(msg);
                }
                catch (error) {
                    Logger_1.Logger.instanse.error("amqpwrapper", "OnMessage", error);
                }
            }, (result) => {
            });
        }
        catch (error) {
            Logger_1.Logger.instanse.error("amqpwrapper", "OnMessage", error);
        }
    }
    async sendWithReply(exchange, queue, data, expiration, correlationId, routingkey) {
        if (openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
            correlationId = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
        var promise = new Deferred();
        this.activecalls[correlationId] = promise;
        if (this.replyqueue) {
            await this.sendWithReplyTo(exchange, queue, this.replyqueue.queue, data, expiration, correlationId, routingkey);
        }
        return promise.promise;
    }
    async sendWithReplyTo(exchange, queue, replyTo, data, expiration, correlationId, routingkey, priority = 1) {
        await amqpwrapper.asyncWaitFor(() => this.connected);
        if (this.channel == null || this.conn == null) {
            throw new Error("Cannot send message, when not connected");
        }
        if (typeof data !== 'string' && !(data instanceof String)) {
            data = JSON.stringify(data);
        }
        Logger_1.Logger.instanse.silly("amqpwrapper", "sendWithReplyTo", "send to queue: " + queue + " exchange: " + exchange + " with reply to " + replyTo + " correlationId: " + correlationId);
        const options = { mandatory: true };
        options.replyTo = replyTo;
        if (openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
            correlationId = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
            options.correlationId = correlationId;
        if (expiration < 1)
            expiration = Config_1.Config.amqp_default_expiration;
        options.expiration = expiration.toString();
        options.mandatory = true;
        // options.confirm = true;
        // options.persistent = true;
        // options.durable = true;
        // options.mandatory = true;
        // options.immediate = true;
        options.priority = priority;
        if (openflow_api_1.NoderedUtil.IsNullEmpty(exchange)) {
            this.channel.publish("", queue, Buffer.from(data), options);
            await this.channel.waitForConfirms();
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                WebSocketServer_1.WebSocketServer.websocket_queue_message_count.add(1, { ...Logger_1.Logger.otel.defaultlabels, queuename: queue });
        }
        else {
            if (openflow_api_1.NoderedUtil.IsNullEmpty(routingkey))
                routingkey = "";
            this.channel.publish(exchange, routingkey, Buffer.from(data), options);
        }
    }
    async send(exchange, queue, data, expiration, correlationId, routingkey, priority = 1) {
        if (exchange == "openflow" && !Config_1.Config.enable_openflow_amqp)
            return;
        await amqpwrapper.asyncWaitFor(() => this.connected);
        if (this.channel == null || this.conn == null) {
            throw new Error("Cannot send message, when not connected");
        }
        if (typeof data !== 'string' && !(data instanceof String)) {
            data = JSON.stringify(data);
        }
        if (openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
            correlationId = openflow_api_1.NoderedUtil.GetUniqueIdentifier();
        Logger_1.Logger.instanse.silly("amqpwrapper", "send", "send to queue: " + queue + " exchange: " + exchange);
        const options = { mandatory: true };
        if (!openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
            options.correlationId = correlationId;
        if (expiration < 1)
            expiration = Config_1.Config.amqp_default_expiration;
        options.expiration = expiration.toString();
        options.mandatory = true;
        options.priority = priority;
        // options.confirm = true;
        // options.persistent = true;
        // options.durable = true;
        // options.mandatory = true;
        // options.immediate = true;
        if (openflow_api_1.NoderedUtil.IsNullEmpty(exchange)) {
            this.channel.publish("", queue, Buffer.from(data), options);
            await this.channel.waitForConfirms();
            if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                WebSocketServer_1.WebSocketServer.websocket_queue_message_count.add(1, { ...Logger_1.Logger.otel.defaultlabels, queuename: queue });
        }
        else {
            this.channel.publish(exchange, routingkey, Buffer.from(data), options);
        }
    }
    async Adddlx(parent) {
        if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.amqp_dlx))
            return;
        await this.AddExchangeConsumer(Crypt_1.Crypt.rootUser(), Config_1.Config.amqp_dlx, "fanout", "", null, null, true, async (msg, options, ack, done) => {
            ack();
            if (typeof msg === "string" || msg instanceof String) {
                try {
                    msg = JSON.parse(msg);
                }
                catch (error) {
                }
            }
            try {
                var ismine = this.IsMyQueue(options.replyTo);
                if (typeof msg === "string" || msg instanceof String) {
                    msg = "timeout";
                }
                else {
                    msg.command = "timeout";
                }
                if (ismine) {
                    // Resend message, this time to the reply queue for the correct node (replyTo)
                    Logger_1.Logger.instanse.warn("amqpwrapper", "Adddlx", "[" + options.exchangename + "] Send timeout to " + options.replyTo + " correlationId: " + options.correlationId);
                    // await amqpwrapper.Instance().sendWithReply("", options.replyTo, msg, 20000, options.correlationId, "");
                    await amqpwrapper.Instance().send("", options.replyTo, msg, 20000, options.correlationId, "");
                }
                else {
                    Logger_1.Logger.instanse.debug("amqpwrapper", "Adddlx", "[" + options.exchangename + "] Received timeout, (not handled by me) to " + options.replyTo + " correlationId: " + options.correlationId);
                }
            }
            catch (error) {
                Logger_1.Logger.instanse.error("amqpwrapper", "Adddlx", "Failed sending deadletter message to " + options.replyTo);
                Logger_1.Logger.instanse.error("amqpwrapper", "Adddlx", error);
            }
            done();
        }, parent);
    }
    IsMyconsumerTag(consumerTag) {
        var q = this.queues.filter(q => q.consumerTag == consumerTag);
        return q.length != 0;
    }
    IsMyQueue(queuename) {
        var q = this.queues.filter(q => q.queuename == queuename || q.queue == queuename);
        return q.length != 0;
    }
    async AddOFExchange(parent) {
        if (!Config_1.Config.enable_openflow_amqp)
            return;
        await this.AddExchangeConsumer(Crypt_1.Crypt.rootUser(), "openflow", "fanout", "", null, null, true, async (msg, options, ack, done) => {
            ack();
            if (typeof msg === "string" || msg instanceof String) {
                try {
                    msg = JSON.parse(msg);
                }
                catch (error) {
                }
            }
            if (typeof msg !== "string") {
                Logger_1.Logger.instanse.debug("amqpwrapper", "AddOFExchange", "[" + options.exchangename + "] Received command " + msg.command);
                switch (msg.command) {
                    case "clearcache":
                        Logger_1.Logger.DBHelper.clearCache("amqp broadcast");
                        break;
                    case "housekeeping":
                        // if (this.IsMyconsumerTag(options.consumerTag)) break;
                        if (msg.lastrun) {
                            Logger_1.Logger.instanse.debug("amqpwrapper", "AddOFExchange", "[" + options.exchangename + "] " + msg.lastrun);
                            Message_1.Message.lastHouseKeeping = new Date(msg.lastrun);
                        }
                        else {
                            if (Message_1.Message.lastHouseKeeping != null) {
                                amqpwrapper.Instance().send("openflow", "", { "command": "housekeeping", "lastrun": Message_1.Message.lastHouseKeeping.toISOString() }, 20000, null, "", 1);
                            }
                        }
                        break;
                    case "shutdown":
                        try {
                            await Config_1.Config.db.shutdown();
                            await Logger_1.Logger.otel.shutdown();
                            await Logger_1.Logger.License.shutdown();
                            // await Auth.shutdown();
                        }
                        catch (error) {
                            Logger_1.Logger.instanse.error("amqpwrapper", "AddOFExchange", error);
                        }
                        process.exit(404);
                        // process.kill(process.pid, "SIGINT");
                        break;
                    case "dumpwebsocketclients":
                        WebSocketServer_1.WebSocketServer.DumpClients();
                        break;
                    case "killwebsocketclient":
                        for (let i = WebSocketServer_1.WebSocketServer._clients.length - 1; i >= 0; i--) {
                            const cli = WebSocketServer_1.WebSocketServer._clients[i];
                            if (cli.id == msg.id) {
                                Logger_1.Logger.instanse.warn("amqpwrapper", "killwebsocketclient", "Killing websocket client " + msg.id);
                                cli.Close();
                            }
                        }
                        break;
                    default:
                        Logger_1.Logger.instanse.error("amqpwrapper", "AddOFExchange", new Error("[OF] Received unknown command: " + msg.command));
                        break;
                }
            }
            else {
                Logger_1.Logger.instanse.verbose("amqpwrapper", "AddOFExchange", "Received string message: " + JSON.stringify(msg));
            }
            done();
        }, parent);
    }
}
exports.amqpwrapper = amqpwrapper;
amqpwrapper._instance = null;
//# sourceMappingURL=amqpwrapper.js.map