raiden-ts
Version:
Raiden Light Client Typescript/Javascript SDK
97 lines • 6.12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.matrixUpdateCapsEpic = exports.matrixMonitorChannelPresenceEpic = exports.matrixMonitorPresenceEpic = void 0;
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
const isEqual_1 = __importDefault(require("lodash/isEqual"));
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const actions_1 = require("../../channels/actions");
const config_1 = require("../../config");
const utils_1 = require("../../services/utils");
const actions_2 = require("../../utils/actions");
const error_1 = require("../../utils/error");
const rx_1 = require("../../utils/rx");
const actions_3 = require("../actions");
const utils_2 = require("../utils");
/**
* Fetch peer's presence info from services
*
* @param address - Address of interest
* @param pfs$ - Observable of cached best PFS
* @param deps - Epics dependencies
* @returns Observable of user with most recent presence
*/
function searchAddressPresence$(address, pfs$, deps) {
return pfs$.pipe((0, operators_1.withLatestFrom)(deps.config$), (0, operators_1.concatMap)(([{ url }, { httpTimeout }]) => (0, utils_1.getPresenceFromService$)(address, url, deps).pipe((0, operators_1.timeout)(httpTimeout),
// this catchAndLog will suppress error and retry next PFS only if error is a networkError,
// otherwise (e.g. address offline) will error early and become matrixPresence.failure
(0, rx_1.catchAndLog)({ onErrors: error_1.networkErrors, log: deps.log.debug }, 'Error fetching presence from service', address, url))), (0, operators_1.first)(), (0, operators_1.catchError)((err) => (0, rxjs_1.of)(actions_3.matrixPresence.failure(err, { address }))));
}
/**
* Handles MatrixRequestMonitorPresenceAction and emits a MatrixPresenceUpdateAction
* If presence is already known, emits it, else fetch from user profile
* Even if the presence stays the same, we emit a MatrixPresenceUpdateAction, as this may be a
* request being waited by a promise or something like that
* IOW: every request should be followed by a presence update or a failed action, but presence
* updates may happen later without new requests (e.g. when the user goes offline)
*
* @param action$ - Observable of matrixPresence.request actions
* @param state$ - Observable of RaidenStates
* @param deps - RaidenEpicDeps members
* @param deps.matrix$ - MatrixClient async subject
* @param deps.log - Logger instance
* @param deps.config$ - Config observable
* @returns Observable of presence updates or fail action
*/
function matrixMonitorPresenceEpic(action$, {}, deps) {
const { latest$, config$ } = deps;
const cache = new Map();
const pfs$ = (0, utils_1.choosePfs$)(undefined, deps, true).pipe((0, operators_1.shareReplay)());
return action$.pipe((0, operators_1.tap)((action) => {
if (actions_3.matrixPresence.success.is(action))
cache.set(action.meta.address, action);
else if (actions_3.matrixPresence.failure.is(action))
cache.delete(action.meta.address);
}), (0, operators_1.filter)((0, actions_2.isActionOf)(actions_3.matrixPresence.request)),
// this mergeMap is like withLatestFrom, but waits until matrix$ emits its only value
(0, operators_1.groupBy)((action) => action.meta.address), (0, operators_1.mergeMap)((grouped$) => grouped$.pipe((0, operators_1.withLatestFrom)(latest$, config$),
// if we're already fetching presence for this address, no need to fetch again
(0, operators_1.exhaustMap)(([action, { rtc }, { pollingInterval }]) => {
const { address } = action.meta;
const cached = cache.get(address);
// we already fetched this peer's presence recently, or there's an RTC channel with them
if (cached && (Date.now() - cached.payload.ts < pollingInterval || address in rtc))
return (0, rxjs_1.of)(cached);
return searchAddressPresence$(address, pfs$, deps);
}))));
}
exports.matrixMonitorPresenceEpic = matrixMonitorPresenceEpic;
/**
* Channel monitoring triggers matrix presence monitoring for partner
*
* @param action$ - Observable of RaidenActions
* @returns Observable of matrixPresence.request actions
*/
function matrixMonitorChannelPresenceEpic(action$) {
return action$.pipe((0, operators_1.filter)(actions_1.channelMonitored.is), (0, operators_1.map)((action) => actions_3.matrixPresence.request(undefined, { address: action.meta.partner })));
}
exports.matrixMonitorChannelPresenceEpic = matrixMonitorChannelPresenceEpic;
/**
* Update our matrix's avatarUrl on config.caps on startup and changes
*
* @param action$ - Observable of RaidenActions
* @param state$ - Observable of RaidenStates
* @param deps - Epics dependencies
* @param deps.matrix$ - MatrixClient async subject
* @param deps.config$ - Config object
* @param deps.init$ - Init$ subject
* @returns Observable which never emits
*/
function matrixUpdateCapsEpic(action$, {}, { matrix$, config$, init$ }) {
return config$.pipe((0, rx_1.completeWith)(action$), (0, operators_1.pluck)('caps'), (0, operators_1.distinctUntilChanged)(isEqual_1.default), (0, operators_1.withLatestFrom)(init$.pipe((0, operators_1.ignoreElements)(), (0, operators_1.startWith)(false), (0, operators_1.endWith)(true))), (0, operators_1.switchMap)(([caps, synced]) => matrix$.pipe((0, rx_1.withMergeFrom)(async (matrix) => matrix.setAvatarUrl(caps && !(0, isEmpty_1.default)(caps) ? (0, utils_2.stringifyCaps)(caps) : '')), (0, operators_1.filter)(() => synced), (0, rx_1.withMergeFrom)(async ([matrix]) => matrix.setPresence({ presence: 'offline', status_msg: '' })), (0, rx_1.withMergeFrom)(async ([[matrix]]) => matrix.setPresence({ presence: 'online', status_msg: Date.now().toString() })), (0, rx_1.retryWhile)((0, config_1.intervalFromConfig)(config$)))), (0, operators_1.ignoreElements)());
}
exports.matrixUpdateCapsEpic = matrixUpdateCapsEpic;
//# sourceMappingURL=presence.js.map