"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
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 __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.amqpwrapper = exports.amqpexchange = exports.amqpqueue = exports.Deferred = void 0;
var retry = require("async-retry");
var amqplib = require("amqplib");
var Config_1 = require("./Config");
var Crypt_1 = require("./Crypt");
var url = require("url");
var openflow_api_1 = require("@openiap/openflow-api");
var WebSocketServer_1 = require("./WebSocketServer");
var Logger_1 = require("./Logger");
var got = require("got");
var Deferred = /** @class */ (function () {
    function Deferred() {
        var me = this;
        this.promise = new Promise(function (resolve, reject) {
            me.reject = reject;
            me.resolve = resolve;
        });
    }
    return Deferred;
}());
exports.Deferred = Deferred;
var amqpqueue = /** @class */ (function () {
    function amqpqueue() {
    }
    return amqpqueue;
}());
exports.amqpqueue = amqpqueue;
var amqpexchange = /** @class */ (function () {
    function amqpexchange() {
    }
    return amqpexchange;
}());
exports.amqpexchange = amqpexchange;
// tslint:disable-next-line: class-name
var amqpwrapper = /** @class */ (function () {
    function amqpwrapper(connectionstring) {
        this.AssertExchangeOptions = { durable: false, confirm: true };
        this.AssertQueueOptions = { durable: true };
        this.activecalls = {};
        // public queues: IHashTable<amqpqueue> = {};
        // private exchanges: IHashTable<amqpexchange> = {};
        // public queues: amqpqueue[] = [];
        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;
        }
    }
    amqpwrapper.Instance = function () {
        return this._instance;
    };
    amqpwrapper.SetInstance = function (instance) {
        this._instance = instance;
    };
    amqpwrapper.prototype.incqueuemessagecounter = function (queuename) {
        var result = 0;
        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(this.queuemessagecounter[queuename]))
            result = this.queuemessagecounter[queuename];
        result++;
        this.queuemessagecounter[queuename] = result;
        return result;
    };
    amqpwrapper.prototype.connect = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, _b, _c, error_1;
            var _this = this;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        _d.trys.push([0, 5, , 6]);
                        if (this.timeout != null) {
                            this.timeout = null;
                        }
                        if (!(this.conn == null)) return [3 /*break*/, 2];
                        _a = this;
                        return [4 /*yield*/, amqplib.connect(this.connectionstring)];
                    case 1:
                        _a.conn = _d.sent();
                        this.conn.on('error', function (error) {
                            if (error.code != 404) {
                                Logger_1.Logger.instanse.error(error);
                            }
                        });
                        this.conn.on("close", function () {
                            Logger_1.Logger.instanse.info("[AMQP] reconnecting");
                            _this.conn = null;
                            if (_this.timeout == null) {
                                _this.timeout = setTimeout(_this.connect.bind(_this), 1000);
                            }
                        });
                        _d.label = 2;
                    case 2:
                        _b = this;
                        return [4 /*yield*/, this.conn.createConfirmChannel()];
                    case 3:
                        _b.channel = _d.sent();
                        _c = this;
                        return [4 /*yield*/, this.AddQueueConsumer("", null, null, function (msg, options, ack, done) {
                                if (_this.replyqueue) {
                                    if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                                        WebSocketServer_1.WebSocketServer.websocket_queue_message_count.
                                            bind(__assign(__assign({}, Logger_1.Logger.otel.defaultlabels), { queuename: _this.replyqueue.queue })).update(_this.incqueuemessagecounter(_this.replyqueue.queue));
                                    if (!openflow_api_1.NoderedUtil.IsNullUndefinded(_this.activecalls[options.correlationId])) {
                                        _this.activecalls[options.correlationId].resolve(msg);
                                        _this.activecalls[options.correlationId] = null;
                                        delete _this.activecalls[options.correlationId];
                                    }
                                }
                                ack();
                                done();
                            }, undefined)];
                    case 4:
                        _c.replyqueue = _d.sent();
                        this.channel.on('close', function (e) {
                            try {
                                if (_this.conn != null)
                                    _this.conn.close();
                            }
                            catch (error) {
                            }
                            _this.conn = null;
                            _this.channel = null;
                            if (_this.timeout == null) {
                                _this.timeout = setTimeout(_this.connect.bind(_this), 1000);
                            }
                        });
                        this.channel.on('error', function (error) {
                            if (error.code != 404) {
                                Logger_1.Logger.instanse.error(error);
                            }
                        });
                        return [3 /*break*/, 6];
                    case 5:
                        error_1 = _d.sent();
                        console.error(error_1);
                        this.timeout = setTimeout(this.connect.bind(this), 1000);
                        return [3 /*break*/, 6];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.RemoveQueueConsumer = function (queue, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, error_2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.validateToken", parent);
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 4, 5, 6]);
                        if (!(queue != null)) return [3 /*break*/, 3];
                        Logger_1.Logger.instanse.info("[AMQP] Remove queue consumer " + queue.queue + "/" + queue.consumerTag);
                        if (!(this.channel != null)) return [3 /*break*/, 3];
                        return [4 /*yield*/, this.channel.cancel(queue.consumerTag)];
                    case 2:
                        _a.sent();
                        _a.label = 3;
                    case 3: return [3 /*break*/, 6];
                    case 4:
                        error_2 = _a.sent();
                        span.recordException(error_2);
                        throw error_2;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.AddQueueConsumer = function (queuename, QueueOptions, jwt, callback, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, queue_1, tuser, name_1, skip, isrole, arr, arr_1, arr_2, tuser, name_2, tuser, isrole, skip, arr, arr_3, arr_4, q_1, _a, consumeresult, error_3;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.validateToken", parent);
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 21, 22, 23]);
                        if (this.channel == null || this.conn == null)
                            throw new Error("Cannot Add new Queue Consumer, not connected to rabbitmq");
                        queue_1 = (openflow_api_1.NoderedUtil.IsNullEmpty(queuename) ? "" : queuename);
                        if (!(Config_1.Config.amqp_force_queue_prefix && !openflow_api_1.NoderedUtil.IsNullEmpty(jwt) && !openflow_api_1.NoderedUtil.IsNullEmpty(queue_1))) return [3 /*break*/, 11];
                        if (!(queue_1.length == 24)) return [3 /*break*/, 9];
                        tuser = Crypt_1.Crypt.verityToken(jwt);
                        name_1 = tuser.username.split("@").join("").split(".").join("");
                        name_1 = name_1.toLowerCase();
                        skip = false;
                        if (tuser._id == queue_1) {
                            // Queue is for me
                            skip = false;
                        }
                        else if (tuser.roles != null) {
                            isrole = tuser.roles.filter(function (x) { return x._id == queue_1; });
                            if (isrole.length > 0)
                                skip = false;
                        }
                        if (!skip) return [3 /*break*/, 7];
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "users", jwt, undefined, undefined, span)];
                    case 2:
                        arr = _b.sent();
                        if (arr.length == 0)
                            skip = true;
                        if (!!skip) return [3 /*break*/, 4];
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "openrpa", jwt, undefined, undefined, span)];
                    case 3:
                        arr_1 = _b.sent();
                        if (arr_1.length == 0)
                            skip = true;
                        _b.label = 4;
                    case 4:
                        if (!!skip) return [3 /*break*/, 6];
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "workflow", jwt, undefined, undefined, span)];
                    case 5:
                        arr_2 = _b.sent();
                        if (arr_2.length == 0)
                            skip = true;
                        _b.label = 6;
                    case 6:
                        if (!skip) {
                            queue_1 = name_1 + queue_1;
                        }
                        else {
                            Logger_1.Logger.instanse.info("[SKIP] skipped force prefix for " + queue_1);
                        }
                        return [3 /*break*/, 8];
                    case 7:
                        Logger_1.Logger.instanse.info("[SKIP] skipped force prefix for " + queue_1);
                        _b.label = 8;
                    case 8: return [3 /*break*/, 10];
                    case 9:
                        tuser = Crypt_1.Crypt.verityToken(jwt);
                        name_2 = tuser.username.split("@").join("").split(".").join("");
                        name_2 = name_2.toLowerCase();
                        queue_1 = name_2 + queue_1;
                        _b.label = 10;
                    case 10: return [3 /*break*/, 17];
                    case 11:
                        if (!(queue_1.length == 24)) return [3 /*break*/, 17];
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(jwt)) return [3 /*break*/, 17];
                        tuser = Crypt_1.Crypt.verityToken(jwt);
                        isrole = tuser.roles.filter(function (x) { return x._id == queue_1; });
                        if (!(isrole.length == 0 && tuser._id != queue_1)) return [3 /*break*/, 17];
                        skip = false;
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "users", jwt, undefined, undefined, span)];
                    case 12:
                        arr = _b.sent();
                        if (arr.length == 0)
                            skip = true;
                        if (!!skip) return [3 /*break*/, 14];
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "openrpa", jwt, undefined, undefined, span)];
                    case 13:
                        arr_3 = _b.sent();
                        if (arr_3.length == 0)
                            skip = true;
                        _b.label = 14;
                    case 14:
                        if (!!skip) return [3 /*break*/, 16];
                        return [4 /*yield*/, Config_1.Config.db.query({ _id: queue_1 }, { name: 1 }, 1, 0, null, "workflow", jwt, undefined, undefined, span)];
                    case 15:
                        arr_4 = _b.sent();
                        if (arr_4.length == 0)
                            skip = true;
                        _b.label = 16;
                    case 16:
                        if (!skip) {
                            throw new Error("Access denied creating consumer for " + queue_1);
                        }
                        _b.label = 17;
                    case 17:
                        q_1 = new amqpqueue();
                        q_1.callback = callback;
                        q_1.QueueOptions = Object.assign({}, (QueueOptions != null ? QueueOptions : this.AssertQueueOptions));
                        if (openflow_api_1.NoderedUtil.IsNullEmpty(queue_1))
                            queue_1 = "";
                        if (queue_1.startsWith("amq."))
                            queue_1 = "";
                        if (openflow_api_1.NoderedUtil.IsNullEmpty(queue_1))
                            q_1.QueueOptions.autoDelete = true;
                        _a = q_1;
                        return [4 /*yield*/, this.channel.assertQueue(queue_1, q_1.QueueOptions)];
                    case 18:
                        _a.ok = _b.sent();
                        if (!(q_1 && q_1.ok)) return [3 /*break*/, 20];
                        q_1.queue = q_1.ok.queue;
                        q_1.queuename = queuename;
                        return [4 /*yield*/, this.channel.consume(q_1.ok.queue, function (msg) {
                                _this.OnMessage(q_1, msg, q_1.callback);
                            }, { noAck: false })];
                    case 19:
                        consumeresult = _b.sent();
                        q_1.consumerTag = consumeresult.consumerTag;
                        Logger_1.Logger.instanse.info("[AMQP] Added queue consumer " + q_1.queue + "/" + q_1.consumerTag);
                        _b.label = 20;
                    case 20: return [2 /*return*/, q_1];
                    case 21:
                        error_3 = _b.sent();
                        span.recordException(error_3);
                        throw error_3;
                    case 22:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 23: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.AddExchangeConsumer = function (exchange, algorithm, routingkey, ExchangeOptions, jwt, callback, parent) {
        return __awaiter(this, void 0, void 0, function () {
            var span, tuser, name_3, q, _ok, AssertQueueOptions, _a, error_4;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        span = Logger_1.Logger.otel.startSubSpan("amqpwrapper.validateToken", parent);
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 4, 5, 6]);
                        if (this.channel == null || this.conn == null)
                            throw new Error("Cannot Add new Exchange Consumer, not connected to rabbitmq");
                        if (Config_1.Config.amqp_force_exchange_prefix && !openflow_api_1.NoderedUtil.IsNullEmpty(jwt)) {
                            tuser = Crypt_1.Crypt.verityToken(jwt);
                            name_3 = tuser.username.split("@").join("").split(".").join("");
                            name_3 = name_3.toLowerCase();
                            exchange = name_3 + exchange;
                        }
                        q = new amqpexchange();
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(q.queue)) {
                            this.RemoveQueueConsumer(q.queue, span);
                        }
                        // q.ExchangeOptions = new Object((ExchangeOptions != null ? ExchangeOptions : this.AssertExchangeOptions));
                        q.ExchangeOptions = Object.assign({}, (ExchangeOptions != null ? ExchangeOptions : this.AssertExchangeOptions));
                        q.exchange = exchange;
                        q.algorithm = algorithm;
                        q.routingkey = routingkey;
                        q.callback = callback;
                        return [4 /*yield*/, this.channel.assertExchange(q.exchange, q.algorithm, q.ExchangeOptions)];
                    case 2:
                        _ok = _b.sent();
                        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;
                        }
                        _a = q;
                        return [4 /*yield*/, this.AddQueueConsumer("", AssertQueueOptions, jwt, q.callback, span)];
                    case 3:
                        _a.queue = _b.sent();
                        if (q.queue) {
                            this.channel.bindQueue(q.queue.queue, q.exchange, q.routingkey);
                            Logger_1.Logger.instanse.info("[AMQP] Added exchange consumer " + q.exchange + ' to queue ' + q.queue.queue);
                        }
                        this.exchanges.push(q);
                        return [2 /*return*/, q];
                    case 4:
                        error_4 = _b.sent();
                        span.recordException(error_4);
                        throw error_4;
                    case 5:
                        Logger_1.Logger.otel.endSpan(span);
                        return [7 /*endfinally*/];
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.OnMessage = function (sender, msg, callback) {
        var _this = this;
        // Logger.instanse.info("OnMessage " + msg.content.toString());
        try {
            var now = new Date();
            // const seconds = (now.getTime() - sender.cli.lastheartbeat.getTime()) / 1000;
            // if (seconds >= Config.client_heartbeat_timeout) {
            //     try {
            //         Logger.instanse.info("amqpwrapper.OnMessage: receive message for inactive client, nack message and try and close");
            //         this.channel.nack(msg);
            //         sender.cli.Close();
            //     } catch (error) {
            //         console.error(error);
            //     }
            //     return;
            // }
            if (msg == null) {
                return;
            }
            var correlationId = msg.properties.correlationId;
            var replyTo = msg.properties.replyTo;
            var consumerTag = msg.fields.consumerTag;
            var routingkey = msg.fields.routingkey;
            var exchange = msg.fields.exchange;
            var options = {
                correlationId: correlationId,
                replyTo: replyTo,
                consumerTag: consumerTag,
                routingkey: routingkey,
                exchange: exchange
            };
            var data = msg.content.toString();
            callback(data, options, function (nack) {
                try {
                    if (nack == false) {
                        _this.channel.nack(msg);
                        // this.channel.nack(msg, false, true);
                        msg = null;
                        return;
                    }
                    _this.channel.ack(msg);
                }
                catch (error) {
                    console.error(error);
                }
            }, function (result) {
                // ROLLBACK
                // if (msg != null && !NoderedUtil.IsNullEmpty(replyTo)) {
                //     try {
                //         this.channel.sendToQueue(replyTo, Buffer.from(result), { correlationId: msg.properties.correlationId });
                //     } catch (error) {
                //         console.error("Error sending response to " + replyTo + " " + JSON.stringify(error))
                //     }
                // }
            });
        }
        catch (error) {
            console.error(error);
        }
    };
    amqpwrapper.prototype.sendWithReply = function (exchange, queue, data, expiration, correlationId) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
                            correlationId = this.generateUuid();
                        this.activecalls[correlationId] = new Deferred();
                        if (!this.replyqueue) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.sendWithReplyTo(exchange, queue, this.replyqueue.queue, data, expiration, correlationId)];
                    case 1:
                        _a.sent();
                        _a.label = 2;
                    case 2: return [2 /*return*/, this.activecalls[correlationId].promise];
                }
            });
        });
    };
    amqpwrapper.prototype.sendWithReplyTo = function (exchange, queue, replyTo, data, expiration, correlationId) {
        return __awaiter(this, void 0, void 0, function () {
            var options;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        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.info("send to queue: " + queue + " exchange: " + exchange + " with reply to " + replyTo);
                        options = { mandatory: true };
                        options.replyTo = replyTo;
                        if (openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
                            correlationId = this.generateUuid();
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(correlationId))
                            options.correlationId = correlationId;
                        if (expiration < 1)
                            expiration = Config_1.Config.amqp_default_expiration;
                        options.expiration = expiration.toString();
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(exchange)) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.checkQueue(queue)];
                    case 1:
                        if (!(_a.sent())) {
                            throw new Error("No consumer listening at " + queue);
                        }
                        if (!this.channel.sendToQueue(queue, Buffer.from(data), options, function (err, ok) {
                        })) {
                            throw new Error("No consumer listening at " + queue);
                        }
                        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                            WebSocketServer_1.WebSocketServer.websocket_queue_message_count.
                                bind(__assign(__assign({}, Logger_1.Logger.otel.defaultlabels), { queuename: queue })).update(this.incqueuemessagecounter(queue));
                        return [3 /*break*/, 3];
                    case 2:
                        this.channel.publish(exchange, "", Buffer.from(data), options);
                        _a.label = 3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.send = function (exchange, queue, data, expiration, correlationId) {
        return __awaiter(this, void 0, void 0, function () {
            var options;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        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 = this.generateUuid();
                        Logger_1.Logger.instanse.info("send to queue: " + queue + " exchange: " + exchange);
                        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();
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(exchange)) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.checkQueue(queue)];
                    case 1:
                        if (!(_a.sent())) {
                            throw new Error("No consumer listening at " + queue);
                        }
                        if (!this.channel.sendToQueue(queue, Buffer.from(data), options, function (err, ok) {
                        })) {
                            throw new Error("No consumer listening at " + queue);
                        }
                        if (!openflow_api_1.NoderedUtil.IsNullUndefinded(WebSocketServer_1.WebSocketServer.websocket_queue_message_count))
                            WebSocketServer_1.WebSocketServer.websocket_queue_message_count.
                                bind(__assign(__assign({}, Logger_1.Logger.otel.defaultlabels), { queuename: queue })).update(this.incqueuemessagecounter(queue));
                        return [3 /*break*/, 3];
                    case 2:
                        this.channel.publish(exchange, "", Buffer.from(data), options);
                        _a.label = 3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    amqpwrapper.prototype.generateUuid = function () {
        return Math.random().toString() +
            Math.random().toString() +
            Math.random().toString();
    };
    amqpwrapper.parseurl = function (amqp_url) {
        var q = url.parse(amqp_url, true);
        q.username = "guest";
        q.password = "guest";
        if (q.port == null || q.port == "") {
            q.port = "15672";
        }
        if (q.auth != null && q.auth != "") {
            var arr = q.auth.split(':');
            q.username = arr[0];
            q.password = arr[1];
        }
        q.protocol = 'http://';
        return q;
    };
    // This will crash the channel, that does not seem scalable
    amqpwrapper.prototype.checkQueue = function (queuename) {
        return __awaiter(this, void 0, void 0, function () {
            var test, error_5;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!Config_1.Config.amqp_check_for_consumer) return [3 /*break*/, 5];
                        test = null;
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        if (Config_1.Config.amqp_check_for_consumer_count) {
                            return [2 /*return*/, this.checkQueueConsumerCount(queuename)];
                        }
                        return [4 /*yield*/, amqpwrapper.getqueue(Config_1.Config.amqp_url, '/', queuename)];
                    case 2:
                        test = _a.sent();
                        if (test == null) {
                            return [2 /*return*/, false];
                        }
                        return [3 /*break*/, 4];
                    case 3:
                        error_5 = _a.sent();
                        test = null;
                        return [3 /*break*/, 4];
                    case 4:
                        if (test == null || test.consumerCount == 0) {
                            return [2 /*return*/, false];
                        }
                        _a.label = 5;
                    case 5: return [2 /*return*/, true];
                }
            });
        });
    };
    amqpwrapper.prototype.checkQueueConsumerCount = function (queuename) {
        return __awaiter(this, void 0, void 0, function () {
            var result, error_6;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        result = false;
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, retry(function (bail) { return __awaiter(_this, void 0, void 0, function () {
                                var queue, hasConsumers;
                                return __generator(this, function (_a) {
                                    switch (_a.label) {
                                        case 0: return [4 /*yield*/, amqpwrapper.getqueue(Config_1.Config.amqp_url, '/', queuename)];
                                        case 1:
                                            queue = _a.sent();
                                            hasConsumers = false;
                                            if (queue.consumers > 0) {
                                                hasConsumers = true;
                                            }
                                            if (!hasConsumers) {
                                                if (queue.consumer_details != null && queue.consumer_details.length > 0) {
                                                    hasConsumers = true;
                                                }
                                                else {
                                                    hasConsumers = false;
                                                }
                                            }
                                            if (hasConsumers == false) {
                                                hasConsumers = false;
                                                throw new Error("No consumer listening at " + queuename);
                                                // return bail();
                                            }
                                            return [2 /*return*/, hasConsumers];
                                    }
                                });
                            }); }, {
                                retries: 10,
                                minTimeout: 500,
                                maxTimeout: 500,
                                onRetry: function (error, count) {
                                    result = false;
                                    console.warn("retry " + count + " error " + error.message + " getting " + url);
                                }
                            })];
                    case 2:
                        result = _a.sent();
                        return [3 /*break*/, 4];
                    case 3:
                        error_6 = _a.sent();
                        Logger_1.Logger.instanse.debug(error_6.message ? error_6.message : error_6);
                        return [3 /*break*/, 4];
                    case 4:
                        if (result == true) {
                            return [2 /*return*/, result];
                        }
                        return [2 /*return*/, false];
                }
            });
        });
    };
    amqpwrapper.getvhosts = function (amqp_url) {
        return __awaiter(this, void 0, void 0, function () {
            var q, options, _url, response, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        q = this.parseurl(amqp_url);
                        options = {
                            headers: {
                                'Content-type': 'application/x-www-form-urlencoded'
                            },
                            username: q.username,
                            password: q.password
                        };
                        _url = 'http://' + q.host + ':' + q.port + '/api/vhosts';
                        return [4 /*yield*/, got.get(_url, options)];
                    case 1:
                        response = _a.sent();
                        payload = JSON.parse(response.body);
                        return [2 /*return*/, payload];
                }
            });
        });
    };
    amqpwrapper.getqueues = function (amqp_url, vhost) {
        if (vhost === void 0) { vhost = null; }
        return __awaiter(this, void 0, void 0, function () {
            var q, options, _url, response, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        q = this.parseurl(amqp_url);
                        options = {
                            headers: {
                                'Content-type': 'application/x-www-form-urlencoded'
                            },
                            username: q.username,
                            password: q.password
                        };
                        _url = 'http://' + q.host + ':' + q.port + '/api/queues';
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(vhost))
                            _url += '/' + encodeURIComponent(vhost);
                        return [4 /*yield*/, got.get(_url, options)];
                    case 1:
                        response = _a.sent();
                        payload = JSON.parse(response.body);
                        return [2 /*return*/, payload];
                }
            });
        });
    };
    amqpwrapper.getqueue = function (amqp_url, vhost, queuename) {
        return __awaiter(this, void 0, void 0, function () {
            var q, options, _url, response, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        q = this.parseurl(amqp_url);
                        options = {
                            headers: {
                                'Content-type': 'application/x-www-form-urlencoded'
                            },
                            username: q.username,
                            password: q.password,
                            timeout: 500, retry: 1
                        };
                        _url = 'http://' + q.host + ':' + q.port + '/api/queues/' + encodeURIComponent(vhost) + '/' + encodeURIComponent(queuename);
                        return [4 /*yield*/, got.get(_url, options)];
                    case 1:
                        response = _a.sent();
                        payload = JSON.parse(response.body);
                        return [2 /*return*/, payload];
                }
            });
        });
    };
    amqpwrapper.deletequeue = function (amqp_url, vhost, queuename) {
        return __awaiter(this, void 0, void 0, function () {
            var q, options, _url, response, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        q = this.parseurl(amqp_url);
                        options = {
                            headers: {
                                'Content-type': 'application/x-www-form-urlencoded'
                            },
                            username: q.username,
                            password: q.password,
                            timeout: 500, retry: 1
                        };
                        _url = 'http://' + q.host + ':' + q.port + '/api/queues/' + encodeURIComponent(vhost) + '/' + encodeURIComponent(queuename);
                        return [4 /*yield*/, got.delete(_url, options)];
                    case 1:
                        response = _a.sent();
                        payload = JSON.parse(response.body);
                        return [2 /*return*/, payload];
                }
            });
        });
    };
    amqpwrapper._instance = null;
    return amqpwrapper;
}());
exports.amqpwrapper = amqpwrapper;
//# sourceMappingURL=amqpwrapper.js.map