raiden-ts
Version:
Raiden Light Client Typescript/Javascript SDK
92 lines • 3.78 kB
JavaScript
import { defer, merge, of } from 'rxjs';
import { filter, ignoreElements, take } from 'rxjs/operators';
import { messageSend } from '../../messages/actions';
import { isResponseOf } from '../../utils/actions';
import { completeWith, repeatUntil } from '../../utils/rx';
import { Direction } from '../state';
/**
* Exponential back-off infinite generator
*
* @param start - First yielded value
* @param max - Ceiling of values, won't increase above this number
* @param multiplier - Multiply yielded value by this factor on each iteration
* @yields Numbers representing delays in exponential backoff strategy of growth
*/
export function* exponentialBackoff(start = 1e3, max = 60e3, multiplier = 1.4) {
let delay = start;
while (true) {
yield delay;
delay = Math.min(max, Math.ceil(delay * multiplier));
}
}
/**
* Dispatches an actions and waits until a condition is satisfied.
*
* @param action$ - Observable of actions that will be monitored
* @param request - The request/action that will be dispatched
* @param predicate - The condition that will that was to be satisfied for the observable to
* complete
* @returns Observable of the request type.
*/
export function dispatchAndWait$(action$, request, predicate) {
return merge(
// wait until respective success/failure action is seen before completing
action$.pipe(filter(predicate), take(1),
// don't output success/failure action, just wait for first match to complete
ignoreElements()),
// output once
of(request));
}
/**
* Retry sending a message until some condition is met
*
* @param send - messageSend.request to be sent
* @param action$ - RaidenActions observable
* @param notifier - Stops retrying when this notifier emits
* @param delayMs - Delay between retries, or Iterator yielding delays
* @returns Observable which retry messageSend.request until notifier emits
*/
export function retrySendUntil$(send, action$, notifier, delayMs = 30e3) {
let first = true;
return defer(() => {
if (first) {
first = false;
}
else if (send.payload.userId) {
// from 1st retry on, pop payload.userId, to force re-fetch presence/metadata
const { userId: _, ...payload } = send.payload;
send = { ...send, payload };
}
return dispatchAndWait$(action$, send, isResponseOf(messageSend, send.meta));
}).pipe(repeatUntil(notifier, delayMs), completeWith(action$));
}
/**
* Creates a type-guard function which verifies 'msg' is of given type between withdraw messages
* and that total_withdraw and expiration matches given 'data'.
* May be used to find matching messages in [[ChannelEnd]]'s 'pendingWithdraws' array
*
* @param type - Literal type tag to filter
* @param data - Optional data to match, either in 'meta' or another 'message' format
* @returns Typeguard function to check for matching withdraw protocol messages
*/
export function matchWithdraw(type, data) {
return (msg) => msg.type === type &&
(!data ||
(msg.expiration.eq(data.expiration) &&
msg.total_withdraw.eq('totalWithdraw' in data ? data.totalWithdraw : data.total_withdraw)));
}
/**
* @param req - WithdrawRequest message
* @param channel - Channel in which it was received
* @returns withdraw async action meta for respective request
*/
export function withdrawMetaFromRequest(req, channel) {
return {
tokenNetwork: channel.tokenNetwork,
partner: channel.partner.address,
direction: req.participant === channel.partner.address ? Direction.RECEIVED : Direction.SENT,
expiration: req.expiration.toNumber(),
totalWithdraw: req.total_withdraw,
};
}
//# sourceMappingURL=utils.js.map