2020-05-29 22:22:00 +02:00
|
|
|
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
|
|
|
|
|
|
|
|
// AnTOS Web desktop is is licensed under the GNU General Public
|
|
|
|
// License v3.0, see the LICENCE file for more information
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation, either version 3 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
//along with this program. If not, see https://www.gnu.org/licenses/.
|
|
|
|
|
|
|
|
namespace OS {
|
|
|
|
export namespace API {
|
2021-11-24 22:15:25 +01:00
|
|
|
/**
|
|
|
|
* Data type exchanged via
|
|
|
|
* the global Announcement interface
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @interface AnnouncementDataType
|
|
|
|
*/
|
2021-11-24 22:37:49 +01:00
|
|
|
export interface AnnouncementDataType<T> {
|
2021-11-24 22:15:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* message string
|
|
|
|
*
|
|
|
|
* @type {string| FormattedString}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
|
|
|
message: string | FormattedString;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process ID
|
|
|
|
*
|
|
|
|
* @type {number}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
|
|
|
id: number;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* App name
|
|
|
|
*
|
|
|
|
* @type {string | FormattedString}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
|
|
|
name: string | FormattedString;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Icon file
|
|
|
|
*
|
|
|
|
* @type {string}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
|
|
|
icon?: string;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* App icon class
|
|
|
|
*
|
|
|
|
* @type {string}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
|
|
|
iconclass?: string;
|
|
|
|
/**
|
|
|
|
* User specific data
|
|
|
|
*
|
|
|
|
* @type {*}
|
|
|
|
* @memberof AppAnnouncementDataType
|
|
|
|
*/
|
2021-11-24 22:37:49 +01:00
|
|
|
u_data?: T;
|
2021-11-24 22:15:25 +01:00
|
|
|
}
|
2020-05-29 22:22:00 +02:00
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Observable entry type definition
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @interface ObservableEntryType
|
|
|
|
*/
|
|
|
|
export interface ObservableEntryType {
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
|
|
|
* A Set of callbacks that should be called only once.
|
|
|
|
* These callbacks will be removed after the first
|
|
|
|
* occurrence of the corresponding event
|
|
|
|
*
|
|
|
|
* @memberof ObservableEntryType
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
one: Set<(d: any) => void>;
|
2020-06-12 20:24:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A Set of callbacks that should be called
|
|
|
|
* every time the corresponding event is triggered
|
|
|
|
*
|
|
|
|
* @memberof ObservableEntryType
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
many: Set<(d: any) => void>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Announcement listener type definition
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @interface AnnouncerListenerType
|
|
|
|
*/
|
|
|
|
export interface AnnouncerListenerType {
|
|
|
|
[index: number]: {
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
|
|
|
* The event name
|
|
|
|
*
|
|
|
|
* @type {string}
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
e: string;
|
2020-06-12 20:24:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The event callback
|
|
|
|
*
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
f: (d: any) => void;
|
|
|
|
}[];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* This class is the based class used in AntOS event
|
|
|
|
* announcement system.
|
|
|
|
* It implements the observer pattern using simple
|
|
|
|
* subscribe/publish mechanism
|
2020-05-29 22:22:00 +02:00
|
|
|
* @export
|
|
|
|
* @class Announcer
|
|
|
|
*/
|
|
|
|
export class Announcer {
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
|
|
|
* The observable object that stores event name
|
|
|
|
* and its corresponding callback in [[ObservableEntryType]]
|
|
|
|
*
|
|
|
|
* @type {GenericObject<ObservableEntryType>}
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
observable: GenericObject<ObservableEntryType>;
|
2020-06-12 20:24:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable/disable the announcer
|
|
|
|
*
|
|
|
|
* @type {boolean}
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
enable: boolean;
|
2020-06-12 20:24:39 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
*Creates an instance of Announcer.
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
constructor() {
|
|
|
|
this.observable = {};
|
|
|
|
this.enable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Disable the announcer, when this function is called
|
|
|
|
* all events and their callbacks will be removed
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @returns
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
|
|
|
disable() {
|
|
|
|
this.off("*");
|
|
|
|
return (this.enable = false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Subscribe to an event, the callback will be called
|
|
|
|
* every time the corresponding event is trigged
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} evtName event name
|
|
|
|
* @param {(d: any) => void} callback The corresponding callback
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {void}
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
|
|
|
on(evtName: string, callback: (d: any) => void): void {
|
|
|
|
if (!this.enable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!this.observable[evtName]) {
|
|
|
|
this.observable[evtName] = {
|
|
|
|
one: new Set(),
|
|
|
|
many: new Set(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
this.observable[evtName].many.add(callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Subscribe to an event, the callback will
|
|
|
|
* be called only once and then removed from the announcer
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} evtName event name
|
|
|
|
* @param {(d: any) => void} callback the corresponding callback
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {void}
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
|
|
|
one(evtName: string, callback: (d: any) => void): void {
|
|
|
|
if (!this.enable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!this.observable[evtName]) {
|
|
|
|
this.observable[evtName] = {
|
|
|
|
one: new Set(),
|
|
|
|
many: new Set(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
this.observable[evtName].one.add(callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Unsubscribe the callback from an event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} evtName event name
|
|
|
|
* @param {(d: any) => void} [callback] the callback to be unsubscribed.
|
|
|
|
* When the `callback` is `*`, all callbacks related to `evtName` will be
|
|
|
|
* removed
|
2020-05-29 22:22:00 +02:00
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
|
|
|
off(evtName: string, callback?: (d: any) => void): void {
|
|
|
|
const fn = (evt: string, cb: (d: any) => void) => {
|
|
|
|
if (!this.observable[evt]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cb) {
|
|
|
|
this.observable[evt].one.delete(cb);
|
|
|
|
return this.observable[evt].many.delete(cb);
|
|
|
|
} else {
|
|
|
|
if (this.observable[evt]) {
|
|
|
|
return delete this.observable[evt];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (evtName === "*") {
|
|
|
|
for (let k in this.observable) {
|
|
|
|
fn(k, callback);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fn(evtName, callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Trigger an event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} evtName event name
|
|
|
|
* @param {*} data data object that will be send to all related callback
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {void}
|
|
|
|
* @memberof Announcer
|
|
|
|
*/
|
|
|
|
trigger(evtName: string, data: any): void {
|
|
|
|
const trig = (name: string, d: any) => {
|
|
|
|
const names = [name, "*"];
|
2020-06-03 23:43:08 +02:00
|
|
|
for (let evt of names) {
|
2020-05-29 22:22:00 +02:00
|
|
|
if (!this.observable[evt]) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
this.observable[evt].one.forEach((f) => f(d));
|
|
|
|
this.observable[evt].one = new Set();
|
|
|
|
this.observable[evt].many.forEach((f) => f(d));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (evtName === "*") {
|
|
|
|
for (let k in this.observable) {
|
|
|
|
const v = this.observable[k];
|
|
|
|
if (k !== "*") {
|
|
|
|
trig(k, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return trig(evtName, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
|
|
|
* This namespace defines every thing related to the system announcement.
|
|
|
|
*
|
|
|
|
* The system announcement provides a global way to communicate between
|
|
|
|
* processes (applications/services) using the subscribe/publish
|
|
|
|
* mechanism
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
export namespace announcer {
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
2020-06-16 18:02:17 +02:00
|
|
|
* The global announcer object that manages global events
|
2020-06-12 20:24:39 +02:00
|
|
|
* and callbacks
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
export var observable: API.Announcer = new API.Announcer();
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
2020-06-16 18:02:17 +02:00
|
|
|
* This variable is used to allocate the `id` of all messages
|
2020-06-12 20:24:39 +02:00
|
|
|
* passing between publishers and subscribers in the
|
|
|
|
* system announcement
|
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
export var quota: 0;
|
2020-06-12 20:24:39 +02:00
|
|
|
/**
|
2020-06-15 18:10:13 +02:00
|
|
|
* Placeholder of all global events listeners
|
2020-06-12 20:24:39 +02:00
|
|
|
*/
|
2020-05-29 22:22:00 +02:00
|
|
|
export var listeners: API.AnnouncerListenerType = {};
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Subscribe to a global event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} e event name
|
2021-11-24 22:37:49 +01:00
|
|
|
* @param {(d: API.AnnouncementDataType<any>) => void} f event callback
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {GUI.BaseModel} a the process (Application/service) related to the callback
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
2021-11-24 22:37:49 +01:00
|
|
|
export function on(e: string, f: (d: API.AnnouncementDataType<any>) => void, a: BaseModel): void {
|
2020-05-29 22:22:00 +02:00
|
|
|
if (!announcer.listeners[a.pid]) {
|
|
|
|
announcer.listeners[a.pid] = [];
|
|
|
|
}
|
|
|
|
announcer.listeners[a.pid].push({ e, f });
|
|
|
|
announcer.observable.on(e, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Trigger a global event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} e event name
|
|
|
|
* @param {*} d data passing to all related callback
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
|
|
|
export function trigger(e: string, d: any): void {
|
|
|
|
announcer.observable.trigger(e, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Report system fail. This will trigger the global `fail`
|
|
|
|
* event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {(string | FormattedString)} m message string
|
|
|
|
* @param {Error} e error to be reported
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
2020-06-10 11:15:01 +02:00
|
|
|
export function osfail(m: string | FormattedString, e: Error): void {
|
2021-11-24 22:15:25 +01:00
|
|
|
announcer.ostrigger("fail", m, e );
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Report system error. This will trigger the global `error`
|
|
|
|
* event
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {(string | FormattedString)} m message string
|
|
|
|
* @param {Error} e error to be reported
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
2020-06-10 11:15:01 +02:00
|
|
|
export function oserror(m: string | FormattedString, e: Error): void {
|
2021-11-24 22:15:25 +01:00
|
|
|
announcer.ostrigger("error", m, e );
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Trigger system notification (`info` event)
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {(string | FormattedString)} m notification message
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
2020-06-10 11:15:01 +02:00
|
|
|
export function osinfo(m: string | FormattedString): void {
|
2021-11-24 22:15:25 +01:00
|
|
|
announcer.ostrigger("info", m);
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-11-24 22:15:25 +01:00
|
|
|
*
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {string} e event name
|
2021-11-24 22:15:25 +01:00
|
|
|
* @param {(string| FormattedString)} m event message
|
|
|
|
* @param {*} [d] user data
|
2020-05-29 22:22:00 +02:00
|
|
|
*/
|
2021-11-24 22:15:25 +01:00
|
|
|
export function ostrigger(e: string, m: string| FormattedString, d?: any): void {
|
2021-11-24 22:37:49 +01:00
|
|
|
const aob: API.AnnouncementDataType<any> = {} as API.AnnouncementDataType<any>;
|
2021-11-24 22:15:25 +01:00
|
|
|
aob.id = 0;
|
|
|
|
aob.message = m;
|
|
|
|
aob.u_data = d;
|
|
|
|
aob.name = "OS";
|
|
|
|
announcer.trigger(e, aob);
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Unregister a process (application/service) from
|
|
|
|
* the global announcement system
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
2020-06-12 20:24:39 +02:00
|
|
|
* @param {GUI.BaseModel} app reference to the process
|
2020-05-29 22:22:00 +02:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
export function unregister(app: BaseModel): void {
|
|
|
|
if (
|
|
|
|
!announcer.listeners[app.pid] ||
|
|
|
|
!(announcer.listeners[app.pid].length > 0)
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-03 23:43:08 +02:00
|
|
|
for (let i of announcer.listeners[app.pid]) {
|
2020-05-29 22:22:00 +02:00
|
|
|
announcer.observable.off(i.e, i.f);
|
|
|
|
}
|
|
|
|
delete announcer.listeners[app.pid];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-06-12 20:24:39 +02:00
|
|
|
* Allocate message id
|
2020-05-29 22:22:00 +02:00
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
|
|
|
export function getMID(): number {
|
2020-06-12 20:24:39 +02:00
|
|
|
quota += 1;
|
|
|
|
return quota;
|
2020-05-29 22:22:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|