@emeraldpay/api
Version:
Common code for Emerald gRPC APIs
128 lines • 4.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnceSuccess = exports.AlwaysRepeat = exports.Retry = exports.isContinueCheck = void 0;
const Channel_1 = require("./Channel");
const Executor_1 = require("./Executor");
function isContinueCheck(checker) {
return (typeof checker === 'object' &&
checker != null &&
'shouldContinue' in checker &&
typeof checker.shouldContinue === 'function');
}
exports.isContinueCheck = isContinueCheck;
class Retry {
constructor(channel, executor, checker) {
this.status = Channel_1.ConnectionStatus.PENDING;
if (channel == null || !(0, Channel_1.isChannel)(channel)) {
throw new Error('Channel is not provided');
}
if (executor == null || !(0, Executor_1.isMethodExecutor)(executor)) {
throw new Error('Executor is not provided');
}
if (checker == null || !isContinueCheck(checker)) {
throw new Error('Continue checker is not provided');
}
this.channel = channel;
this.checker = checker;
this.executor = executor;
}
callWhenReady() {
if (!this.checker.shouldContinue()) {
this.notify(Channel_1.ConnectionStatus.CLOSED);
if (this.checker.failed === true) {
this.executor.terminate();
}
return;
}
this.notify(Channel_1.ConnectionStatus.CONNECTING);
const connection = this.channel.getState();
const isReady = (state, retry) => {
var _a, _b, _c, _d;
if (state === Channel_1.ConnectivityState.READY) {
(_b = (_a = this.checker).onConnected) === null || _b === void 0 ? void 0 : _b.call(_a);
this.executor.connected();
return true;
}
if (state === Channel_1.ConnectivityState.SHUTDOWN) {
this.checker.onClose();
return false;
}
if (state === Channel_1.ConnectivityState.TRANSIENT_FAILURE) {
(_d = (_c = this.checker).onFail) === null || _d === void 0 ? void 0 : _d.call(_c);
}
if (retry) {
setTimeout(this.callWhenReady.bind(this), 1000, this.executor, this.checker);
}
return false;
};
const execute = () => this.executor.execute(() => {
this.notify(Channel_1.ConnectionStatus.CONNECTING);
setTimeout(this.callWhenReady.bind(this), 1000, this.executor, this.checker);
});
if (isReady(connection, false)) {
this.notify(Channel_1.ConnectionStatus.CONNECTED);
execute();
}
else {
this.notify(Channel_1.ConnectionStatus.CONNECTING);
this.channel.watch(connection, 5000, (error, state) => {
var _a, _b;
if (error != null) {
(_b = (_a = this.checker).onFail) === null || _b === void 0 ? void 0 : _b.call(_a);
}
if (isReady(state, true)) {
execute();
}
});
}
}
setConnectionListener(listener) {
this.statusListener = listener;
listener(this.status);
}
notify(status) {
var _a;
if (status != this.status) {
this.status = status;
}
(_a = this.statusListener) === null || _a === void 0 ? void 0 : _a.call(this, status);
}
}
exports.Retry = Retry;
class AlwaysRepeat {
constructor(retries) {
this.counter = 0;
this.closed = false;
this.retries = retries;
}
get failed() {
return this.counter >= this.retries;
}
shouldContinue() {
return !this.failed && !this.closed;
}
onFail() {
this.counter += 1;
}
onClose() {
this.closed = true;
}
onSuccess() {
this.counter = 0;
}
}
exports.AlwaysRepeat = AlwaysRepeat;
class OnceSuccess extends AlwaysRepeat {
constructor() {
super(...arguments);
this.succeed = false;
}
shouldContinue() {
return !this.failed && !this.closed && !this.succeed;
}
onSuccess() {
this.succeed = true;
}
}
exports.OnceSuccess = OnceSuccess;
//# sourceMappingURL=Retry.js.map