Skip to content

Conversation

@jeon-soyeong
Copy link
Collaborator

@jeon-soyeong jeon-soyeong commented Jan 8, 2026

요약

네트워크 초대 요청 송수신 로직을 구현하였습니다.

작업 목록

  • 네트워크 초대 요청 송수신 로직 구현
    • HostManaging, ClientManaging onDataReceived 추가
    • 네트워크 패킷 구조 추상화 (NetworkTransferable)
    • 패킷 타입 정의 (NetworkPacketType) 및 헤더 분리 (PacketHeader)
    • NetworkSessionManager 데이터 수신 핸들러 분리 (초대 vs 게임 데이터)
    • NetworkSessionManager 제네릭 기반의 패킷 전송 로직 구현 (requestInvite, replyToInvite)

작업 내용

1. 네트워크 패킷 구조 추상화 (NetworkKit)

  • 초대 요청 송수신과 게임 데이터 송수신을 고려해 범용적으로 사용할 수 있는 프로토콜과 타입을 정의했습니다.
    • NetworkPacketType: 패킷의 종류를 정의 (invite, accept, decline, gameData 등).
    • NetworkTransferable (Protocol): 네트워크로 전송 가능한 객체가 준수해야 할 규약. App 계층에서 구체적인 패킷(InvitationPacket, GamePlayPacket 등)을 정의할 때 채택하여 사용합니다.
    • NetworkPacketHeader: 데이터 수신 시, 전체를 디코딩하기 전 패킷의 타입(type)과 보낸 사람(senderIdentifier)을 식별하기 위한 경량 구조체입니다.

2. NetworkSessionManager 수신 로직 (Handle Received Data)

  • 데이터 수신 시 NetworkPacketHeader를 먼저 디코딩하여 패킷 타입을 확인한 후, 역할에 맞는 클로저로 데이터를 분기 처리했습니다.
    • handleReceivedData: 수신된 데이터의 헤더를 확인하고, 초대 관련 패킷과 게임 데이터 패킷을 분리하여 처리합니다.
    • Callback 분리:
      • onReceiveInvitationPacket: 초대, 수락, 거절 등 매칭 관련 데이터 전달.
      • onReceiveGamePacket: 게임 관련 데이터 전달.

3. 제네릭(Generic) 기반 전송 메소드 구현

  • 구체적인 패킷 타입에 의존하지 않고, 외부에서 정의한 패킷을 전송할 수 있도록 제네릭을 도입했습니다.
    • requestInvite: 연결(connect) 시도 후 초대 요청 패킷 전송.
    • replyToInvite: 대기 중인 연결(pendingInviteConnections)을 찾아 응답 패킷 전송.

closes DEV-21

@linear
Copy link

linear bot commented Jan 8, 2026

Copy link
Member

@yungu0010 yungu0010 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다! 궁금한 점 코멘트 남겼어요ㅎ.ㅎ 제가 잘 이해하지 못한 부분이 있다면 설명 부탁드립니다!

@@ -1,17 +1,18 @@
//
// SessionProvider.swift
// NetworkSessionManager.swift
Copy link
Member

Choose a reason for hiding this comment

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

감사합니다👍


// MARK: - Private Methods

private func setupCallbacks() {
Copy link
Member

Choose a reason for hiding this comment

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

p2: 내부 로직을 setupHostCallbacksetupClientCallback으로 분리해도 좋을 것 같네요!


public var onLocalNetworkPermissionGranted: (() -> Void)?
public var onLocalNetworkPermissionDenied: ((Error) -> Void)?
public var onInviteReceived: ((_ from: String) -> Void)?
Copy link
Member

Choose a reason for hiding this comment

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

p1: ConnectionSessionProvider 프로토콜에 함께 선언해주면 좋을 것 같아요!

}

// 메세지 전송 패킷
public struct GamePacket: Codable {
Copy link
Member

Choose a reason for hiding this comment

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

p1: public으로 설정하신 이유가 있는지 궁금합니다! 외부 모듈에서도 해당 Packet의 구조를 알아야하나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

다음 PR UI 작업에서 데이터 전달시 사용할 예정입니다!

Comment on lines 36 to 37
public var onInviteAccepted: (() -> Void)?
public var onInviteDeclined: (() -> Void)?
Copy link
Member

Choose a reason for hiding this comment

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

p2: 부울 값을 담는 클로저로 통합해서 Router에서 분기처리를 하는 방법도 있을 것 같아요~!(취향차이인 것 같아서 참고만 해주세요)

Suggested change
public var onInviteAccepted: (() -> Void)?
public var onInviteDeclined: (() -> Void)?
public var onInviteStateDecided: ((Bool) -> Void)?

private let decoder = JSONDecoder()
private let encoder = JSONEncoder()

private var incomingInviteConnection: NWConnection?
Copy link
Member

Choose a reason for hiding this comment

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

p1: 이렇게 되면 Host는 한 번에 하나의 초대만 관리할 수 있는 것으로 보여요.

디바이스 A, B, C가 있을 때

