signalrProvider.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. 'use client';
  2. import { createContext, useContext, useEffect, useState, useRef } from 'react';
  3. import * as signalR from '@microsoft/signalr';
  4. import useAuth from '@/hooks/useAuth';
  5. const SignalRContext = createContext<{
  6. connection: signalR.HubConnection | null;
  7. connected: boolean;
  8. stopConnection: () => void;
  9. reConnection: () => void;
  10. }>({
  11. connection: null,
  12. connected: false,
  13. stopConnection: () => {},
  14. reConnection: () => {}
  15. });
  16. type Props = {
  17. children: React.ReactNode;
  18. accessToken: string|null;
  19. signalRUrl: string;
  20. }
  21. export function SignalRProvider({ children, accessToken, signalRUrl }: Props) {
  22. const connection = useRef<signalR.HubConnection|null>(null);
  23. const [connected, setConnected] = useState<boolean>(false);
  24. const { logout } = useAuth();
  25. useEffect(() => {
  26. initConnection();
  27. return () => {
  28. if (connection.current) {
  29. stopConnection();
  30. }
  31. };
  32. }, []);
  33. useEffect(() => {
  34. if (connected) {
  35. console.info('SignalR Connected');
  36. } else if(connection.current) {
  37. console.info('SignalR Disconnected');
  38. } else {
  39. console.info('SignalR Waiting...');
  40. }
  41. }, [connected]);
  42. const initConnection = async () => {
  43. try {
  44. if (connection.current && connection.current.state !== signalR.HubConnectionState.Disconnected) {
  45. return;
  46. }
  47. console.log('SignalR Connecting...');
  48. const connectionOptions = accessToken ? { accessTokenFactory: async () => accessToken, withCredentials: true } : {};
  49. const conn = new signalR.HubConnectionBuilder().withUrl(signalRUrl, connectionOptions).build();
  50. if (conn.state === signalR.HubConnectionState.Disconnected) {
  51. console.warn('SignalR Connection is already disconnected');
  52. return;
  53. }
  54. await conn.start();
  55. setConnected(true);
  56. conn.on('Connected', (message) => {
  57. console.info(message);
  58. });
  59. conn.on('Logout', (message) => {
  60. console.info(message);
  61. });
  62. conn.on('Kick', async () => {
  63. await logout();
  64. });
  65. connection.current = conn;
  66. } catch (error) {
  67. console.error('SignalR Connect Failed:', error);
  68. }
  69. };
  70. const stopConnection = async () => {
  71. if (connection.current && connection.current.state === signalR.HubConnectionState.Connected) {
  72. try {
  73. await connection.current.invoke('Logout');
  74. setConnected(false);
  75. } catch (error) {
  76. console.error('SignalR Disconnect Failed:', error);
  77. }
  78. }
  79. };
  80. const reConnection = async () => {
  81. if (connection.current && connection.current.state === signalR.HubConnectionState.Connected) {
  82. try {
  83. console.log('SignalR ReConnecting...');
  84. await connection.current.stop();
  85. await initConnection();
  86. console.log('SignalR ReConnected');
  87. } catch (error) {
  88. console.error("SignalR ReConnection Failed:", error);
  89. }
  90. }
  91. };
  92. return (
  93. <SignalRContext.Provider value={{ connection: connection.current, connected, stopConnection, reConnection }}>
  94. {children}
  95. </SignalRContext.Provider>
  96. )
  97. }
  98. export function useSignalRContext() {
  99. return useContext(SignalRContext);
  100. }