raiden-ts
Version:
Raiden Light Client Typescript/Javascript SDK
149 lines • 9.59 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transferClearCompletedEpic = exports.transferRequestResolveEpic = exports.initQueuePendingReceivedEpic = exports.initQueuePendingEnvelopeMessagesEpic = void 0;
const omit_1 = __importDefault(require("lodash/omit"));
const pick_1 = __importDefault(require("lodash/pick"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const constants_1 = require("../../constants");
const actions_1 = require("../../services/actions");
const actions_2 = require("../../transport/actions");
const utils_1 = require("../../transport/utils");
const rx_1 = require("../../utils/rx");
const types_1 = require("../../utils/types");
const actions_3 = require("../actions");
const state_1 = require("../state");
const utils_2 = require("../utils");
/**
* Re-queue pending transfer's BalanceProof/Envelope messages for retry on init
*
* @param action$ - Observable of RaidenActions
* @param state$ - Observable of RaidenStates
* @returns Observable of transferSigned|transferUnlock.success actions
*/
function initQueuePendingEnvelopeMessagesEpic({}, state$) {
return state$.pipe((0, operators_1.first)(), (0, operators_1.mergeMap)(({ transfers }) => (0, rxjs_1.from)(Object.values(transfers).filter((r) => r.direction === state_1.Direction.SENT &&
!r.unlockProcessed &&
!r.expiredProcessed &&
!r.secretRegistered &&
!r.channelClosed))), (0, operators_1.mergeMap)(function* (transferState) {
// loop over all pending transfers
const meta = {
secrethash: transferState.transfer.lock.secrethash,
direction: state_1.Direction.SENT,
};
// on init, request monitor presence of any pending transfer target
yield actions_2.matrixPresence.request(undefined, { address: transferState.transfer.target });
// Processed not received yet for LockedTransfer
if (!transferState.transferProcessed)
yield (0, actions_3.transferSigned)({
message: (0, types_1.untime)(transferState.transfer),
fee: transferState.fee,
partner: transferState.partner,
}, meta);
// already unlocked, but Processed not received yet for Unlock
if (transferState.unlock)
yield actions_3.transferUnlock.success({ message: (0, types_1.untime)(transferState.unlock), partner: transferState.partner }, meta);
// lock expired, but Processed not received yet for LockExpired
if (transferState.expired)
yield actions_3.transferExpire.success({ message: (0, types_1.untime)(transferState.expired), partner: transferState.partner }, meta);
}));
}
exports.initQueuePendingEnvelopeMessagesEpic = initQueuePendingEnvelopeMessagesEpic;
/**
* Re-queue pending Received transfer's
*
* @param action$ - Observable of RaidenActions
* @param state$ - Observable of RaidenStates
* @param deps - Epics dependencies
* @param deps.config$ - Config observable
* @returns Observable of transferSigned|transferUnlock.success actions
*/
function initQueuePendingReceivedEpic({}, state$, { config$ }) {
return state$.pipe((0, operators_1.first)(), (0, operators_1.mergeMap)(({ transfers }) => (0, rxjs_1.from)(Object.values(transfers).filter((r) => r.direction === state_1.Direction.RECEIVED &&
!r.unlock &&
!r.expired &&
!r.secretRegistered &&
!r.channelClosed))), (0, operators_1.mergeMap)((transferState) => {
// loop over all pending transfers
const secrethash = transferState.transfer.lock.secrethash;
const meta = { secrethash, direction: state_1.Direction.RECEIVED };
return (0, rxjs_1.merge)(
// on init, request monitor presence of any pending transfer initiator
(0, rxjs_1.of)((0, actions_3.transferSigned)({
message: (0, types_1.untime)(transferState.transfer),
fee: transferState.fee,
partner: transferState.partner,
}, meta)),
// already revealed to us, but user didn't sign SecretReveal yet
transferState.secret && !transferState.secretReveal
? (0, rxjs_1.of)((0, actions_3.transferSecret)({ secret: transferState.secret }, meta))
: rxjs_1.EMPTY,
// already revealed to sender, but they didn't Unlock yet
transferState.secretReveal
? (0, rxjs_1.of)((0, actions_3.transferSecretReveal)({ message: (0, types_1.untime)(transferState.secretReveal) }, meta))
: rxjs_1.EMPTY,
// secret not yet known; request *when* receiving is enabled (may be later)
// secretRequest should always be defined as we sign it when receiving transfer
!transferState.secret && transferState.secretRequest
? config$.pipe((0, operators_1.pluck)('caps'), (0, operators_1.filter)((caps) => !!(0, utils_1.getCap)(caps, constants_1.Capabilities.RECEIVE)), (0, operators_1.take)(1), (0, operators_1.mergeMapTo)((0, rxjs_1.of)(actions_2.matrixPresence.request(undefined, { address: transferState.transfer.initiator }), (0, actions_3.transferSecretRequest)({ message: (0, types_1.untime)(transferState.secretRequest) }, meta))))
: rxjs_1.EMPTY);
}));
}
exports.initQueuePendingReceivedEpic = initQueuePendingReceivedEpic;
/**
* @param action$ - Observable of unresolved transfer.request actions
* @param state$ - Observable of RaidenStates
* @param deps - Epics dependenceis
* @param deps.config$ - Config observable
* @returns Observable of pathFind.request and resolved transfer.request actions
*/
function transferRequestResolveEpic(action$, {}, { config$ }) {
return action$.pipe((0, rx_1.dispatchRequestAndGetResponse)(actions_1.pathFind, (dispatch) => action$.pipe((0, operators_1.filter)(actions_3.transfer.request.is), (0, operators_1.filter)((action) => !action.payload.resolved), (0, operators_1.mergeMap)((action) => dispatch(actions_1.pathFind.request((0, pick_1.default)(action.payload, ['paths', 'pfs']), (0, pick_1.default)(action.payload, ['tokenNetwork', 'target', 'value']))).pipe((0, operators_1.withLatestFrom)(action$.pipe((0, operators_1.filter)(actions_2.matrixPresence.success.is), (0, operators_1.filter)((a) => a.meta.address === action.payload.target)), config$), (0, operators_1.map)(([route, targetPresence, { encryptSecret }]) => {
let encryptSecretOptions;
if ((action.payload.encryptSecret ?? encryptSecret) && action.payload.secret)
encryptSecretOptions = {
secret: action.payload.secret,
amount: action.payload.value,
payment_identifier: action.payload.paymentId,
};
const resolvedPayload = (0, utils_2.metadataFromPaths)(route.payload.paths, targetPresence, encryptSecretOptions);
const restPayload = (0, omit_1.default)(action.payload, ['paths', 'pfs', 'encryptSecret']);
const requestOptions = { ...restPayload, ...resolvedPayload };
return actions_3.transfer.request(requestOptions, action.meta);
}), (0, operators_1.catchError)((err) => (0, rxjs_1.of)(actions_3.transfer.failure(err, action.meta))))))));
}
exports.transferRequestResolveEpic = transferRequestResolveEpic;
function hasTransferMeta(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
action) {
return 'meta' in action && action.meta?.secrethash && action.meta?.direction;
}
/**
* Clear transfer from state after it's completed and some timeout of inactivity
* It should still get saved (by persister) on database, but is freed from memory.
*
* @param action$ - Observable of RaidenActions
* @param state$ - Observable of RaidenStates
* @param deps - Epics dependencies
* @param deps.config$ - Config observable
* @returns Observable of transferClear actions
*/
function transferClearCompletedEpic(action$, state$, { config$ }) {
return state$.pipe((0, rx_1.pluckDistinct)('transfers'), (0, rx_1.distinctRecordValues)(), (0, operators_1.groupBy)(([key]) => key, // group per transfer
// cleanup when transfer is cleared
{ duration: ({ key }) => state$.pipe((0, operators_1.filter)(({ transfers }) => !(key in transfers))) }), (0, operators_1.withLatestFrom)(config$), (0, operators_1.mergeMap)(([grouped$, { httpTimeout }]) => grouped$.pipe(
// when transfer completes or there's nothing else to do with it
(0, operators_1.filter)(([, transfer]) => !!(transfer.unlockProcessed || transfer.expiredProcessed || transfer.channelSettled)), (0, operators_1.take)(1), (0, operators_1.mergeMap)(([, transfer]) =>
// in case any new "activity" happens on this transfer, bump debounceTimer'r
action$.pipe((0, operators_1.filter)(hasTransferMeta), (0, operators_1.filter)((action) => (0, utils_2.transferKey)(action.meta) === grouped$.key), (0, operators_1.startWith)({ meta: (0, pick_1.default)(transfer, ['secrethash', 'direction']) }), (0, rx_1.completeWith)(grouped$))),
// after some time with no action for this transfer going through (e.g. Processed retries)
(0, operators_1.debounceTime)(3 * httpTimeout), (0, operators_1.map)(({ meta }) => (0, actions_3.transferClear)(undefined, meta)))),
// no need to transferClear on shutdown; let any pending transfer be cleared on next run
(0, rx_1.completeWith)(action$));
}
exports.transferClearCompletedEpic = transferClearCompletedEpic;
//# sourceMappingURL=init.js.map