  1. B가 A에게 초대
  2. A가 고민 중
  3. 그 사이 C가 A에게 초대

이 경우 A는 하나의 connection만 관리하기 때문에 B의 초대에 응답을 할 수 없게될 것 같습니다!(잘못 이해했다면 말씀해주세요)

이런 경우를 처리하기 위해 hostManager에서 connections라는 배열을 두었는데, 여러개의 connections을 관리할 수 있도록 개선이 필요해보여요!

host에서 직접 connection을 관리하고, NetworkSession은 데이터 파싱만 하는 구조를 가지는게 어떨까요.. ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오호 감사합니다!
NetworkSessionManager가 초대 요청에 대한 응답처리도 해야되는데
초대 요청에 대한 응답을 누구한테 줄지 NetworkSessionManager의 handleReceivedData에서 packet을 파싱해서 내용을 보고 누가 보낸 것인지 구분이 필요할 것 같아요! UI에서 packet으로 초대 요청자의 닉네임을 보내오니까 (connection을 패킷에 넣을 수는 없고)
여기서 딕셔너리([닉네임: NWConnection])로 구분해서 사용해도 될 것 같습니당!

}
}

public func sendGamePacket(_ packet: GamePacket, to peer: Peer? = nil) {
Copy link
Member

Choose a reason for hiding this comment

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

p1: Peer가 옵셔널인 이유가 무엇인가요? 초대 요청을 하려면 항상 Peer가 존재해야하는 것 아닌가요?_?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

초대와 수락 응답에 해당 함수를 공통으로 사용하려고 했었고,
수락 응답시에는 이미 연결되어 있는 connection을 저장해놨으니까 peer객체가 필요 없어서 옵셔널로 했었습니다!
근데 요청용과 초대 응답의 함수를 분리하는게 나을 것 같기도 합니다! 위에 수정하면서 고민해볼게요!

Copy link
Collaborator

@leesungkug leesungkug left a comment

Choose a reason for hiding this comment

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

코드 잘 봤습니다! 윤돌이 말해준 것처럼 커넥션 관리하는 부분만 수정되면 좋을 것 같아요

}
}

private func handleReceivedData(_ data: Data, from connection: NWConnection? = nil) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

p2: 나중에 게임 데이터 송수신 시에는 현재 연결된 커넥션을 재사용하거나, 별도 채널을 열어 처리할 수도 있을 것 같아요. 그래서 게임 통신을 구현할 때 메서드 이름만 봐도 초대 데이터 처리 역할이 드러나도록 네이밍을 가져가면 좋을 것 같아요.

Copy link
Collaborator

@oyobbeb oyobbeb left a comment

Choose a reason for hiding this comment

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

회의때 말했던 내용들 다시 작성해보았어요~! 👍🏼

}

// 메세지 전송 패킷
public struct GamePacket: Codable {
Copy link
Collaborator

Choose a reason for hiding this comment

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

p1: GamePacket 이라는 이름이 NetworkKit아래에 있어서 어색한 것 같아요! General한 근거리 통신 혹은 NetworkPacket과 같이 도메인 내용이 없어도 될 것 같아요!

GameMessageType도 동일하게 생각해요!

// 메세지 전송 패킷
public struct GamePacket: Codable {
public let type: GameMessageType
public let senderNickname: String
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: senderIdentifier와 같은 느낌도 괜찮을 것 같아요!

@jeon-soyeong jeon-soyeong changed the title [DEV-21] 네트워크 초대 요청 수신 처리 구현 [DEV-21] 네트워크 초대 요청 송수신 로직 구현 Jan 8, 2026
- GameMessageType: 주고 받을 메세지 타입 정보
- GamePacket: 실제로 주고 받을 메세지 전송 패킷

refs: DEV-21
-  HostManager, ClientManager에서 서로 데이터 수신시 NetworkSessionManager에게 전달하기 위함.

refs: DEV-21
- handleReceivedData: ClientManager, HostManager에서 전달받은 onDataReceived 클로저의 데이터를 처리하여 추후 UI로 전달
- sendGamePacket: UI에서 GamePacket data(초대/ 수락 및 거절 응답)를 보내기 위함.

refs: DEV-21
- onInviteReceived, onInviteResponse, onInviteCanceled 클로저 추가
- requestInvite, replyToInvite 메소드 추가

refs: DEV-21
- sendGamePacket 한개로 초대 / 수락응답을 모두 처리하려고 했으나 역할에 따른 분리가 필요하다고 생각하여 변경
- requestInvite의 데이터 전송 전 연결 체크를 위해 client.connectToHost(endpoint: peer.endpoint) 수정

refs: DEV-21
…e protocol, NetworkPacketHeader, InvitationPacket추가

refs: DEV-21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants