import { Observable , of } from "rxjs" ; import { filter , first , map } from "rxjs/operators" ; import { CoatyObject , CoreType , DiscoverEvent , Uuid } from ".." ; import { Controller } from "./controller" ; /**
 * Discovers objects by given object Ids and maintains a local cache of
 * resolved objects. The controller will also update existing objects in its
 * cache whenever such objects are advertised by other parties.
 *
 * To realize an object cache controller for a specific core types or for specific objects,
 * define a custom controller class that extends this abstract class and
 * set the core type and/or the filter predicate of objects to be cached in the `OnInit` method.
 */ export abstract class ObjectCacheController < T extends CoatyObject > extends Controller { private _objectCache : Map < Uuid , T > ; private _pendingRequests : Map < Uuid , Observable < T > > ; private _coreType : CoreType ; private _objectFilter : ( obj : T ) => boolean ; onInit ( ) { super . onInit ( ) ; this . _objectCache = new Map < Uuid , T > ( ) ; this . _pendingRequests = new Map < Uuid , Observable < T > > ( ) ; this . _coreType = "CoatyObject" ; this . _objectFilter = undefined ; } onCommunicationManagerStarting ( ) { super . onCommunicationManagerStarting ( ) ; this . _objectCache . clear ( ) ; this . _pendingRequests . clear ( ) ; this . _observeObjectAdvertisements ( ) ; } param objectId param shouldResolvePending resolveObject ( objectId , shouldResolvePending = false ) { const object = this . _objectCache . get ( objectId ) ; if ( object ) { return of ( object ) ; } let resolve = this . _pendingRequests . get ( objectId ) ; if ( ! resolve || shouldResolvePending ) { resolve = this . communicationManager . publishDiscover ( DiscoverEvent . withObjectId ( objectId ) ) . pipe ( map ( event => event . data . object as T ) , first ( obj => obj && ( obj . coreType === this . coreType ) && ( this . _objectFilter ? this . _objectFilter ( obj ) : true ) ) ) ; this . _pendingRequests . set ( objectId , resolve ) ; resolve . subscribe ( obj => { this . _objectCache . set ( obj . objectId , obj ) ; this . _pendingRequests . delete ( obj . objectId ) ; } ) ; } return resolve ; } /**
     * Sets a filter predicate on objects to be resolved.
     *
     * To filter out specific objects or object types you should set an object
     * filter once in the `OnInit` method of your custom controller.
     */ public set objectFilter ( predicate ) { this . _objectFilter = predicate ; } /**
     * Gets the core type of objects to be cached.
     * The default value returned is `CoatyObject`.
     */ protected get coreType ( ) { return this . _coreType ; } /**
     * Sets the core type of objects to be cached.
     *
     * To filter out specific object core types you should set
     * the core type once in the `OnInit`
     * method of your custom controller.
     */ protected set coreType ( value ) { this . _coreType = value || "CoatyObject" ; } private _observeObjectAdvertisements ( ) { this . communicationManager . observeAdvertiseWithCoreType ( this . coreType ) . pipe ( filter ( event => this . _objectCache . has ( event . data . object . objectId ) ) ) . subscribe ( event => { const obj = event . data . object as T ; this . _objectCache . set ( obj . objectId , obj ) ; } ) ; } }