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

[Refactor] NearbyNetwork 데이터 송수신 기능 리팩터링 #152

Merged
merged 2 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,18 @@ public protocol NearbyNetworkInterface {
connection: RefactoredNetworkConnection,
myConnectionInfo: RequestedContext) -> Result<Bool, Never>

/// 연결된 기기들에게 데이터를 송신합니다.
/// - Parameter data: 송신할 데이터
func send(data: Data)

/// 연결된 기기들에게 파일을 송신합니다.
/// - Parameters:
/// - fileURL: 파일의 URL
/// - info: 파일에 대한 정보
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
func send(fileURL: URL, info: DataInformationDTO) async

/// 연결된 기기들에게 데이터를 송신합니다.
/// - Parameter data: 송신할 데이터
/// - Returns: 전송 성공 여부
func send(data: DataInformationDTO) async -> Bool

/// 특정 기기에게 파일을 전송합니다.
/// - Parameters:
/// - fileURL: 파일의 URL
Expand All @@ -71,6 +72,13 @@ public protocol NearbyNetworkInterface {
fileURL: URL,
info: DataInformationDTO,
to connection: NetworkConnection) async

/// 특정 기기에게 데이터를 전송합니다.
/// - Parameters:
/// - data: 송신할 데이터
/// - connection: 전송할 기기 연결 정보
/// - Returns: 전송 성공 여부
func send(data: DataInformationDTO, to connection: RefactoredNetworkConnection) async -> Bool
}

