"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetrySolanaRpcFactory = void 0;
var tslib_1 = require("tslib");
var kit_1 = require("@solana/kit");
var rpc_transformers_1 = require("@solana/rpc-transformers");
var baseRpcFactories_1 = require("./baseRpcFactories");
var rateLimitedRpcFactory_1 = require("./rateLimitedRpcFactory");
var svm_1 = require("../../arch/svm");
var utils_1 = require("../../utils");
var NetworkUtils_1 = require("../../utils/NetworkUtils");
var RetrySolanaRpcFactory = (function (_super) {
    tslib_1.__extends(RetrySolanaRpcFactory, _super);
    function RetrySolanaRpcFactory(retries, retryDelaySeconds) {
        var rateLimitedConstructorParams = [];
        for (var _i = 2; _i < arguments.length; _i++) {
            rateLimitedConstructorParams[_i - 2] = arguments[_i];
        }
        var _this = this;
        var superParams = rateLimitedConstructorParams.slice(-2);
        _this = _super.apply(this, superParams) || this;
        _this.retries = retries;
        _this.retryDelaySeconds = retryDelaySeconds;
        if (_this.retries < 0 || !Number.isInteger(_this.retries)) {
            throw new Error("retries cannot be < 0 and must be an integer. Currently set to ".concat(_this.retries));
        }
        if (_this.retryDelaySeconds < 0) {
            throw new Error("retryDelaySeconds cannot be < 0. Currently set to ".concat(_this.retryDelaySeconds));
        }
        var rateLimitedRpcFactory = new (rateLimitedRpcFactory_1.RateLimitedSolanaRpcFactory.bind.apply(rateLimitedRpcFactory_1.RateLimitedSolanaRpcFactory, tslib_1.__spreadArray([void 0], rateLimitedConstructorParams, false)))();
        _this.rateLimitedTransport = rateLimitedRpcFactory.createTransport();
        _this.logger = rateLimitedRpcFactory.logger;
        return _this;
    }
    RetrySolanaRpcFactory.prototype.createTransport = function () {
        var _this = this;
        return function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            return _this._tryCall(function () { return _this.rateLimitedTransport.apply(_this, args); }, args);
        };
    };
    RetrySolanaRpcFactory.prototype._tryCall = function (transportCall, args) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _a, method, params, retryAttempt, response, error_1, retryDelaySeconds, exponentialBackoff, jitter, delayS;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = args[0].payload, method = _a.method, params = _a.params;
                        retryAttempt = 0;
                        _b.label = 1;
                    case 1:
                        if (!true) return [3, 7];
                        _b.label = 2;
                    case 2:
                        _b.trys.push([2, 4, , 6]);
                        return [4, transportCall()];
                    case 3:
                        response = _b.sent();
                        (0, rpc_transformers_1.getThrowSolanaErrorResponseTransformer)()(response, { methodName: method, params: params });
                        return [2, response];
                    case 4:
                        error_1 = _b.sent();
                        if (retryAttempt++ >= this.retries || this.shouldFailImmediate(method, error_1)) {
                            throw error_1;
                        }
                        retryDelaySeconds = this.retryDelaySeconds;
                        exponentialBackoff = retryDelaySeconds * Math.pow(2, retryAttempt - 1);
                        jitter = 1 + 2 * Math.random();
                        delayS = this.isRateLimitResponse(error_1) ? exponentialBackoff + jitter : retryDelaySeconds;
                        this.logger.debug({
                            at: "RetryRpcFactory",
                            message: "Retrying Solana RPC call",
                            provider: (0, NetworkUtils_1.getOriginFromURL)(this.clusterUrl),
                            method: method,
                            retryAttempt: retryAttempt,
                            retryDelaySeconds: delayS,
                            error: error_1 === null || error_1 === void 0 ? void 0 : error_1.toString(),
                        });
                        return [4, (0, utils_1.delay)(delayS)];
                    case 5:
                        _b.sent();
                        return [3, 6];
                    case 6: return [3, 1];
                    case 7: return [2];
                }
            });
        });
    };
    RetrySolanaRpcFactory.prototype.shouldFailImmediate = function (method, error) {
        if (!(0, svm_1.isSolanaError)(error)) {
            return false;
        }
        switch (method) {
            default:
                return false;
        }
    };
    RetrySolanaRpcFactory.prototype.isRateLimitResponse = function (error) {
        if (!(0, svm_1.isSolanaError)(error)) {
            return false;
        }
        var code = error.context.__code;
        return code === kit_1.SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR && error.context.statusCode === 429;
    };
    return RetrySolanaRpcFactory;
}(baseRpcFactories_1.SolanaClusterRpcFactory));
exports.RetrySolanaRpcFactory = RetrySolanaRpcFactory;
//# sourceMappingURL=retryRpcFactory.js.map