import * as PubSub from "pubsub-js" ; import { fnVoid } from "./commonTypes" ; import { LoggingService } from "./loggingService" ; import { UtilsInternal } from "./utilsInternal" ; /**
 * A Pub/Sub event system that enables you to subscribe to various events published by Arc.js.
 * For more information, see [Pub/Sub Events](/Events.md#pubsubevents).
 */ export class PubSubEventService { param topic param payload returns public static publish ( topic , payload ) { LoggingService . debug ( `PubSubEventService: publishing ${ topic }` ) ; return PubSub . publish ( topic , payload ) ; } param topics param callback returns public static subscribe ( topics , callback ) { return Array . isArray ( topics ) ? PubSubEventService . aggregate ( topics , callback ) : new EventSubscription ( PubSub . subscribe ( topics , callback ) ) ; } /**
     * Remove all subscriptions
     */ public static clearAllSubscriptions ( ) { PubSub . clearAllSubscriptions ( ) ; } param key param milliseconds public static unsubscribe ( key , milliseconds = - 1 ) { if ( milliseconds === - 1 ) { PubSub . unsubscribe ( key ) ; return Promise . resolve ( ) ; } return new Promise < void > ( ( resolve ) : void => { setTimeout ( ( ) => { PubSub . unsubscribe ( key ) ; resolve ( ) ; } , milliseconds ) ; } ) ; } param matchTemplates param topic public static isTopicSpecifiedBy ( matchTemplates , topic ) { if ( ! topic ) { return false ; } if ( ! matchTemplates ) { return false ; } if ( ( typeof matchTemplates === "string" ) && ( matchTemplates === "*" ) ) { return true ; } matchTemplates = UtilsInternal . ensureArray ( matchTemplates ) ; const topicWords = topic . split ( "." ) ; for ( const template of matchTemplates ) { if ( ! template ) { continue ; } if ( template === topic ) { return true ; } if ( template . length > topic . length ) { continue ; } if ( template [ 0 ] === "." ) { continue ; } const templateWords = template . split ( "." ) ; if ( templateWords . length > topicWords . length ) { continue ; } let matches = false ; for ( let i = 0 ; i < templateWords . length ; ++ i ) { const templateWord = templateWords [ i ] ; const topicWord = topicWords [ i ] ; if ( ( templateWord === "*" ) || ( templateWord === topicWord ) ) { matches = true ; } else { matches = false ; break ; } } if ( ! matches ) { continue ; } return true ; } return false ; } param topics param callback returns private static aggregate ( topics , callback ) { return new SubscriptionCollection ( topics , callback ) ; } } /**
 * Creates a collection of subscriptions to which one can unsubscribe all at once.
 */ export class SubscriptionCollection implements IEventSubscription { /**
     * Collection of values returned by `subscribe`, or the token, or the handler function
     */ private subscriptions : Set < IEventSubscription > ; constructor ( topics ? , callback ? ) { this . subscriptions = new Set < IEventSubscription > ( ) ; if ( topics ) { if ( ! callback ) { throw new Error ( "SubscriptionCollection: callback is not set" ) ; } this . subscribe ( topics , callback ) ; } } param topics param callback public subscribe ( topics , callback ) { topics = UtilsInternal . ensureArray ( topics ) ; topics . forEach ( ( topic ) => { const subscriptionKey = PubSub . subscribe ( topic , callback ) ; this . subscriptions . add ( new EventSubscription ( subscriptionKey ) ) ; } ) ; } param milliseconds public unsubscribe ( milliseconds = - 1 ) { const promises = new Array < Promise < void > > ( ) ; this . subscriptions . forEach ( ( s ) => { promises . push ( s . unsubscribe . call ( s , milliseconds ) ) ; } ) ; return Promise . all ( promises ) . then ( ( ) => { this . subscriptions . clear ( ) ; } ) ; } } export type EventSubscriptionCallback = ( topic : string , payload : any ) => any ; export type EventSubscriptionKey = string | EventSubscriptionCallback ; export interface IEventSubscription { unsubscribe ( milliseconds ? ) : Promise < void > ; } export class EventSubscription implements IEventSubscription { public constructor ( private key ) { } param milliseconds public unsubscribe ( milliseconds = - 1 ) { if ( milliseconds === - 1 ) { PubSub . unsubscribe ( this . key ) ; return Promise . resolve ( ) ; } return new Promise < void > ( ( resolve ) : void => { setTimeout ( ( ) => { PubSub . unsubscribe ( this . key ) ; resolve ( ) ; } , milliseconds ) ; } ) ; } }