public protocol NearbyNetworkConnectionDelegate: AnyObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public final class NearbyNetworkBrowser {
init(serviceType: String) {
let option = NWProtocolFramer.Options(definition: NearbyNetworkProtocol.definition)
let parameter = NWParameters.tcp
parameter.defaultProtocolStack
parameter
.defaultProtocolStack
.applicationProtocols
.insert(option, at: 0)
nwBrowser = NWBrowser(
Expand Down
17 changes: 8 additions & 9 deletions NearbyNetwork/NearbyNetwork/Sources/NearbyNetworkProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ enum NearbyNetworkMessageType: UInt32 {
case data = 2
}

// Create a class that implements a framing protocol.
class NearbyNetworkProtocol: NWProtocolFramerImplementation {
static let definition = NWProtocolFramer.Definition(implementation: NearbyNetworkProtocol.self)
static var label: String { return "NearbyNetworkProtocol" }
Expand All @@ -26,7 +25,6 @@ class NearbyNetworkProtocol: NWProtocolFramerImplementation {
func stop(framer: NWProtocolFramer.Instance) -> Bool { return true }
func cleanup(framer: NWProtocolFramer.Instance) { }

// Whenever the application sends a message, add your protocol header and forward the bytes.
func handleOutput(
framer: NWProtocolFramer.Instance,
message: NWProtocolFramer.Message,
Expand All @@ -42,18 +40,20 @@ class NearbyNetworkProtocol: NWProtocolFramerImplementation {
// framer에 헤더를 넣어줍니다.
framer.writeOutput(data: header.encodedData)

// Ask the connection to insert the content of the app message after your header.
// 헤더 뒤 메시지를 넣어줍니다.
try? framer.writeOutputNoCopy(length: messageLength)
}

// Whenever new bytes are available to read, try to parse out your message format.
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
while true {
// Try to read out a single header.
// 헤더 읽기
var tempHeader: NearbyNetworkProtocolHeader? = nil
let headerSize = NearbyNetworkProtocolHeader.encodedSize

let parsed = framer.parseInput(minimumIncompleteLength: headerSize, maximumLength: headerSize) { (buffer, _) -> Int in
let parsed = framer.parseInput(
minimumIncompleteLength: headerSize,
maximumLength: headerSize
) { (buffer, _) -> Int in
guard
let buffer = buffer,
buffer.count >= headerSize
Expand All @@ -69,23 +69,22 @@ class NearbyNetworkProtocol: NWProtocolFramerImplementation {
let header = tempHeader
else { return headerSize }

// Create an object to deliver the message.
// 수신된 메시지 만들기
var messageType = NearbyNetworkMessageType.invalid
if let parsedMessageType = NearbyNetworkMessageType(rawValue: header.type) {
messageType = parsedMessageType
}

let message = NWProtocolFramer.Message(nearbyNetworkMessageType: messageType)

// Deliver the body of the message, along with the message object.
if !framer.deliverInputNoCopy(length: Int(header.length), message: message, isComplete: true) {
return 0
}
}
}
}

// Extend framer messages to handle storing your command types in the message metadata.
// Message metadata를 쉽게 관리하기 위해 기능 확장
extension NWProtocolFramer.Message {
convenience init(nearbyNetworkMessageType: NearbyNetworkMessageType) {
self.init(definition: NearbyNetworkProtocol.definition)
Expand Down
10 changes: 9 additions & 1 deletion NearbyNetwork/NearbyNetwork/Sources/NearbyNetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ extension NearbyNetworkService: NearbyNetworkInterface {
}
}

public func send(fileURL: URL, info: DataSource.DataInformationDTO) async {
public func send(fileURL: URL, info: DataInformationDTO) async {
let infoJsonData = try? encoder.encode(info)

guard
Expand All @@ -150,6 +150,10 @@ extension NearbyNetworkService: NearbyNetworkInterface {
}
}

public func send(data: DataInformationDTO) async -> Bool {
return true
Copy link
Collaborator

Choose a reason for hiding this comment

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

갑자기 이거 보고 생각났는데..
저는 딴이랑 페프할 때 한줄이면 return 생략했거덩요?
별거 아니니까 그냥 무시시 고고??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

허얼 ~ 1줄이여도 노 생략인게 저희 컨벤션으루 기억합니다만 !!??!!!!

Copy link
Collaborator

Choose a reason for hiding this comment

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

엇.. 저희 명시적으로 작성하려구 한 줄 일때도 return 생략하지 않기로 했던 것으로 기억합니다!

}

public func send(
fileURL: URL,
info: DataSource.DataInformationDTO,
Expand All @@ -172,6 +176,10 @@ extension NearbyNetworkService: NearbyNetworkInterface {
self.logger.log(level: .error, "\(peer)에게 file 데이터 전송 실패")
}
}

public func send(data: DataInformationDTO, to connection: RefactoredNetworkConnection) async -> Bool {
return true
}
}

// MARK: - MCSessionDelegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import OSLog
public final class RefactoredNearbyNetworkService {
public var connectionDelegate: NearbyNetworkConnectionDelegate? = nil
public var foundPeerHandler: ((_ networkConnections: [RefactoredNetworkConnection]) -> Void)?
public let refactoredReciptDataPublisher: AnyPublisher<DataInformationDTO, Never>
private let refactoredReciptDataSubject: PassthroughSubject<DataInformationDTO, Never>
private let serviceName: String
private let serviceType: String
private let peerID: UUID
Expand Down Expand Up @@ -42,6 +44,8 @@ public final class RefactoredNearbyNetworkService {
nearbyNetworkConnections = [:]
jsonEncoder = JSONEncoder()
jsonDecoder = JSONDecoder()
refactoredReciptDataSubject = PassthroughSubject<DataInformationDTO, Never>()
refactoredReciptDataPublisher = refactoredReciptDataSubject.eraseToAnyPublisher()
self.serviceName = serviceName
self.serviceType = serviceType
nearbyNetworkBrowser.delegate = self
Expand Down Expand Up @@ -99,7 +103,42 @@ public final class RefactoredNearbyNetworkService {
}

private func handleReceivedData(data: Data?, connection: NWConnection) {
self.logger.log(level: .error, "\(connection.debugDescription): 데이터 수신")
guard
let data,
let dataDTO = try? jsonDecoder.decode(DataInformationDTO.self, from: data)
else { return }

refactoredReciptDataSubject.send(dataDTO)
self.logger.log(level: .debug, "\(connection.debugDescription): 데이터 수신")
}

private func send(data: DataInformationDTO, connection: NWConnection) async -> Bool {
typealias Continuation = CheckedContinuation<Bool, Never>
var tryCount = 0

let encodedData = try? jsonEncoder.encode(data)
let message = NWProtocolFramer.Message(nearbyNetworkMessageType: .data)
let context = NWConnection.ContentContext(identifier: "Data", metadata: [message])

while tryCount < 3 {
let result = await withCheckedContinuation { (continuation: Continuation) in
connection.send(
content: encodedData,
contentContext: context,
completion: .contentProcessed({ error in
if let error {
continuation.resume(returning: false)
} else {
continuation.resume(returning: true)
}
}))
}

if result { return true }
tryCount += 1
}
Comment on lines +123 to +139
Copy link
Member

@eemdeeks eemdeeks Jan 10, 2025

Choose a reason for hiding this comment

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

withCheckedContinuation으로 클로저 내부의 error에 따른 처리를 해 주셨군요..??
다른 방법도 있을 것 같은데, 이 코드를 보니.. 이코드밖에 생각이 안날 것 같네요!(그만큼 훌륭하단 뜻) 좋습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

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

우선 Continuation을 사용한 이유는 send의 결과 값을 반환하기 위해 불가피하게 wrapping 하였습니다!
저희가 고려한 다른 방법은 완료 핸들러를 통해 send 결과를 전달하는 방식이었는데요! 이 방식보다 continuation으로 감싸 결과 값을 직접 반환하는 편이 가독성과 코드 유지 보수 측면에서 더 낫다고 판단했습니다!


return false
}
}

Expand Down Expand Up @@ -192,16 +231,36 @@ extension RefactoredNearbyNetworkService: NearbyNetworkInterface {
}

public func send(data: Data) {

// TODO: - will be deprecated
}

public func send(fileURL: URL, info: DataInformationDTO) async {
// TODO: - will be deprecated
}

public func send(data: DataInformationDTO) async -> Bool {
let result: Bool = await withTaskGroup(of: Bool.self, returning: Bool.self) { taskGroup in
for connection in nearbyNetworkConnections.values {
taskGroup.addTask {
return await self.send(data: data, connection: connection)
}
}
for await childResult in taskGroup {
if !childResult { return false }
}
return true
}
return result
}

public func send(fileURL: URL, info: DataInformationDTO, to connection: NetworkConnection) async {
// TODO: - will be deprecated
}

public func send(data: DataInformationDTO, to connection: RefactoredNetworkConnection) async -> Bool {
guard let connection = nearbyNetworkConnections[connection] else { return false }
return await send(data: data, connection: connection)
}
}

// MARK: - NearbyNetworkBrowserDelegate
Expand Down