Skip to content

Commit

Permalink
Merge pull request #104 from softeerbootcamp4th/main
Browse files Browse the repository at this point in the history
[Deploy] 8.21 최종 테스트
  • Loading branch information
racgoo authored Aug 21, 2024
2 parents bdbe5d2 + d010a0f commit d22a47e
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 33 deletions.
5 changes: 3 additions & 2 deletions packages/admin/src/components/chat/RealTimeChatting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ 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';

/** 실시간 기대평 섹션 */
Expand All @@ -13,6 +13,7 @@ function RealTimeChatting({
}: Pick<AdminSocketReturnType, 'chatSocket'>) {
const { openAlert, addAlertCallback } = useAlert();
const noticeInputRef = useRef<HTMLInputElement>(null);

const handleSend: React.FormEventHandler<HTMLFormElement> = (event) => {
event.preventDefault();
const { value } = noticeInputRef!.current!;
Expand Down
13 changes: 11 additions & 2 deletions packages/admin/src/hooks/socket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,26 @@ export type AdminSocketReturnType = ReturnType<typeof useSocket>;
export default function useSocket() {
const accessToken = Cookie.getCookie<string>(ACCESS_TOKEN_KEY) ?? '';
const chatSocket = useChatSocket();
const { onReceiveMessage, onReceiveBlock, onReceiveNotice, ...chatSocketProps } = chatSocket;

const {
onReceiveMessage,
onReceiveBlock,
onReceiveNotice,
onReceiveMessageHistory,
...chatSocketProps
} = chatSocket;

useEffect(() => {
if (accessToken !== '') {
socketManager.connectSocketClient({
token: accessToken,
onReceiveMessage,
onReceiveBlock,
onReceiveNotice,
onReceiveMessageHistory,
});
}
}, [socketManager, accessToken]);
}, []);

return { chatSocket: chatSocketProps };
}
75 changes: 60 additions & 15 deletions packages/admin/src/hooks/socket/useChatSocket.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
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';

export type AdminChatSocketReturnType = ReturnType<typeof useChatSocket>;

export default function useChatSocket() {
const { openAlert } = useAlert();

const socketClient = socketManager.getSocketClient();

const [socketClient, setSocketClient] = useState<Socket | null>(null);
const [isValid, setIsValid] = useState(false);
const [chatMessages, setChatMessages] = useState<ChatProps[]>([]);
const [notice, setNotice] = useState<string>('');

const updateSocket = () => {
setSocketClient(socketManager.getSocketClient());
setIsValid(true);
};

useEffect(() => {
eventBus.on('socket_connected', updateSocket);
}, []);

const handleIncomingMessage: SocketSubscribeCallbackType = useCallback((data: unknown) => {
setChatMessages((prevMessages) => [...prevMessages, data] as ChatProps[]);
}, []);
Expand Down Expand Up @@ -42,7 +52,15 @@ export default function useChatSocket() {
const { content } = data as { content: string };
setNotice(content);
},
[socketClient],
[chatMessages],
);

const handleIncomingMessageHistory: SocketSubscribeCallbackType = useCallback(
(data: unknown) => {
const parsedDataList = data as Omit<ChatProps, 'id'>[];
setChatMessages((prevMessages) => [...parsedDataList, ...prevMessages] as ChatProps[]);
},
[chatMessages],
);

