import * as LRU from "lru-cache" ; import { extractRequestError , LogService , MatrixClient , MatrixProfile } from ".." ; import { MembershipEvent } from "../models/events/MembershipEvent" ; import { Appservice } from "../appservice/Appservice" ; category export class ProfileCache { private cache : LRU ; param { number } maxEntries param { number } maxAgeMs param { MatrixClient } client constructor ( maxEntries , maxAgeMs , private client ) { this . cache = new LRU ( { max : maxEntries , maxAge : maxAgeMs , } ) ; } private getCacheKey ( userId , roomId ) { return `${ userId }@${ roomId || '<none>' }` ; } param { MatrixClient } client public watchWithClient ( client ) { client . on ( "room.event" , async ( roomId , event ) => { if ( ! event [ 'state_key' ] || ! event [ 'content' ] || event [ 'type' ] !== 'm.room.member' ) return ; await this . tryUpdateProfile ( roomId , new MembershipEvent ( event ) , client ) ; } ) ; } param { Appservice } appservice param { Function } clientFn public watchWithAppservice ( appservice , clientFn = null ) { if ( ! clientFn ) clientFn = ( ) => appservice . botClient ; appservice . on ( "room.event" , async ( roomId , event ) => { if ( ! event [ 'state_key' ] || ! event [ 'content' ] || event [ 'type' ] !== 'm.room.member' ) return ; const memberEvent = new MembershipEvent ( event ) ; let client = clientFn ( memberEvent . membershipFor , roomId ) ; if ( ! client ) client = appservice . botClient ; await this . tryUpdateProfile ( roomId , memberEvent , client ) ; } ) ; } param { string } userId param { string | null } roomId returns { Promise < MatrixProfile > } public async getUserProfile ( userId , roomId = null ) { const cacheKey = this . getCacheKey ( userId , roomId ) ; const cached = this . cache . get ( cacheKey ) ; if ( cached ) return Promise . resolve ( < MatrixProfile > cached ) ; const profile = await this . getUserProfileWith ( userId , roomId , this . client ) ; this . cache . set ( cacheKey , profile ) ; return profile ; } private async getUserProfileWith ( userId , roomId , client ) { try { if ( roomId ) { const membership = await client . getRoomStateEvent ( roomId , "m.room.member" , userId ) ; return new MatrixProfile ( userId , membership ) ; } else { const profile = await client . getUserProfile ( userId ) ; return new MatrixProfile ( userId , profile ) ; } } catch ( e ) { LogService . warn ( "ProfileCache" , "Non-fatal error getting user profile. They might not exist." ) ; LogService . warn ( "ProfileCache" , extractRequestError ( e ) ) ; return new MatrixProfile ( userId , { } ) ; } } private async tryUpdateProfile ( roomId , memberEvent , client ) { const roomCacheKey = this . getCacheKey ( memberEvent . membershipFor , roomId ) ; const generalCacheKey = this . getCacheKey ( memberEvent . membershipFor , null ) ; if ( this . cache . has ( roomCacheKey ) ) { this . cache . set ( roomCacheKey , new MatrixProfile ( memberEvent . membershipFor , memberEvent . content ) ) ; } if ( this . cache . has ( generalCacheKey ) ) { const profile = await this . getUserProfileWith ( memberEvent . membershipFor , null , client ) ; this . cache . set ( generalCacheKey , profile ) ; } } }