class CEventHub {
#subscribers = new Map();
#latest_data = new Map();
publish({data, descriptor}) {
descriptor = Object.keys(descriptor).sort().reduce(
(descriptor_sorted, key) => {
descriptor_sorted[key] = descriptor[key];
return descriptor_sorted;
},
{}
);
const descriptor_hash = JSON.stringify(descriptor);
this.#latest_data.delete(descriptor_hash);
this.#latest_data.set(descriptor_hash, {data, descriptor});
for (const {require, callback} of this.#subscribers.values()) {
if (CEventHub.#match(require, descriptor)) {
callback({data, descriptor});
}
}
}
subscribe({require = {}, callback}) {
for (const {data, descriptor} of [...this.#latest_data.values()].reverse()) {
if (CEventHub.#match(require, descriptor)) {
callback({data, descriptor});
break;
}
}
const subscription = {};
this.#subscribers.set(subscription, {require, callback});
return subscription;
}
unsubscribe(subscription) {
return this.#subscribers.delete(subscription);
}
getData(require) {
for (const {data, descriptor} of [...this.#latest_data.values()].reverse()) {
if (CEventHub.#match(require, descriptor)) {
return data;
}
}
return undefined;
}
invalidateData(require) {
for (const [descriptor_hash, {descriptor}] of this.#latest_data.entries()) {
if (CEventHub.#match(require, descriptor)) {
this.#latest_data.delete(descriptor_hash);
}
}
}
static #match(require, descriptor) {
for (const [key, value] of Object.entries(require)) {
if (!(key in descriptor) || descriptor[key] !== value) {
return false;
}
}
return true;
}
}