feat: ticket system base implementation
This commit is contained in:
1
src/services/sse/index.ts
Normal file
1
src/services/sse/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './sse.service';
|
||||
66
src/services/sse/sse.service.ts
Normal file
66
src/services/sse/sse.service.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { ENV_CONSTANT } from '@/constants/secrect.constant';
|
||||
|
||||
export type SseEventHandler<T = unknown> = (
|
||||
data: T,
|
||||
event: MessageEvent,
|
||||
) => void;
|
||||
|
||||
export type SseEventMap<TEvents extends Record<string, unknown>> = {
|
||||
[EventName in keyof TEvents]: SseEventHandler<TEvents[EventName]>;
|
||||
};
|
||||
|
||||
export interface SseConnection {
|
||||
source: EventSource;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
function getSseUrl(path: string) {
|
||||
if (/^https?:\/\//i.test(path)) return path;
|
||||
|
||||
const baseUrl = ENV_CONSTANT.BASE_API_URL ?? '';
|
||||
const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
||||
|
||||
return `${normalizedBase}${normalizedPath}`;
|
||||
}
|
||||
|
||||
function parseEventData(event: MessageEvent) {
|
||||
if (!event.data) return null;
|
||||
|
||||
try {
|
||||
return JSON.parse(event.data);
|
||||
} catch {
|
||||
return event.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const sseService = {
|
||||
connect: <TEvents extends Record<string, unknown>>(
|
||||
path: string,
|
||||
events: SseEventMap<TEvents>,
|
||||
): SseConnection => {
|
||||
const source = new EventSource(getSseUrl(path));
|
||||
const cleanups: Array<() => void> = [];
|
||||
|
||||
Object.entries(events).forEach(([eventName, handler]) => {
|
||||
const listener = (event: Event) => {
|
||||
const messageEvent = event as MessageEvent;
|
||||
(handler as SseEventHandler)(
|
||||
parseEventData(messageEvent),
|
||||
messageEvent,
|
||||
);
|
||||
};
|
||||
|
||||
source.addEventListener(eventName, listener);
|
||||
cleanups.push(() => source.removeEventListener(eventName, listener));
|
||||
});
|
||||
|
||||
return {
|
||||
source,
|
||||
close: () => {
|
||||
cleanups.forEach((cleanup) => cleanup());
|
||||
source.close();
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user