import { BindingScope , config , ContextView , injectable } from '@loopback/core' ; import debugFactory from 'debug' ; import { Message } from './types' ; const debug = debugFactory ( 'greeter-extension' ) ; /**
 * Configuration for CachingService
 */ export interface CachingServiceOptions { ttl : number ; } /**
 * Message caching service
 */ @ injectable ( { scope : BindingScope . SINGLETON } ) export class CachingService { private timer : NodeJS . Timer ; private store : Map < string , Message > = new Map ( ) ; constructor ( @ config . view ( ) private optionsView ) { optionsView . on ( 'refresh' , ( ) => { debug ( 'Restarting the service as configuration changes...' ) ; this . restart ( ) . catch ( err => { console . error ( 'Cannot restart the caching service.' , err ) ; process . exit ( 1 ) ; } ) ; } ) ; } param key param message async set ( key , message ) { this . store . set ( key , message ) ; } param key async get ( key ) { const expired = await this . isExpired ( key ) ; debug ( 'Getting cache for %s' , key , expired ) ; return expired ? undefined : this . store . get ( key ) ; } param key async delete ( key ) { return this . store . delete ( key ) ; } /**
     * Clear the cache
     */ async clear ( ) { this . store . clear ( ) ; } param key param now async isExpired ( key , now = new Date ( ) ) { const ttl = await this . getTTL ( ) ; const msg = this . store . get ( key ) ; if ( ! msg ) return true ; return now . getTime ( ) - msg . timestamp . getTime ( ) > ttl ; } /**
     * Get the TTL setting
     */ async getTTL ( ) { const options = await this . optionsView . singleValue ( ) ; debug ( 'Caching options: %j' , options ) ; return options ?. ttl ?? 5000 ; } /**
     * Remove expired items from the cache
     */ async sweep ( ) { debug ( 'Sweeping cache...' ) ; for ( const key of this . store . keys ( ) ) { if ( await this . isExpired ( key ) ) { debug ( 'Cache for %s is swept.' , key ) ; await this . delete ( key ) ; } } } /**
     * This method will be invoked when the application starts
     */ async start ( ) { debug ( 'Starting caching service' ) ; await this . clear ( ) ; const ttl = await this . getTTL ( ) ; debug ( 'TTL: %d' , ttl ) ; this . timer = setInterval ( ( ) => { this . sweep ( ) . catch ( console . warn ) ; } , ttl ) ; } /**
     * This method will be invoked when the application stops
     */ async stop ( ) { debug ( 'Stopping caching service' ) ; if ( this . timer ) { clearInterval ( this . timer ) ; } await this . clear ( ) ; } /**
     * This method may be used to restart the service (and may be triggered by a
     * 'refresh' event)
     */ async restart ( ) { await this . stop ( ) ; await this . start ( ) ; } }