-
Notifications
You must be signed in to change notification settings - Fork 2
[FEAT]/#101 프레임 이벤트 비즈니스 로직 구현 #104
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
Conversation
- DomainInterface에 존재하는 FrameEntity에서 FrameType이 필요했음. - FrameType을 DomainInterface에 두고, FrameImageGenerator에서 의존하도록 구조 변경
- Host, Guest는 EventEntity으로 변경사항을 래핑해서 EventHub에 보내주어야 합니다. - 변경사항으로는 현재 StickerEntity의 변경, FrameType의 변경이 일어날 수 있습니다. - 따라서 이를 분기하기 위해 StickerEntity, FrameType을 연관값으로 갖는 enum 타입의 EventType을 두었습니다.
- EntityType라는 네이밍이 너무 추상적이었습니다. 또한 연관값의 데이터를 전달하는 느낌이 나지 않았습니다. - EventPayload라는 네이밍으로 통신을 통해 전달되는 핵심 데이터의 느낌이 나도록 변경하였습니다.
- EventType과 EventPayload와 같은 enum에 frozen 키워드를 추가하여 열거형이 변경되지 않음을 명시적으로 선언하였습니다.
- 현재 EventHub의 EventManager는 오직 StickerEntity를 담은 Event만을 관리할 수 있습니다. - 하지만 EventHub는 StickerEntity 이외에도 FrameEntity를 담은 Event 또한 관리해야합니다. - 현재 EventManager에서는 관련 StickerEntity를 관리하는 딕셔너리가 존재하기 때문에 해당 Manager에서 Frame 까지 함께 관리한다면 SRP에 위배됩니다. - 따라서 현재의 EventManager를 StickerEntity를 담은 Event만을 담당하는 Manager 역할을 할 수 있도록 리팩터링 하였습니다. - 다음 커밋에서 네이밍 변경이 있습니다.
- 책임 분리를 위해 기존 `StickerEntity`만을 담당하던 `EventManager`를 `StickerEventManager`로 네이밍 변경 - `StickerEventManger` 기준에서는 모호했던 `resultEventPublihser`라는 모호한 네이밍을 사용하지 않고 `braodcastSubject`로 컨텍스트를 강조하는 네이밍으로 변경 - `EventHub`를 바라보는 레퍼지토리의 경우 필요한 것은 `[StickerEntity]이므로 외부에서는 `stickerListPublisher`로 네이밍 변경
- 큐의 현재 상태를 명시적으로 나타내도록 변경 - 외부에 보여지는 publisher와 내부에서 사용하는 subject 분리를 통해 접근제어 수준 변경
- 기존 callEventPublisher라는 네이밍이 StickerEventManger에게 매우 모호했습니다. - Manager가 준비가 되어있어서 이벤트를 받을 수 있다는 의미를 알리는 publisher로 `isReady`라는 네이밍을 채택하였습니다. - Bool 타입이기에 굳이 어미에 Publisher를 붙이지 않았습니다. - 그외 Subject와 Publisher를 연산프로퍼티를 통해 접근제어자를 다루었습니다.
- FrameEventManager 인스턴스를 포함하여 이벤트를 할당 - 이벤트큐는 항상 가능해야하며, 두 매니저(스티커, 프레임)중 하나 이상이 준비된 경우만 필터를 통과합니다. - 만약 이벤트큐에 준비된 최신 이벤트의 payload가 매니저의 담당과 다르다면 무시됩니다. - 프레임은 소유권 상관 없이 브로드캐스팅 됩니다.
- 기존에는 [StickerEntity]를 그대로 담아 보내고 있었습니다. - 추가 기능인 FrameEntity 또한 전달되어야하는 상황에서 if-else 분기문으로 decode를 반복하기보다 EventPayload에 담아 보내어 decode를 1회 반드시 성공한 이후에 switch로 분기하는 방식을 선택했습니다. - EventPayload에 [StickerEntity] 케이스를 추가하였습니다.
- UseCase, Repository 인터페이스 / 구체타입 구현
- ReceiveFrameUseCase 추가
...ayer/PhotoGetherData/PhotoGetherData/EventConnection/EventConnectionHostRepositoryImpl.swift
Outdated
Show resolved
Hide resolved
PhotoGether/DataLayer/PhotoGetherData/PhotoGetherData/EventHub/EventHub.swift
Outdated
Show resolved
Hide resolved
Kiyoung-Kim-57
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와 진짜 고민한 흔적이 많은 코드네요! 많이 배워갑니다!!
0Hooni
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 💯
수고하셨습니다!
|
|
||
| public func mergeSticker(type: EventType, sticker: StickerEntity) { | ||
| let sticketEvent = EventEntity(type: type, timeStamp: Date(), entity: sticker) | ||
| let sticketEvent = EventEntity( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오타 나신것 같아요!
rename로 sticketEvent → stickerEvent로 바꿔주시면 좋을거 같습니다 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style/#101:: 오타 수정 수정 완료했습니다!
🤔 배경
기존
EventEntity는StickerEntity만을payload로 담아 통신하는 구조였습니다.Host,Guest간에FrameEntity또한 브로드캐스팅 되어야하기 때문에 이를 개선해야 했습니다.따라서
FrameEntity를 구현하고, 관련EventHub의 로직을 구현 및 리팩터링이 이뤄졌으며,WebRTC통신과정에서Decoding/Encoding과정을 단순화하고자EventPayload의 연관값과 분기를 활용했습니다.비즈니스로직을
View의UIControl Event와 연동하고자 의존성 주입을 시도하였으나 기존 코드의 많은 개선이 필요하여화면 관련 UI 작업은 너무 길어져서추후 PR로 남기겠습니다.네이밍의 경우 최대한 신경썻지만 이상한 부분은 영훈님과 논의하지 않은 부분이라 임시로 처리되어 있습니다.
ex. sendToViewModel, sendToViewModelFrame등...PR 고봉밥 죄송합니다.. 리뷰노트만 확인해주시고 커밋단위로 훑어보는 정도면 크게 어렵지 않습니다..!
📃 작업 내역
FrameEntity 및 FrameType: 프레임 데이터 관리를 위해 추가 구현EventPayload 구현:EventHub및 통신에서Sticker와Frame데이터를 통합적으로 처리합니다.EventManager 분리:EventHub에서Sticker와Frame이벤트를 각각의 매니저로 분리하여 관리할 수 있도록 리팩터링EventHub 리팩터링:FrameManger가 추가되어 큐 상태와 매니저의 상태를 기반으로 이벤트 처리를 리팩터링Data가 아닌EventPayload타입과 연관값을 활용한 데이터 전송 및 분기 로직을 단순화UseCase,Repository추가 및의존성 주입✅ 리뷰 노트
폴더링 관련
EventHub내의 클래스 및 파일 분리는 컨플릭트를 고려하여 추후 진행할 예정입니다.FrameEventManager 구현
EventType으로.update만을 사용합니다.EventHub 중앙 집중을 위해 반드시 이를 거치도록 구현했습니다.// FrameEventManager.swift private func updateEvent(by frame: FrameEntity) { guard currentFrame?.frameType != frame.frameType else { return } currentFrame = frame broadcastSubject.send(frame) }currentFrame을 갖습니다.EventHub의 EventManager 분리
StickerEventManager만 존재했을 때는 현재EventQueue와StickerEventManager가 준비만 된다면 따로 핸들링이 필요하지 않았습니다.FrameEventManager가 추가되어 부가적인 핸들링이 필요해졌습니다.processEvent에서 준비된 이벤트큐의Event의 타입이Sticker일때는StickerManager가 준비가 되어야하며Frame일때도 상동합니다.EventQueue의popLast()메서드를 호출하면 해당EventQueue에서Event가방출되며 처리되지 않고 리턴되기 때문에 아래와 같은 메서드를EventQueue에 추가하였고processEvent에서 처리하고 있습니다.WebRTC sendData() 통신 시 전달할 데이터의 디코딩/인코딩
// MARK: HOST eventHub.stickerListPublisher .sink { [weak self] entityList in let payload = EventPayload.stickerList(entityList) guard let encodedData = try? self?.encoder.encode(payload) else { return } self?.clients.forEach { $0.sendData(data: encodedData)} ... } .store(in: &cancellables) eventHub.framePublisher .sink { [weak self] frameEntity in let payload = EventPayload.frame(frameEntity) guard let encodedData = try? self?.encoder.encode(payload) else { return } self?.clients.forEach { $0.sendData(data: encodedData) } ... } .store(in: &cancellables)Host는Guest들에게encoding된Data를 송신해야하며, 이때EventPayload에 담아 보냅니다.// MARK: GUEST clients.first?.receivedDataPublisher .sink(receiveValue: { [weak self] data in guard let payload = try? self?.decoder.decode(EventPayload.self, from: data) else { return } switch payload { case .stickerList(let stickerList): self?.receiveDataFromHost.send(stickerList) case .frame(let frameEntity): self?.receiveDataFromHostFrame.send(frameEntity) default: break } }) .store(in: &cancellables)Guest의 경우 해당sendData()로 송신한 데이터를receivedDataPublisher를 통해 수신하며, 이때EventPayload로단 1회 디코딩합니다.EventPayload및 연관값으로 감싸지않고 분기를 통해 각[StickerEntity].self와FrameEntity.self로 디코딩을 하는 경우 불필요한 디코딩 및 실패가 일어날 수 있어 이 방식을 채택하였습니다.🎨 스크린샷
UI를 제외한비즈니스로직만을 구현하였습니다.Guest의receiveDataPublisher, 해당 데이터의EventPayload 디코딩및Sticker/Frame 엔티티의 분기를 확인했습니다.🚀 테스트 방법
asyncAfter를 통해 임의로 Event를 EventHub에 push하면 가능하긴 합니다..