mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 16:05:58 +08:00
feat: add event source provider with hook (#3298)
* feat: add event source provider with hook * chore: jwt is updated --------- Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
f47c23032c
commit
900752b6e2
22
frontend/src/hooks/useEventSourceEvent/index.ts
Normal file
22
frontend/src/hooks/useEventSourceEvent/index.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { EventListener, EventSourceEventMap } from 'event-source-polyfill';
|
||||||
|
import { useEventSource } from 'providers/EventSource';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export const useEventSourceEvent = (
|
||||||
|
eventName: keyof EventSourceEventMap,
|
||||||
|
listener: EventListener,
|
||||||
|
): void => {
|
||||||
|
const { eventSourceInstance } = useEventSource();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (eventSourceInstance) {
|
||||||
|
eventSourceInstance.addEventListener(eventName, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (): void => {
|
||||||
|
if (eventSourceInstance) {
|
||||||
|
eventSourceInstance.removeEventListener(eventName, listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [eventName, eventSourceInstance, listener]);
|
||||||
|
};
|
124
frontend/src/providers/EventSource.tsx
Normal file
124
frontend/src/providers/EventSource.tsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import { apiV3 } from 'api/apiV1';
|
||||||
|
import { ENVIRONMENT } from 'constants/env';
|
||||||
|
import { EventListener, EventSourcePolyfill } from 'event-source-polyfill';
|
||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
PropsWithChildren,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import AppReducer from 'types/reducer/app';
|
||||||
|
|
||||||
|
interface IEventSourceContext {
|
||||||
|
eventSourceInstance: EventSourcePolyfill | null;
|
||||||
|
isConnectionOpen: boolean;
|
||||||
|
isConnectionLoading: boolean;
|
||||||
|
isConnectionError: string;
|
||||||
|
handleStartOpenConnection: (url?: string) => void;
|
||||||
|
handleCloseConnection: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventSourceContext = createContext<IEventSourceContext>({
|
||||||
|
eventSourceInstance: null,
|
||||||
|
isConnectionOpen: false,
|
||||||
|
isConnectionLoading: false,
|
||||||
|
isConnectionError: '',
|
||||||
|
handleStartOpenConnection: () => {},
|
||||||
|
handleCloseConnection: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function EventSourceProvider({
|
||||||
|
children,
|
||||||
|
}: PropsWithChildren): JSX.Element {
|
||||||
|
const [isConnectionOpen, setIsConnectionOpen] = useState<boolean>(false);
|
||||||
|
const [isConnectionLoading, setIsConnectionLoading] = useState<boolean>(false);
|
||||||
|
const [isConnectionError, setIsConnectionError] = useState<string>('');
|
||||||
|
|
||||||
|
const { user } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
|
const eventSourceRef = useRef<EventSourcePolyfill | null>(null);
|
||||||
|
|
||||||
|
const handleCloseConnection = useCallback(() => {
|
||||||
|
if (!eventSourceRef.current) return;
|
||||||
|
|
||||||
|
eventSourceRef.current.close();
|
||||||
|
setIsConnectionOpen(false);
|
||||||
|
setIsConnectionLoading(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOpenConnection: EventListener = useCallback(() => {
|
||||||
|
setIsConnectionLoading(false);
|
||||||
|
setIsConnectionOpen(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleErrorConnection: EventListener = useCallback(() => {
|
||||||
|
if (!eventSourceRef.current) return;
|
||||||
|
|
||||||
|
handleCloseConnection();
|
||||||
|
|
||||||
|
eventSourceRef.current.removeEventListener('error', handleErrorConnection);
|
||||||
|
eventSourceRef.current.removeEventListener('open', handleOpenConnection);
|
||||||
|
}, [handleCloseConnection, handleOpenConnection]);
|
||||||
|
|
||||||
|
const handleStartOpenConnection = useCallback(
|
||||||
|
(url?: string) => {
|
||||||
|
const eventSourceUrl = url || `${ENVIRONMENT.baseURL}${apiV3}logs/livetail`;
|
||||||
|
|
||||||
|
const TIMEOUT_IN_MS = 10 * 60 * 1000;
|
||||||
|
|
||||||
|
eventSourceRef.current = new EventSourcePolyfill(eventSourceUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${user?.accessJwt}`,
|
||||||
|
},
|
||||||
|
heartbeatTimeout: TIMEOUT_IN_MS,
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsConnectionLoading(true);
|
||||||
|
setIsConnectionError('');
|
||||||
|
|
||||||
|
eventSourceRef.current.addEventListener('error', handleErrorConnection);
|
||||||
|
|
||||||
|
eventSourceRef.current.addEventListener('open', handleOpenConnection);
|
||||||
|
},
|
||||||
|
[handleErrorConnection, handleOpenConnection, user?.accessJwt],
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextValue = useMemo(
|
||||||
|
() => ({
|
||||||
|
eventSourceInstance: eventSourceRef.current,
|
||||||
|
isConnectionError,
|
||||||
|
isConnectionLoading,
|
||||||
|
isConnectionOpen,
|
||||||
|
handleStartOpenConnection,
|
||||||
|
handleCloseConnection,
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
isConnectionError,
|
||||||
|
isConnectionLoading,
|
||||||
|
isConnectionOpen,
|
||||||
|
handleStartOpenConnection,
|
||||||
|
handleCloseConnection,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EventSourceContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</EventSourceContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEventSource = (): IEventSourceContext => {
|
||||||
|
const context = useContext(EventSourceContext);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('Should be used inside the context');
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user