ui/api: init message bus subscriber hooks
This commit is contained in:
2
pkgs/clan-app/ui/index.d.ts
vendored
2
pkgs/clan-app/ui/index.d.ts
vendored
@@ -1,4 +1,4 @@
|
|||||||
import { ProcessMessage } from "./src/hooks/api";
|
import { ProcessMessage } from "./src/hooks/notify";
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|
||||||
|
|||||||
@@ -99,14 +99,3 @@ export const callApi = <K extends OperationNames>(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ProcessMessage {
|
|
||||||
topic: string;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
data: any;
|
|
||||||
origin: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.notifyBus = (data) => {
|
|
||||||
console.debug("Channel function called with data:", data);
|
|
||||||
};
|
|
||||||
|
|||||||
89
pkgs/clan-app/ui/src/hooks/notify.ts
Normal file
89
pkgs/clan-app/ui/src/hooks/notify.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import { createSignal, onCleanup } from "solid-js";
|
||||||
|
import { OperationNames } from "./api";
|
||||||
|
|
||||||
|
export interface ProcessMessage<
|
||||||
|
TData = unknown,
|
||||||
|
TTopic extends string = string,
|
||||||
|
> {
|
||||||
|
topic: TTopic;
|
||||||
|
data: TData;
|
||||||
|
origin: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Subscriber<T extends ProcessMessage> {
|
||||||
|
filter: (msg: T) => boolean;
|
||||||
|
callback: (msg: T) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscribers: Subscriber<ProcessMessage>[] = [];
|
||||||
|
|
||||||
|
// Declare the global function on the window type
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
notifyBus: (msg: ProcessMessage) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.notifyBus = (msg: ProcessMessage) => {
|
||||||
|
console.debug("notifyBus called with:", msg);
|
||||||
|
for (const sub of subscribers) {
|
||||||
|
try {
|
||||||
|
if (sub.filter(msg)) {
|
||||||
|
sub.callback(msg);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Subscriber threw an error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to any message
|
||||||
|
*
|
||||||
|
* Returns a function to unsubsribe itself
|
||||||
|
*
|
||||||
|
* consider using useNotify for reactive usage on solidjs
|
||||||
|
*/
|
||||||
|
export function _subscribeNotify<T extends ProcessMessage>(
|
||||||
|
filter: (msg: T) => boolean,
|
||||||
|
callback: (msg: T) => void,
|
||||||
|
) {
|
||||||
|
// Cast to shared subscriber type for storage
|
||||||
|
const sub: Subscriber<ProcessMessage> = {
|
||||||
|
filter: filter as (msg: ProcessMessage) => boolean,
|
||||||
|
callback: callback as (msg: ProcessMessage) => void,
|
||||||
|
};
|
||||||
|
subscribers.push(sub);
|
||||||
|
return () => {
|
||||||
|
const idx = subscribers.indexOf(sub);
|
||||||
|
if (idx >= 0) subscribers.splice(idx, 1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reactive signal that tracks a message by the given filter predicate
|
||||||
|
* The signal has the value of the last message where filter was true
|
||||||
|
* null in case no message was recieved yet
|
||||||
|
*/
|
||||||
|
export function useNotify<T extends ProcessMessage = ProcessMessage>(
|
||||||
|
filter: (msg: T) => boolean = () => true as boolean,
|
||||||
|
) {
|
||||||
|
const [message, setMessage] = createSignal<T | null>(null);
|
||||||
|
|
||||||
|
const unsubscribe = _subscribeNotify(filter, (msg) => setMessage(() => msg));
|
||||||
|
|
||||||
|
onCleanup(unsubscribe);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks any message that was sent from this api origin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function useNotifyOrigin<
|
||||||
|
T extends ProcessMessage = ProcessMessage,
|
||||||
|
K extends OperationNames = OperationNames,
|
||||||
|
>(origin: K) {
|
||||||
|
return useNotify<T>((m) => m.origin === origin);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user