From c8fa30d8479d40c2711b1a7df0b1c9b69b76fd49 Mon Sep 17 00:00:00 2001 From: racgoo Date: Tue, 20 Aug 2024 18:23:14 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix(socket):=20client2=EA=B0=9C=20=EC=83=9D?= =?UTF-8?q?=EA=B8=B0=EB=8A=94=EA=B1=B0=20=EC=88=98=EC=A0=95=20->=20constru?= =?UTF-8?q?ctor=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/chat/RealTimeChatting.tsx | 8 +++- packages/admin/src/hooks/socket/index.ts | 14 ++++++- .../admin/src/hooks/socket/useChatSocket.ts | 31 ++++++++++++++-- packages/admin/src/services/socket.ts | 37 ++++++++++++++----- packages/common/src/constants/socket.ts | 4 +- packages/user/src/services/socket.ts | 2 +- 6 files changed, 79 insertions(+), 17 deletions(-) diff --git a/packages/admin/src/components/chat/RealTimeChatting.tsx b/packages/admin/src/components/chat/RealTimeChatting.tsx index bca9f4c7..53442ed4 100644 --- a/packages/admin/src/components/chat/RealTimeChatting.tsx +++ b/packages/admin/src/components/chat/RealTimeChatting.tsx @@ -9,10 +9,11 @@ import Chat from './Chat.js'; /** 실시간 기대평 섹션 */ function RealTimeChatting({ - chatSocket: { messages, onBlock, onNotice, notice }, + chatSocket: { messages, onBlock, onNotice, notice, onRequestMessageHistory }, }: Pick) { const { openAlert, addAlertCallback } = useAlert(); const noticeInputRef = useRef(null); + const handleSend: React.FormEventHandler = (event) => { event.preventDefault(); const { value } = noticeInputRef!.current!; @@ -26,12 +27,17 @@ function RealTimeChatting({ } }; + const handleLoadHistory = () => { + onRequestMessageHistory(); + }; + return (
+
공지사항 : {notice}
diff --git a/packages/admin/src/hooks/socket/index.ts b/packages/admin/src/hooks/socket/index.ts index 1a8b43f5..b3b99836 100644 --- a/packages/admin/src/hooks/socket/index.ts +++ b/packages/admin/src/hooks/socket/index.ts @@ -8,8 +8,17 @@ export type AdminSocketReturnType = ReturnType; export default function useSocket() { const accessToken = Cookie.getCookie(ACCESS_TOKEN_KEY) ?? ''; + const chatSocket = useChatSocket(); - const { onReceiveMessage, onReceiveBlock, onReceiveNotice, ...chatSocketProps } = chatSocket; + + const { + onReceiveMessage, + onReceiveBlock, + onReceiveNotice, + onReceiveMessageHistory, + ...chatSocketProps + } = chatSocket; + useEffect(() => { if (accessToken !== '') { socketManager.connectSocketClient({ @@ -17,9 +26,10 @@ export default function useSocket() { onReceiveMessage, onReceiveBlock, onReceiveNotice, + onReceiveMessageHistory, }); } - }, [socketManager, accessToken]); + }, []); return { chatSocket: chatSocketProps }; } diff --git a/packages/admin/src/hooks/socket/useChatSocket.ts b/packages/admin/src/hooks/socket/useChatSocket.ts index 973f0b53..1bd3d026 100644 --- a/packages/admin/src/hooks/socket/useChatSocket.ts +++ b/packages/admin/src/hooks/socket/useChatSocket.ts @@ -12,6 +12,8 @@ export default function useChatSocket() { const socketClient = socketManager.getSocketClient(); + // const socketClient = socketManager.getSocketClient(); + const [chatMessages, setChatMessages] = useState([]); const [notice, setNotice] = useState(''); @@ -47,7 +49,16 @@ export default function useChatSocket() { const { content } = data as { content: string }; setNotice(content); }, - [socketClient], + [chatMessages], + ); + + const handleIncomingMessageHistory: SocketSubscribeCallbackType = useCallback( + (data: unknown) => { + console.log(data); + // const { content } = data as { content: string }; + // setNotice(content); + }, + [chatMessages], ); const handleBlock = useCallback( @@ -65,7 +76,7 @@ export default function useChatSocket() { openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); } }, - [socketClient], + [chatMessages], ); const handleSendNotice = useCallback( @@ -81,15 +92,29 @@ export default function useChatSocket() { openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); } }, - [socketClient], + [chatMessages], ); + const handleRequestMessageHistory = useCallback(() => { + try { + socketClient.sendMessages({ + destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_MESSAGE_HISTORY, + body: {}, + }); + } catch (error) { + const errorMessage = (error as Error).message; + openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); + } + }, [chatMessages]); + return { onReceiveMessage: handleIncomingMessage, onReceiveBlock: handleIncomintBlock, onReceiveNotice: handleIncomingNotice, + onReceiveMessageHistory: handleIncomingMessageHistory, onBlock: handleBlock, onNotice: handleSendNotice, + onRequestMessageHistory: handleRequestMessageHistory, messages: chatMessages, notice, }; diff --git a/packages/admin/src/services/socket.ts b/packages/admin/src/services/socket.ts index 640198f1..fd65bac6 100644 --- a/packages/admin/src/services/socket.ts +++ b/packages/admin/src/services/socket.ts @@ -1,11 +1,9 @@ -import { ACCESS_TOKEN_KEY, CHAT_SOCKET_ENDPOINTS } from '@softeer/common/constants'; -import { Cookie, Socket, SocketSubscribeCallbackType } from '@softeer/common/utils'; +import { CHAT_SOCKET_ENDPOINTS } from '@softeer/common/constants'; +import { Socket, SocketSubscribeCallbackType } from '@softeer/common/utils'; import { SOCKET_BASE_URL } from 'src/constants/environments.ts'; // import CustomError from 'src/utils/error.ts'; class SocketManager { - private static instance: SocketManager | null = null; - private socketClient: Socket | null = null; private onReceiveMessage: SocketSubscribeCallbackType | null = null; @@ -14,14 +12,22 @@ class SocketManager { private onReceiveNotice: SocketSubscribeCallbackType | null = null; - constructor(token: string | null) { - this.initializeSocketClient(token); - } + private onReceiveMessageHistory: SocketSubscribeCallbackType | null = null; + + private isConnected: boolean = false; + + // constructor(token: string | null) { + // this.initializeSocketClient(token); + // } public getSocketClient() { return this.socketClient!; } + public getIsConnected() { + return this.isConnected; + } + private initializeSocketClient(token?: string | null) { if (token) { this.socketClient = new Socket(SOCKET_BASE_URL, token); @@ -33,22 +39,27 @@ class SocketManager { onReceiveMessage, onReceiveBlock, onReceiveNotice, + onReceiveMessageHistory, }: { token: string | null | undefined; onReceiveMessage: SocketSubscribeCallbackType; onReceiveBlock: SocketSubscribeCallbackType; onReceiveNotice: SocketSubscribeCallbackType; + onReceiveMessageHistory: SocketSubscribeCallbackType; }) { this.initializeSocketClient(token); this.onReceiveMessage = onReceiveMessage; this.onReceiveBlock = onReceiveBlock; this.onReceiveNotice = onReceiveNotice; + this.onReceiveMessageHistory = onReceiveMessageHistory; this.socketClient!.connect((isConnected) => { if (isConnected) { this.subscribeToTopics(); + this.isConnected = true; } else { + this.isConnected = false; // throw new CustomError('서버에서 데이터를 불러오는 데 실패했습니다.', 500); } }); @@ -63,6 +74,7 @@ class SocketManager { onReceiveBlock: this.onReceiveBlock!, onReceiveMessage: this.onReceiveMessage!, onReceiveNotice: this.onReceiveNotice!, + onReceiveMessageHistory: this.onReceiveMessageHistory!, }); } @@ -70,7 +82,7 @@ class SocketManager { if (this.socketClient) { if (this.onReceiveMessage) { this.socketClient.subscribe({ - destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT, + destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE, callback: this.onReceiveMessage, }); } @@ -87,9 +99,16 @@ class SocketManager { callback: this.onReceiveNotice, }); } + + if (this.onReceiveMessageHistory) { + this.socketClient.subscribe({ + destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE_HISTORY, + callback: this.onReceiveMessageHistory, + }); + } } } } +const socketManager = new SocketManager(); -const socketManager = new SocketManager(Cookie.getCookie(ACCESS_TOKEN_KEY)); export default socketManager; diff --git a/packages/common/src/constants/socket.ts b/packages/common/src/constants/socket.ts index 9d7213df..db650e8d 100644 --- a/packages/common/src/constants/socket.ts +++ b/packages/common/src/constants/socket.ts @@ -1,12 +1,14 @@ import { Category, SocketCategory } from 'src/types/category.ts'; export const CHAT_SOCKET_ENDPOINTS = { - SUBSCRIBE_CHAT: '/topic/chat', + SUBSCRIBE_MESSAGE: '/topic/chat', PUBLISH_CHAT: '/app/chat.sendMessage', SUBSCRIBE_BLOCK: '/topic/block', PUBLISH_BLOCK: '/app/chat.sendBlock', SUBSCRIBE_NOTICE: '/topic/notice', PUBLISH_NOTICE: '/app/chat.sendNotice', + SUBSCRIBE_MESSAGE_HISTORY: '/user/queue/chatHistory', + PUBLISH_MESSAGE_HISTORY: '/app/chat.getHistory', } as const; export const RACING_SOCKET_ENDPOINTS = { diff --git a/packages/user/src/services/socket.ts b/packages/user/src/services/socket.ts index 7fec4484..a760482a 100644 --- a/packages/user/src/services/socket.ts +++ b/packages/user/src/services/socket.ts @@ -71,7 +71,7 @@ class SocketManager { if (this.socketClient) { if (this.onReceiveMessage) { this.socketClient.subscribe({ - destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT, + destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE, callback: this.onReceiveMessage, }); } From f0853adac713cebac7c24955222ab745e0a13c43 Mon Sep 17 00:00:00 2001 From: racgoo Date: Wed, 21 Aug 2024 15:10:17 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat(history):=20=EC=B1=84=ED=8C=85=20histo?= =?UTF-8?q?ry=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/chat/RealTimeChatting.tsx | 5 -- packages/admin/src/hooks/socket/index.ts | 1 - .../admin/src/hooks/socket/useChatSocket.ts | 73 ++++++++++++------- packages/admin/src/pages/review/Review.tsx | 6 ++ packages/admin/src/services/eventBus.ts | 18 +++++ packages/admin/src/services/socket.ts | 7 +- 6 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 packages/admin/src/services/eventBus.ts diff --git a/packages/admin/src/components/chat/RealTimeChatting.tsx b/packages/admin/src/components/chat/RealTimeChatting.tsx index 53442ed4..934c8c2c 100644 --- a/packages/admin/src/components/chat/RealTimeChatting.tsx +++ b/packages/admin/src/components/chat/RealTimeChatting.tsx @@ -27,17 +27,12 @@ function RealTimeChatting({ } }; - const handleLoadHistory = () => { - onRequestMessageHistory(); - }; - return (
-
공지사항 : {notice}
diff --git a/packages/admin/src/hooks/socket/index.ts b/packages/admin/src/hooks/socket/index.ts index b3b99836..ee48604b 100644 --- a/packages/admin/src/hooks/socket/index.ts +++ b/packages/admin/src/hooks/socket/index.ts @@ -8,7 +8,6 @@ export type AdminSocketReturnType = ReturnType; export default function useSocket() { const accessToken = Cookie.getCookie(ACCESS_TOKEN_KEY) ?? ''; - const chatSocket = useChatSocket(); const { diff --git a/packages/admin/src/hooks/socket/useChatSocket.ts b/packages/admin/src/hooks/socket/useChatSocket.ts index 1bd3d026..1523c6aa 100644 --- a/packages/admin/src/hooks/socket/useChatSocket.ts +++ b/packages/admin/src/hooks/socket/useChatSocket.ts @@ -1,7 +1,9 @@ import { ChatProps } from '@softeer/common/components'; import { CHAT_SOCKET_ENDPOINTS } from '@softeer/common/constants'; -import { SocketSubscribeCallbackType } from '@softeer/common/utils'; -import { useCallback, useState } from 'react'; +import { Socket, SocketSubscribeCallbackType } from '@softeer/common/utils'; +import { useCallback, useEffect, useState } from 'react'; +import { eventBus } from 'src/services/eventBus.ts'; + import socketManager from 'src/services/socket.ts'; import { useAlert } from 'src/store/provider/AlertProvider.tsx'; @@ -9,14 +11,20 @@ export type AdminChatSocketReturnType = ReturnType; export default function useChatSocket() { const { openAlert } = useAlert(); - - const socketClient = socketManager.getSocketClient(); - - // const socketClient = socketManager.getSocketClient(); - + const [socketClient, setSocketClient] = useState(null); + const [isValid, setIsValid] = useState(false); const [chatMessages, setChatMessages] = useState([]); const [notice, setNotice] = useState(''); + const updateSocket = () => { + setSocketClient(socketManager.getSocketClient()); + setIsValid(true); + }; + + useEffect(() => { + eventBus.on('socket_connected', updateSocket); + }, []); + const handleIncomingMessage: SocketSubscribeCallbackType = useCallback( (data: unknown, messageId: string) => { const parsedData = data as Omit; @@ -54,9 +62,9 @@ export default function useChatSocket() { const handleIncomingMessageHistory: SocketSubscribeCallbackType = useCallback( (data: unknown) => { - console.log(data); - // const { content } = data as { content: string }; - // setNotice(content); + const parsedDataList = data as Omit[]; + const parsedMessage = parsedDataList.map(parsedData => ({ ...parsedData })); + setChatMessages((prevMessages) => [...parsedMessage, ...prevMessages] as ChatProps[]); }, [chatMessages], ); @@ -67,45 +75,57 @@ export default function useChatSocket() { blockId: id, }; try { - socketClient.sendMessages({ - destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_BLOCK, - body: blockId, - }); + if (socketClient) { + socketClient.sendMessages({ + destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_BLOCK, + body: blockId, + }); + } else { + openAlert('소켓이 연결되지 않았습니다.', 'alert'); + } } catch (error) { const errorMessage = (error as Error).message; openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); } }, - [chatMessages], + [socketClient], ); const handleSendNotice = useCallback( (content: string) => { try { - const chatMessage = { content }; - socketClient.sendMessages({ - destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_NOTICE, - body: chatMessage, - }); + if (socketClient) { + const chatMessage = { content }; + socketClient.sendMessages({ + destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_NOTICE, + body: chatMessage, + }); + } else { + openAlert('소켓이 연결되지 않았습니다.', 'alert'); + } } catch (error) { const errorMessage = (error as Error).message; openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); } }, - [chatMessages], + [socketClient], ); const handleRequestMessageHistory = useCallback(() => { try { - socketClient.sendMessages({ - destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_MESSAGE_HISTORY, - body: {}, - }); + if (socketClient) { + socketClient.sendMessages({ + destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_MESSAGE_HISTORY, + body: {}, + }); + } else { + openAlert('소켓이 연결되지 않았습니다.', 'alert'); + } } catch (error) { const errorMessage = (error as Error).message; openAlert(errorMessage.length > 0 ? errorMessage : '문제가 발생했습니다.', 'alert'); } - }, [chatMessages]); + }, [socketClient]); return { onReceiveMessage: handleIncomingMessage, @@ -117,5 +137,6 @@ export default function useChatSocket() { onRequestMessageHistory: handleRequestMessageHistory, messages: chatMessages, notice, + isValid, }; } diff --git a/packages/admin/src/pages/review/Review.tsx b/packages/admin/src/pages/review/Review.tsx index e6b6b563..0f111ad2 100644 --- a/packages/admin/src/pages/review/Review.tsx +++ b/packages/admin/src/pages/review/Review.tsx @@ -1,8 +1,14 @@ +import { useEffect } from 'react'; import RealTimeChatting from 'src/components/chat/RealTimeChatting.tsx'; import useSocket from 'src/hooks/socket/index.ts'; function Review() { const { chatSocket } = useSocket(); + useEffect(() => { + if (chatSocket.isValid) { + chatSocket.onRequestMessageHistory(); + } + }, [chatSocket.isValid]); return ; } export default Review; diff --git a/packages/admin/src/services/eventBus.ts b/packages/admin/src/services/eventBus.ts new file mode 100644 index 00000000..ede570e3 --- /dev/null +++ b/packages/admin/src/services/eventBus.ts @@ -0,0 +1,18 @@ +class EventBus { + private eventTarget = new EventTarget(); + + public on(event: string, callback: (event: Event) => void): void { + this.eventTarget.addEventListener(event, callback); + } + + public off(event: string, callback: (event: Event) => void): void { + this.eventTarget.removeEventListener(event, callback); + } + + public emit(event: string, detail: any): void { + const customEvent = new CustomEvent(event, { detail }); + this.eventTarget.dispatchEvent(customEvent); + } +} + +export const eventBus = new EventBus(); diff --git a/packages/admin/src/services/socket.ts b/packages/admin/src/services/socket.ts index fd65bac6..87b8f544 100644 --- a/packages/admin/src/services/socket.ts +++ b/packages/admin/src/services/socket.ts @@ -1,6 +1,8 @@ import { CHAT_SOCKET_ENDPOINTS } from '@softeer/common/constants'; import { Socket, SocketSubscribeCallbackType } from '@softeer/common/utils'; import { SOCKET_BASE_URL } from 'src/constants/environments.ts'; +import { eventBus } from './eventBus.ts'; + // import CustomError from 'src/utils/error.ts'; class SocketManager { @@ -16,10 +18,6 @@ class SocketManager { private isConnected: boolean = false; - // constructor(token: string | null) { - // this.initializeSocketClient(token); - // } - public getSocketClient() { return this.socketClient!; } @@ -56,6 +54,7 @@ class SocketManager { this.socketClient!.connect((isConnected) => { if (isConnected) { + eventBus.emit('socket_connected', {}); this.subscribeToTopics(); this.isConnected = true; } else { From c7d8ebd36eb6f30be090fc8fd134c4a3d3501078 Mon Sep 17 00:00:00 2001 From: racgoo Date: Wed, 21 Aug 2024 15:17:06 +0900 Subject: [PATCH 3/3] fix(merge): conflict_resolve --- packages/admin/src/components/chat/RealTimeChatting.tsx | 6 +++--- packages/common/src/constants/socket.ts | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/admin/src/components/chat/RealTimeChatting.tsx b/packages/admin/src/components/chat/RealTimeChatting.tsx index 934c8c2c..ea3d9b82 100644 --- a/packages/admin/src/components/chat/RealTimeChatting.tsx +++ b/packages/admin/src/components/chat/RealTimeChatting.tsx @@ -2,14 +2,14 @@ import { ChatList } from '@softeer/common/components'; import { useRef } from 'react'; import { AdminSocketReturnType } from 'src/hooks/socket/index.ts'; import { useAlert } from 'src/store/provider/AlertProvider.tsx'; -import { Button } from '../ui/button.js'; -import { Input } from '../ui/input.js'; +import { Button } from '../ui/button.tsx'; +import { Input } from '../ui/input.tsx'; import Chat from './Chat.js'; /** 실시간 기대평 섹션 */ function RealTimeChatting({ - chatSocket: { messages, onBlock, onNotice, notice, onRequestMessageHistory }, + chatSocket: { messages, onBlock, onNotice, notice }, }: Pick) { const { openAlert, addAlertCallback } = useAlert(); const noticeInputRef = useRef(null); diff --git a/packages/common/src/constants/socket.ts b/packages/common/src/constants/socket.ts index 5237e8e4..7484829a 100644 --- a/packages/common/src/constants/socket.ts +++ b/packages/common/src/constants/socket.ts @@ -7,15 +7,9 @@ export const CHAT_SOCKET_ENDPOINTS = { PUBLISH_BLOCK: '/app/chat.sendBlock', SUBSCRIBE_NOTICE: '/topic/notice', PUBLISH_NOTICE: '/app/chat.sendNotice', -<<<<<<< HEAD - SUBSCRIBE_MESSAGE_HISTORY: '/user/queue/chatHistory', - PUBLISH_MESSAGE_HISTORY: '/app/chat.getHistory', -======= SUBSCRIBE_MESSAGE_HISTORY: '/user/queue/chatHistory', PUBLISH_MESSAGE_HISTORY: '/app/chat.getHistory', SUBSCRIBE_ERROR: '/user/queue/errors', - ->>>>>>> main } as const; export const RACING_SOCKET_ENDPOINTS = {