const handleBlock = useCallback(
Expand All @@ -51,10 +69,14 @@ 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');
Expand All @@ -66,11 +88,15 @@ export default function useChatSocket() {
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');
Expand All @@ -79,13 +105,32 @@ export default function useChatSocket() {
[socketClient],
);

const handleRequestMessageHistory = useCallback(() => {
try {
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');
}
}, [socketClient]);

return {
onReceiveMessage: handleIncomingMessage,
onReceiveBlock: handleIncomintBlock,
onReceiveNotice: handleIncomingNotice,
onReceiveMessageHistory: handleIncomingMessageHistory,
onBlock: handleBlock,
onNotice: handleSendNotice,
onRequestMessageHistory: handleRequestMessageHistory,
messages: chatMessages,
notice,
isValid,
};
}
6 changes: 6 additions & 0 deletions packages/admin/src/pages/review/Review.tsx
Original file line number Diff line number Diff line change
@@ -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 <RealTimeChatting chatSocket={chatSocket} />;
}
export default Review;
18 changes: 18 additions & 0 deletions packages/admin/src/services/eventBus.ts
Original file line number Diff line number Diff line change
@@ -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();
33 changes: 26 additions & 7 deletions packages/admin/src/services/socket.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
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 { eventBus } from './eventBus.ts';

// import CustomError from 'src/utils/error.ts';

class SocketManager {
Expand All @@ -12,14 +14,18 @@ class SocketManager {

private onReceiveNotice: SocketSubscribeCallbackType | null = null;

constructor(token: string | null) {
this.initializeSocketClient(token);
}
private onReceiveMessageHistory: SocketSubscribeCallbackType | null = null;

private isConnected: boolean = false;

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);
Expand All @@ -31,11 +37,13 @@ class SocketManager {
onReceiveMessage,
onReceiveBlock,
onReceiveNotice,
onReceiveMessageHistory,
}: {
token: string | null | undefined;
onReceiveMessage: SocketSubscribeCallbackType;
onReceiveBlock: SocketSubscribeCallbackType;
onReceiveNotice: SocketSubscribeCallbackType;
onReceiveMessageHistory: SocketSubscribeCallbackType;
}) {
if (this.socketClient) {
await this.socketClient.disconnect();
Expand All @@ -46,10 +54,13 @@ class SocketManager {
this.onReceiveMessage = onReceiveMessage;
this.onReceiveBlock = onReceiveBlock;
this.onReceiveNotice = onReceiveNotice;
this.onReceiveMessageHistory = onReceiveMessageHistory;

try {
await this.socketClient!.connect();
this.subscribeToTopics();
this.isConnected = true;
eventBus.emit('socket_connected', {});
} catch (error) {
throw new Error('서버에서 데이터를 불러오는 데 실패했습니다.');
}
Expand All @@ -61,14 +72,15 @@ class SocketManager {
onReceiveBlock: this.onReceiveBlock!,
onReceiveMessage: this.onReceiveMessage!,
onReceiveNotice: this.onReceiveNotice!,
onReceiveMessageHistory: this.onReceiveMessageHistory!,
});
}

private subscribeToTopics() {
if (this.socketClient) {
if (this.onReceiveMessage) {
this.socketClient.subscribe({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT,
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE,
callback: this.onReceiveMessage,
});
}
Expand All @@ -85,9 +97,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;
7 changes: 3 additions & 4 deletions packages/common/src/constants/socket.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
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_CHAT_LIST: '/user/queue/chatHistory',
PUBLISH_CHAT_LIST: '/app/chat.getHistory',
SUBSCRIBE_MESSAGE_HISTORY: '/user/queue/chatHistory',
PUBLISH_MESSAGE_HISTORY: '/app/chat.getHistory',
SUBSCRIBE_ERROR: '/user/queue/errors',

} as const;

export const RACING_SOCKET_ENDPOINTS = {
Expand Down
6 changes: 3 additions & 3 deletions packages/user/src/services/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ class SocketManager {

if (this.onReceiveChatList) {
await this.socketClient.subscribe({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT_LIST,
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE_HISTORY,
callback: this.onReceiveChatList,
});
this.socketClient.sendMessages({
destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_CHAT_LIST,
destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_MESSAGE_HISTORY,
body: {},
requiresAuth: false,
});
}

if (this.onReceiveMessage) {
this.socketClient.subscribe({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT,
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_MESSAGE,
callback: this.onReceiveMessage,
});
}
Expand Down

0 comments on commit d22a47e

Please sign in to comment.