1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Log } from '../../utils/Log' 17 18type Callback = (args: any) => void 19 20export class EventBus { 21 private TAG = '[EventBus]:' 22 private events: Map<string, Set<Callback>> = new Map() 23 24 constructor() { 25 } 26 27 /** 28 * Register events and handlers 29 * 30 * @param event event to handle. 31 * @param callback event related callbacck 32 */ 33 public on(event: string | string[], callback: Callback): void { 34 Log.info(`${this.TAG} on event = ${JSON.stringify(event)} ${JSON.stringify(callback)}`); 35 if (Array.isArray(event)) { 36 for (let i = 0, l = event.length; i < l; i++) { 37 this.on(event[i], callback) 38 } 39 } else { 40 let callbacks = this.events.get(event) 41 if (!callbacks) { 42 callbacks = new Set() 43 } 44 callbacks.add(callback) 45 this.events.set(event, callbacks) 46 Log.info(`${this.TAG} on event = ${JSON.stringify(event)} ${JSON.stringify(this.events.get(event))}`) 47 } 48 } 49 50 /** 51 * Register events and processing functions, and destroy them after triggering once 52 * 53 * @param event event to handle 54 * @param callback event related callback 55 */ 56 public once(event: string | string[], callback: Callback): void { 57 const _self = this 58 59 function handler(): void { 60 const args: any = arguments; 61 _self.off(event, handler); 62 callback.apply(_self, args); // When called in emit, it will pass parameters to the on method 63 } 64 65 handler.callback = callback; // off determines the destruction event based on this 66 _self.on(event, handler); 67 } 68 69 /** 70 * Destroy events and handlers 71 * 72 * @param event event to handle 73 * @param callback event related callback 74 */ 75 public off(event: string | string[], callback: Callback | undefined): void { 76 // Array cyclic emptying 77 if (Array.isArray(event)) { 78 for (let i = 0, l = event.length; i < l; i++) { 79 this.off(event[i], callback) 80 } 81 return; 82 } 83 const callbacks = this.events.get(event); 84 if (callback == undefined) { 85 callbacks?.clear() 86 return 87 } 88 let cb = null 89 callbacks.forEach((item) => { 90 if (item.name === callback.name) { 91 cb = item 92 } 93 }) 94 callbacks?.delete(cb); 95 Log.info(`${this.TAG} off event = ${JSON.stringify(event)} ${JSON.stringify(this.events.get(event))}`) 96 } 97 98 /** 99 * Trigger all callbacks of an event with parameters 100 * 101 * @param event event to handle 102 * @param argument parameter for the related callback 103 */ 104 public emit(event: string, argument: any): void { 105 // once deleting the event will cause this in the following loop this._events moves forward in fn, 106 // so it is copied here as a new array 107 const _self = this 108 Log.info(`${this.TAG} emit event = ${JSON.stringify(event)}`); 109 const tempCall = _self.events.get(event); 110 if (!tempCall) { 111 return 112 } 113 const callbacks = [...tempCall]; 114 if (callbacks) { 115 for (let i = 0, l = callbacks.length; i < l; i++) { 116 try { 117 callbacks[i].apply(_self, argument) 118 } catch (e: any) { 119 new Error(e) 120 } 121 } 122 } 123 } 124}