UNPKG

raiden-ts

Version:

Raiden Light Client Typescript/Javascript SDK

149 lines 9.59 kB
"use strict"; 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