import { Injectable, Inject } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import { filter } from 'rxjs/operators'; import { map } from 'rxjs/operators'; interface BroadcastEvent { key: any; data?: any; } interface EventCompleteNotification { eventName: string; counter: number; eventCompleteBus: Subject; originalCounter: number; isDone: boolean; } interface EventJobStatus { numberOfListener: number; jobDoneNumber: number; eventName: string; } /** * * 元件A發佈JOB EVENT 給元件1,2…N,若有需求的元件則訂閱此一JOB EVENT。訂閱元件收到後,處理完對應的業務邏輯後, * 可發送訊息給元件A告之己完成,當每個元件都處理完後,元件A可在對應的函式中處理對應的業務邏輯 * 範例請參考 Angular_行內共用元件_EsbDispatchService_教學.docx * * @author:GYC */ @Injectable() export class EsbDispatchService { private eventBus: Subject; private eventCompleteNotificationList: EventCompleteNotification[]; constructor() { //eventBus 給訂閱元件來訂閱 this.eventBus = new Subject(); //eventCompleteNotificationList 給元件A publisher 來訂閱 //目的為元件 A publisher 可以收到 //1.通知 元件A publisher 有 某一訂閱元件己完成工作了 //2.通知 元件A publisher 全部訂閱元件 job都己完成了 this.eventCompleteNotificationList = []; } /** * * @param key jobname * @param data 要傳給訂閱元件 */ broadcast(key: any, data?: any): Observable { let observable: Observable = this.createEventCompleteNotification(key + '_complete').asObservable() .pipe(map((event) => event.data)); setTimeout( () => this.eventBus.next({ key, data }) , 10); //給 元件A publisher(發佈JOB EVENT) 來訂閱 return observable; } /** * 訂閱元件呼叫 */ listen(key: any): Observable { //訂閱清單:記錄有多少個 訂閱元件 this.addEventCompleteNotification(key + '_complete'); return this.eventBus.asObservable() .pipe(filter(event => { return event.key === key ? true : false; })).pipe(map(event => { return event.data; })); } /** * 取消訂閱 * @param key */ unsubscribe(key: any) { key = key + '_complete'; this.eventCompleteNotificationList.forEach((eventReceiver: EventCompleteNotification, index: number) => { if (eventReceiver.eventName === key) { this.eventCompleteNotificationList.splice(index, 1); } }); } /** * 取得所有訂閱清單 */ jobList(): any { let jobsubscribeList = []; this.eventCompleteNotificationList.forEach((eventReceiver: EventCompleteNotification, index: number) => { jobsubscribeList.push(eventReceiver.eventName.replace('_complete', '')); }); return jobsubscribeList; } /** * 取得 共有多少訂閱者,己完成有多少 * @param key */ jobStatus(key: any): any { let findKey = key + '_complete'; for (let eventCompleteNotification of this.eventCompleteNotificationList) { if (eventCompleteNotification.eventName === findKey) { return { numberOfListener: eventCompleteNotification.originalCounter, jobDoneNumber: eventCompleteNotification.originalCounter - eventCompleteNotification.counter, eventName: key, }; } } return { numberOfListener: 0, jobDoneNumber: 0, eventName: key, }; } /** * 通知 元件A publisher 有 訂閱元件己完成工作了 * @param key * @param data */ complete(key: any, data?: any) { key = key + '_complete'; for (let eventCompleteNotification of this.eventCompleteNotificationList) { if (eventCompleteNotification.eventName === key) { //通知 元件A publisher 有 訂閱元件己完成工作了 eventCompleteNotification.eventCompleteBus.next({ key, data }); //每當有一個 訂閱元件己完成工作了,就要從清單中 count -1, 當 count為0時,就會通知 元件A publisher 全部job都己完成了 this.decreaseEventCompleteNotificationCnt(key); break; } } } /** * 給 元件A publisher(發佈JOB EVENT) 來訂閱, * 當 訂閱元件收到後,處理完對應的業務邏輯後, 可發送訊息給元件A告之己完成 */ private createEventCompleteNotification(eventName: string) { let eventCompleteBus: Subject; //從 eventCompleteNotificationList 找出是否有符合的 eventName for (let eventCompleteNotification of this.eventCompleteNotificationList) { if (eventCompleteNotification.eventName === eventName) { eventCompleteBus = eventCompleteNotification.eventCompleteBus; if (eventCompleteNotification.isDone) { eventCompleteNotification.counter = eventCompleteNotification.originalCounter; eventCompleteNotification.isDone = false; } break; } } //若 eventCompleteBus為 null 時, //create eventCompleteNotification if (!eventCompleteBus) { let eventCompleteNotification: EventCompleteNotification = { counter: 0, //記錄有多少個 訂閱元件 originalCounter: 0, eventName: eventName,//記錄 event complet name job name 加上 _complet 例如 job1_complete eventCompleteBus: new Subject(), isDone: false }; eventCompleteBus = eventCompleteNotification.eventCompleteBus; this.eventCompleteNotificationList.push(eventCompleteNotification); } return eventCompleteBus; } /** * * 每當有一個 訂閱元件己完成工作了,就要從訂閱清單中找出 相同的事件名稱(key + '_complete') * 再從 訂閱清單中 count屬件減一 * @param eventCompleteName key + '_complete' */ private decreaseEventCompleteNotificationCnt(eventCompleteName: any): void { for (let eventCompleteNotification of this.eventCompleteNotificationList) { if (eventCompleteNotification.eventName === eventCompleteName) { //每當有一個 訂閱元件己完成工作了,就要從清單中 count -1 //當 count為0時,就會通知 元件A publisher 全部job都己完成了 if (eventCompleteNotification.counter > 0) { eventCompleteNotification.counter--; } if (eventCompleteNotification.counter === 0) { //通知 元件A publisher 全部job都己完成了 eventCompleteNotification.eventCompleteBus.complete(); eventCompleteNotification.counter = 0; eventCompleteNotification.eventCompleteBus = new Subject(); eventCompleteNotification.isDone = true; } break; } } } /** * 每當一個 訂閱元件 訂閱一個事件,就要記錄 有多少個訂閱元件 訂閱此一事件 * @param eventName key + '_complete' */ private addEventCompleteNotification(eventName: string): void { let isExisted: boolean = false; for (let eventCompleteNotification of this.eventCompleteNotificationList) { if (eventCompleteNotification.eventName === eventName) { //每當新增一個 訂閱元件,就要從清單中 count加一 eventCompleteNotification.counter++; eventCompleteNotification.originalCounter = eventCompleteNotification.counter; isExisted = true; break; } } if (!isExisted) { //若找不到此訂閱清單, 則 create 一個新的 let eventCompleteNotification: EventCompleteNotification = { counter: 1, originalCounter: 1, eventName: eventName, eventCompleteBus: new Subject(), isDone: false }; this.eventCompleteNotificationList.push(eventCompleteNotification); } } }