@eclipse-scout/core
Version:
Eclipse Scout runtime
158 lines (138 loc) • 5.04 kB
text/typescript
/*
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
import {Event, EventHandler, EventListener, EventSupport, InitModelOf, ObjectModel, ObjectWithType, scout, systems, UiNotificationDo, UiNotificationHandler, UiNotificationPoller} from '../index';
export class UiNotificationSystem implements UiNotificationSystemModel, ObjectWithType {
declare model: UiNotificationSystemModel;
declare initModel: UiNotificationSystemModel;
poller: UiNotificationPoller;
name: string;
events: UiNotificationEventSupport;
objectType: string;
constructor() {
this.events = new UiNotificationEventSupport(this);
}
init(model: InitModelOf<this>) {
this.name = model?.name;
}
subscribe(topic: string, handler: UiNotificationHandler): JQuery.Promise<string> {
scout.assertParameter('topic', topic);
scout.assertParameter('handler', handler);
this.events.on(topic, handler);
return this.whenSubscriptionStart(topic).catch(error => {
this.unsubscribe(topic, handler);
throw error;
});
}
subscribeOne(topic: string, handler: UiNotificationHandler): JQuery.Promise<string> {
scout.assertParameter('topic', topic);
scout.assertParameter('handler', handler);
this.events.one(topic, handler);
return this.whenSubscriptionStart(topic).catch(error => {
this.unsubscribe(topic, handler);
throw error;
});
}
unsubscribe(topic: string, handler?: UiNotificationHandler) {
scout.assertParameter('topic', topic);
this.events.off(topic, handler);
}
whenSubscriptionStart(topic: string): JQuery.Promise<string> {
if (this.poller.notifications.get(topic)?.size) {
// If there is at least one notification, the subscription has been started successfully.
// The notification may be the subscriptionStart notification or another one if subscriptionStart notification has been removed because history size exceeded HISTORY_COUNT.
return $.resolvedPromise(topic);
}
let deferred = $.Deferred();
let subscriptionStartHandler = event => {
if (event.notification.topic === topic) {
deferred.resolve(topic);
this.poller.off('subscriptionStart', subscriptionStartHandler);
this.poller.off('error', errorHandler);
}
};
let errorHandler = event => {
deferred.reject(event.error);
this.poller?.off('subscriptionStart', subscriptionStartHandler);
this.poller?.off('error', errorHandler);
};
this.poller.on('subscriptionStart', subscriptionStartHandler);
this.poller.on('error', errorHandler);
return deferred.promise();
}
protected _dispatch(notifications: UiNotificationDo[]) {
for (const notification of notifications) {
if (!this.events.count(notification.topic)) {
$.log.isInfoEnabled() && $.log.info('Notification received but no handler registered');
return;
}
this._trigger(notification.topic, notification);
}
}
protected _trigger(type: string, notification: UiNotificationDo) {
let event = new Event({
id: notification.id,
topic: notification.topic,
creationTime: notification.creationTime,
message: notification.message
});
event.source = this;
this.events.trigger(type, event);
}
updatePoller() {
let topics = this.events.types();
let poller = this.poller;
if (topics.length > 0 && !poller) {
// First topic added -> create poller
let endpointUrl = systems.getOrCreate(this.name).getEndpointUrl('ui-notifications', 'ui-notifications');
poller = scout.create(UiNotificationPoller, {
system: this,
url: endpointUrl
});
poller.on('notifications', event => this._dispatch(event.notifications));
this.poller = poller;
}
if (!poller) {
// No topics registered and no poller started -> do nothing
return;
}
// Update poller with new topics
poller.setTopics(topics);
if (poller.topics.length === 0) {
// Last topic removed -> stop poller
poller.stop();
this.poller = null;
} else {
poller.restart();
}
}
destroy() {
this.poller?.stop();
this.poller = null;
}
}
export class UiNotificationEventSupport extends EventSupport {
system: UiNotificationSystem;
constructor(system: UiNotificationSystem) {
super();
this.system = system;
}
override on(type: string, func: EventHandler, origFunc?: EventHandler): EventListener {
let listener = super.on(type, func, origFunc);
this.system.updatePoller();
return listener;
}
override off(type: string, func?: EventHandler) {
super.off(type, func);
this.system.updatePoller();
}
}
export interface UiNotificationSystemModel extends ObjectModel<UiNotificationSystem> {
name?: string;
}