| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- 'use client';
- import { createContext, useContext, useEffect, useState, useRef } from 'react';
- import * as signalR from '@microsoft/signalr';
- import { fetchLogout } from '@/lib/api/auth';
- const SignalRContext = createContext<{
- cryptoConnection: signalR.HubConnection | null;
- chatConnection: signalR.HubConnection | null;
- cryptoConnected: boolean;
- chatConnected: boolean;
- stopConnections: () => Promise<void>;
- reconnectChat: (accessToken?: string | null) => Promise<void>;
- }>({
- cryptoConnection: null,
- chatConnection: null,
- cryptoConnected: false,
- chatConnected: false,
- stopConnections: async () => {},
- reconnectChat: async () => {}
- });
- type Props = {
- children: React.ReactNode;
- accessToken: string|null;
- signalRCryptoUrl: string;
- signalRChatUrl: string;
- }
- export function SignalRProvider({ children, accessToken, signalRCryptoUrl, signalRChatUrl }: Props) {
- const cryptoConnectionRef = useRef<signalR.HubConnection|null>(null);
- const chatConnectionRef = useRef<signalR.HubConnection|null>(null);
- const [cryptoConnected, setCryptoConnected] = useState<boolean>(false);
- const [chatConnected, setChatConnected] = useState<boolean>(false);
- // 초기 렌더 시에만 전달됨. 토큰 갱신 시에는 reconnectChat()을 통해 수동으로 재연결 처리
- useEffect(() => {
- initCryptoConnection();
- initChatConnection(accessToken);
- return () => {
- stopConnections();
- };
- }, []);
- useEffect(() => {
- if (cryptoConnected) {
- console.info('SignalR Crypto Connected');
- }
- }, [cryptoConnected]);
- useEffect(() => {
- if (chatConnected) {
- console.info('SignalR Chat Connected');
- }
- }, [chatConnected]);
- const initCryptoConnection = async () => {
- try {
- if (cryptoConnectionRef.current && cryptoConnectionRef.current.state !== signalR.HubConnectionState.Disconnected) {
- return;
- }
- const conn = new signalR.HubConnectionBuilder().withUrl(signalRCryptoUrl).withAutomaticReconnect().build();
- await conn.start();
- setCryptoConnected(true);
- cryptoConnectionRef.current = conn;
- } catch (error) {
- console.error('SignalR Crypto Connect Failed:', error);
- }
- };
- const initChatConnection = async (accessToken?: string|null) => {
- try {
- if (chatConnectionRef.current && chatConnectionRef.current.state !== signalR.HubConnectionState.Disconnected) {
- await chatConnectionRef.current.stop();
- }
- const connectionOptions = accessToken ? { accessTokenFactory: async () => accessToken, withCredentials: true } : {};
- const conn = new signalR.HubConnectionBuilder().withUrl(signalRChatUrl, connectionOptions).withAutomaticReconnect().build();
- await conn.start();
- setChatConnected(true);
- conn.on('Connected', (message) => {
- console.info(message);
- });
- conn.on('Logout', (message) => {
- console.info(message);
- });
- conn.on('Kick', async () => {
- await fetchLogout();
- alert('관리자에 의해 강제 종료되었습니다.');
- localStorage.setItem('rememberMe', 'false');
- localStorage.removeItem('member');
- location.replace('/');
- });
- chatConnectionRef.current = conn;
- } catch (error) {
- console.error('SignalR Chat Connect Failed:', error);
- }
- };
- const stopConnections = async () => {
- if (chatConnectionRef.current && chatConnectionRef.current.state === signalR.HubConnectionState.Connected) {
- try {
- await chatConnectionRef.current.invoke('Logout');
- setChatConnected(false);
- } catch (error) {
- console.error('SignalR Chat Disconnect Failed:', error);
- }
- }
- if (cryptoConnectionRef.current && cryptoConnectionRef.current.state === signalR.HubConnectionState.Connected) {
- try {
- await cryptoConnectionRef.current.stop();
- setCryptoConnected(false);
- } catch (error) {
- console.error('SignalR Crypto Disconnect Failed:', error);
- }
- }
- };
- const reconnectChat = async (token?: string | null) => {
- await initChatConnection(token);
- };
- return (
- <SignalRContext.Provider value={{
- cryptoConnection: cryptoConnectionRef.current,
- chatConnection: chatConnectionRef.current,
- cryptoConnected,
- chatConnected,
- stopConnections,
- reconnectChat
- }}>
- {children}
- </SignalRContext.Provider>
- )
- }
- export function useSignalRContext() {
- return useContext(SignalRContext);
- }
|