Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fe,be/feature/#567 fe,be 소켓 이벤트 타입 공유하기 #571

Merged

Conversation

HeoJiye
Copy link
Collaborator

@HeoJiye HeoJiye commented Feb 23, 2024

Note

현재 이 기능은 내부 라이브러리로 리팩토링되었습니다.
https://github.com/boostcampwm2023/web09-MagicConch/tree/dev/packages/socket-event



🔮 resolved #567

Important

@Doosies
HumanSocketManager에 타입 적용 후, 타입 에러 수정 필요
extends SocketManager<any, any>로 되어 있는 걸 주석 처리된 대로 수정한 후 타입 에러를 수정해야 함.

  • Socket.ts, HumanSocketManager.spec.ts, WebRTC.ts 확인 필요

변경 사항

  • socket 관련 타입 선언 파일을 공유해서 사용하도록 설정
  • socket.on() / socket.emit()에서 정해진 API로 사용하지 않으면 타입 에러가 나도록 설정
    • 이벤트 이름, 파라미터 둘 다

고민과 해결 과정

1️⃣ 공식 문서를 참고해서 type을 지정하도록 시도

https://socket.io/docs/v4/typescript/

외부(/@types/event.d.ts)에 소켓 이벤트 타입을 선언해두는 파일을 놓고 frontend, backend 공통으로 사용하도록 설정함.
아래 처럼 이벤트 종류, 각 이벤트의 리스너의 타입을 선언해둠.

interface AiSocketEvent {
  ServerToClientEvent: {
    streamStart: () => void;
    streaming: (token: string) => void;
    streamEnd: () => void;
    tarotCard: () => void; // 타로 카드 펼치기 요청
    chatEnd: (resultId: string) => void;
    error: (message: string) => void;
  };
  ClientToServerEvent: {
    message: (message: string) => void;
    tarotRead: (cardIdx: number) => void; // 타로 카드 해설 요청
  };
  InterServerEvents: {};
  SocketData: {};
}

interface HumanSocketEvent {
  ServerToClientEvent: {
    connection: (data: { description?: RTCSessionDescription; candidate?: RTCIceCandidate }) => void;
    welcome: (otherUsers: any) => void;
    userExit: (data: { id: string }) => void;
    hostExit: () => void;
    roomCreated: () => void;
    roomNameGenerated: (roomId: string) => void;
    joinRoomFailed: () => void;
    joinRoomSuccess: (roomId: string) => void;
    roomExist: () => void;
    roomNotExist: () => void;
    roomFull: () => void;
  };
  ClientToServerEvent: {
    connection: (data: { description?: RTCSessionDescription; candidate?: RTCIceCandidate; roomName: string }) => void;
    generateRoomName: () => void;
    createRoom: (roomId: string, password: string) => void;
    joinRoom: (roomId: string, password: string) => void;
    checkRoomExist: (roomName: string) => void;
  };
  InterServerEvents: {};
  SocketData: {};
}

2️⃣ socket.on() / socket.emit()에서 정해진 API로 사용하지 않으면 타입 에러가 나도록 설정함.

frontend

export class SocketManager<T1 extends EventsMap, T2 extends EventsMap> {
  #socket: Socket<T1, T2> | undefined;

  on(...params: Parameters<Socket<T1, T2>['on']>) {
    if (!this.#socket) {
      throw new Error('소켓이 존재하지 않습니다.');
    }
    this.#socket.on(...params);
  }

  emit(...params: Parameters<Socket<T1, T2>['emit']>) {
    if (!this.#socket) {
      throw new Error('소켓이 존재하지 않습니다.');
    }
    this.#socket.emit(...params);
  }
export class AISocketManager extends SocketManager<
  AiSocketEvent['ServerToClientEvent'],
  AiSocketEvent['ClientToServerEvent']
> {  ...  }

backend

export type AiServer = Server<
  AiSocketEvent['ClientToServerEvent'],
  AiSocketEvent['ServerToClientEvent']
>;

export interface AiSocket
  extends Socket<
    AiSocketEvent['ClientToServerEvent'],
    AiSocketEvent['ServerToClientEvent']
  > {
  user?: UserInfo;
  chatLog: ChatLog[];
  chatEnd: boolean;
}

export type AiSocketClientEvent = keyof AiSocketEvent['ClientToServerEvent'];

export type AiSocketClientEventParams<T extends AiSocketClientEvent> =
  Parameters<AiSocketEvent['ClientToServerEvent'][T]>;
export class SocketGateway
  implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
  @WebSocketServer()
  readonly server: AiServer;
  
  ...

  @SubscribeMessage<AiSocketClientEvent>('message')
  async handleMessageEvent(
    client: AiSocket,
    ...params: AiSocketClientEventParams<'message'>
  ) {
    ...
  }
  ...

(선택) 테스트 결과

ex) 베이스 브랜치에 포함되기 위한 코드는 모두 정상적으로 동작해야 합니다. 결과물에 대한 스크린샷, GIF, 혹은 라이브 데모가 가능하도록 샘플API를 첨부할 수도 있습니다.

Copy link

cloudflare-workers-and-pages bot commented Feb 23, 2024

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6d9338b
Status: ✅  Deploy successful!
Preview URL: https://91f614f0.web09-magicconch.pages.dev
Branch Preview URL: https://fe-be-feature--567-fe-be.web09-magicconch.pages.dev

View logs

Copy link
Collaborator

@Doosies Doosies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 이제 타입 수정도 용이해지고 이벤트 사용도 더 안전해졌다!

Comment on lines +21 to +22
"typeRoots": ["../../@types"],
"include": ["src", "../../@types"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍

Comment on lines +35 to +54
{
scenario: 'data: { description: RTCSessionDescription; roomName: string } 형식 인수 emit',
eventName: 'connection' as any,
eventArgs: [{ description: 'description', roomName: 'roomName' }],
},
{
scenario: 'data: { candidate: RTCIceCandidate; roomName: string } 형식 인수 emit',
eventName: 'connection' as any,
eventArgs: [{ candidate: 'candidate', roomName: 'roomName' }],
},
{
scenario: 'roomName: string 형식 인수 emit',
eventName: 'checkRoomExist' as any,
eventArgs: ['roomName'],
},
{
scenario: 'roomId: string, password: string 형식 인수 emit',
eventName: 'createRoom' as any,
eventArgs: ['roomId', 'password'],
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 각각 어떤 용도일 때 호출하는지 드러나면 좋을 것 같아!! eventArgs만으로 어떤 걸 emit하는지 알 수 있어서 어떤 경우에 호출하는지가 유지보수할 때 용이할 것 같아

@HeoJiye HeoJiye merged commit e1a76fa into dev Feb 23, 2024
2 checks passed
@HeoJiye HeoJiye deleted the FE,BE/feature/#567-FE,BE-소켓-이벤트-타입-공유하기 branch February 23, 2024 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

✅ FEATURE: FE, BE 소켓 이벤트 타입 공유하기
3 participants