UNPKG

sendingnetwork-bot-sdk

Version:
129 lines 6.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProfileCache = void 0; const LRU = require("lru-cache"); const __1 = require(".."); const MembershipEvent_1 = require("../models/events/MembershipEvent"); /** * Functions for avoiding calls to profile endpoints. Useful for bots when * people are mentioned often or bridges which need profile information * often. * @category Utilities */ class ProfileCache { /** * Creates a new profile cache. * @param {number} maxEntries The maximum number of entries to cache. * @param {number} maxAgeMs The maximum age of an entry in milliseconds. * @param {SDNClient} client The client to use to get profile updates. */ constructor(maxEntries, maxAgeMs, client) { this.client = client; this.cache = new LRU({ max: maxEntries, ttl: maxAgeMs, }); } getCacheKey(userId, roomId) { return `${userId}@${roomId || '<none>'}`; } /** * Watch for profile changes to cached entries with the provided client. The * same client will also be used to update the user's profile in the cache. * @param {SDNClient} client The client to watch for profile changes with. */ watchWithClient(client) { client.on("room.event", (roomId, event) => __awaiter(this, void 0, void 0, function* () { if (!event['state_key'] || !event['content'] || event['type'] !== 'm.room.member') return; yield this.tryUpdateProfile(roomId, new MembershipEvent_1.MembershipEvent(event), client); })); } /** * Watch for profile changes to cached entries with the provided application * service. The clientFn will be called to get the relevant client for any * updates. If the clientFn is null, the appservice's bot user will be used. * The clientFn takes two arguments: the user ID being updated and the room ID * they are being updated in (shouldn't be null). The return value should be the * SDNClient to use, or null to use the appservice's bot client. The same * client will be used to update the user's general profile, if that profile * is cached. * @param {Appservice} appservice The application service to watch for profile changes with. * @param {Function} clientFn The function to use to acquire profile updates with. If null, the appservice's bot client will be used. */ watchWithAppservice(appservice, clientFn = null) { if (!clientFn) clientFn = () => appservice.botClient; appservice.on("room.event", (roomId, event) => __awaiter(this, void 0, void 0, function* () { if (!event['state_key'] || !event['content'] || event['type'] !== 'm.room.member') return; const memberEvent = new MembershipEvent_1.MembershipEvent(event); let client = clientFn(memberEvent.membershipFor, roomId); if (!client) client = appservice.botClient; yield this.tryUpdateProfile(roomId, memberEvent, client); })); } /** * Gets a profile for a user in optional room. * @param {string} userId The user ID to get a profile for. * @param {string|null} roomId Optional room ID to get a per-room profile for the user. * @returns {Promise<SDNProfile>} Resolves to the user's profile. */ getUserProfile(userId, roomId = null) { return __awaiter(this, void 0, void 0, function* () { const cacheKey = this.getCacheKey(userId, roomId); const cached = this.cache.get(cacheKey); if (cached) return Promise.resolve(cached); const profile = yield this.getUserProfileWith(userId, roomId, this.client); this.cache.set(cacheKey, profile); return profile; }); } getUserProfileWith(userId, roomId, client) { return __awaiter(this, void 0, void 0, function* () { try { if (roomId) { const membership = yield client.getRoomStateEvent(roomId, "m.room.member", userId); return new __1.SDNProfile(userId, membership); } else { const profile = yield client.getUserProfile(userId); return new __1.SDNProfile(userId, profile); } } catch (e) { __1.LogService.warn("ProfileCache", "Non-fatal error getting user profile. They might not exist."); __1.LogService.warn("ProfileCache", (0, __1.extractRequestError)(e)); return new __1.SDNProfile(userId, {}); } }); } tryUpdateProfile(roomId, memberEvent, client) { return __awaiter(this, void 0, void 0, function* () { const roomCacheKey = this.getCacheKey(memberEvent.membershipFor, roomId); const generalCacheKey = this.getCacheKey(memberEvent.membershipFor, null); if (this.cache.has(roomCacheKey)) { this.cache.set(roomCacheKey, new __1.SDNProfile(memberEvent.membershipFor, memberEvent.content)); } // TODO: Try and figure out semantics for this updating. // Large accounts could cause hammering on the profile endpoint, but hopefully it is cached by the server. if (this.cache.has(generalCacheKey)) { const profile = yield this.getUserProfileWith(memberEvent.membershipFor, null, client); this.cache.set(generalCacheKey, profile); } }); } } exports.ProfileCache = ProfileCache; //# sourceMappingURL=ProfileCache.js.map