Skip to content

Commit ec93040

Browse files
authored
Merge pull request #150 from boostcampwm-2024/refactor/NearbyNetwork
[Refactor] NearbyNetwork 참여 요청, 수락 기능 리팩터링
2 parents ae89e28 + c4b30e2 commit ec93040

File tree

13 files changed

+464
-43
lines changed

13 files changed

+464
-43
lines changed

DataSource/DataSource/Sources/Interface/NearbyNetworkInterface.swift

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,23 @@ public protocol NearbyNetworkInterface {
3333
/// 주변에 내 기기 알리는 것을 중지합니다.
3434
func stopPublishing()
3535

36-
/// 연결된 모든 피어와 연결을 끊습니다.
36+
/// 연결된 모든 피어와 연결을 끊습니다.
3737
func disconnectAll()
3838

3939
/// 주변 기기와 연결을 시도합니다.
4040
/// - Parameter connection: 연결할 기기
41+
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
4142
func joinConnection(connection: NetworkConnection, context: RequestedContext) throws
4243

44+
/// 주변 기기와 연결을 시도합니다.
45+
/// - Parameters:
46+
/// - connection: 연결할 기기
47+
/// - myConnectionInfo: 내 정보
48+
/// - Returns: 연결 요청 성공 여부
49+
func joinConnection(
50+
connection: RefactoredNetworkConnection,
51+
myConnectionInfo: RequestedContext) -> Result<Bool, Never>
52+
4353
/// 연결된 기기들에게 데이터를 송신합니다.
4454
/// - Parameter data: 송신할 데이터
4555
func send(data: Data)
@@ -59,7 +69,7 @@ public protocol NearbyNetworkInterface {
5969
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
6070
func send(
6171
fileURL: URL,
62-
info: DataSource.DataInformationDTO,
72+
info: DataInformationDTO,
6373
to connection: NetworkConnection) async
6474
}
6575

@@ -86,27 +96,40 @@ public protocol NearbyNetworkConnectionDelegate: AnyObject {
8696
/// - Parameters:
8797
/// - connection: 연결된 기기
8898
/// - info: 기존 Session 정보
99+
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
89100
func nearbyNetwork(
90101
_ sender: NearbyNetworkInterface,
91102
didConnect connection: NetworkConnection,
92103
with info: [String: String])
93104

94-
/// 주변 기기와 연결에 성공했을 때 실행됩니다.
105+
/// 주변 기기와 연결에 성공하였을 때 실행됩니다.
95106
/// - Parameters:
107+
/// - connection: 연결된 기기
96108
/// - context: 참여자가 보낸 정보
97109
/// - isHost: 호스트 여부
110+
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
98111
func nearbyNetwork(
99112
_ sender: NearbyNetworkInterface,
100113
didConnect connection: NetworkConnection,
101114
with context: Data?,
102115
isHost: Bool)
103116

117+
/// 주변 기기와 연결에 성공했을 때 실행됩니다.
118+
/// - Parameters:
119+
/// - didConnect: 연결된 peer
120+
func nearbyNetwork(_ sender: NearbyNetworkInterface, didConnect connection: RefactoredNetworkConnection)
121+
104122
/// 연결됐던 기기와 연결이 끊어졌을 때 실행됩니다.
105123
/// - Parameters:
106124
/// - connection: 연결이 끊긴 기기
107-
/// - isHost: 호스트 여부
125+
@available(*, deprecated, message: "이 메서드는 network framework로 리팩터링 하면서 사용되지 않을 예정입니다.")
108126
func nearbyNetwork(
109127
_ sender: NearbyNetworkInterface,
110128
didDisconnect connection: NetworkConnection,
111129
isHost: Bool)
130+
131+
/// 연결됐던 기기와 연결이 끊어졌을 때 실행됩니다.
132+
/// - Parameters:
133+
/// - connection: 연결이 끊긴 기기
134+
func nearbyNetwork(_ sender: NearbyNetworkInterface, didDisconnect connection: RefactoredNetworkConnection)
112135
}

DataSource/DataSource/Sources/Model/NetworkConnection.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,14 @@ public struct RefactoredNetworkConnection: Codable {
4545
}
4646
}
4747

48-
extension RefactoredNetworkConnection: Equatable {
48+
extension RefactoredNetworkConnection: Hashable {
4949
public static func == (lhs: RefactoredNetworkConnection, rhs: RefactoredNetworkConnection) -> Bool {
5050
return lhs.id == rhs.id
5151
}
5252
}
53+
54+
extension RefactoredNetworkConnection: CustomStringConvertible {
55+
public var description: String {
56+
return "ID: \(id), Name: \(name)"
57+
}
58+
}

DataSource/DataSource/Sources/Model/RequestedContext.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88
import Foundation
99

1010
public struct RequestedContext: Codable {
11-
let nickname: String
12-
let participant: String
11+
public let peerID: UUID
12+
public let nickname: String
13+
public let participant: String
1314

14-
public init(nickname: String, participant: String) {
15+
public init(
16+
peerID: UUID,
17+
nickname: String,
18+
participant: String
19+
) {
20+
self.peerID = peerID
1521
self.nickname = nickname
1622
self.participant = participant
1723
}

DataSource/DataSource/Sources/Repository/WhiteboardRepository.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ public final class WhiteboardRepository: WhiteboardRepositoryInterface {
5454
name: whiteboard.name,
5555
info: participantsInfo)
5656

57-
let context = RequestedContext(nickname: myProfile.nickname, participant: myProfile.profileIcon.emoji)
57+
let context = RequestedContext(
58+
peerID: myProfile.id,
59+
nickname: myProfile.nickname,
60+
participant: myProfile.profileIcon.emoji)
5861

5962
try nearbyNetwork.joinConnection(connection: connection, context: context)
6063
}
@@ -170,6 +173,13 @@ extension WhiteboardRepository: NearbyNetworkConnectionDelegate {
170173
}
171174
}
172175

176+
public func nearbyNetwork(
177+
_ sender: any NearbyNetworkInterface,
178+
didConnect connection: RefactoredNetworkConnection
179+
) {
180+
// TODO: - 연결 되었을 때 화이트보드에 프로필 정보 넘기기
181+
}
182+
173183
public func nearbyNetwork(
174184
_ sender: any NearbyNetworkInterface,
175185
didDisconnect connection: NetworkConnection,
@@ -181,4 +191,11 @@ extension WhiteboardRepository: NearbyNetworkConnectionDelegate {
181191
updatePublishingInfo(myProfile: myProfile)
182192
nearbyNetwork.startPublishing(with: self.participantsInfo)
183193
}
194+
195+
public func nearbyNetwork(
196+
_ sender: any NearbyNetworkInterface,
197+
didDisconnect connection: RefactoredNetworkConnection
198+
) {
199+
// TODO: - 연결 끊겼을 때 화이트보드에 프로필 정보 넘기기
200+
}
184201
}

Domain/DomainTests/ManageWhiteboardObjectsUseCaseTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ final class MockWhiteObjectRepository: WhiteboardObjectRepositoryInterface {
453453
}
454454

455455
final class MockWhiteboardRepository: WhiteboardRepositoryInterface {
456-
457456
var delegate: (any WhiteboardRepositoryDelegate)?
458457
var recentPeerPublisher: AnyPublisher<Domain.Profile, Never>
459458
var connectionResultPublisher: AnyPublisher<Bool, Never>

NearbyNetwork/NearbyNetwork.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
00549AD62CEDDDB700DF8F6C /* MCSessionState+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00549AD52CEDDDB100DF8F6C /* MCSessionState+.swift */; };
1414
00549AD82CEDDDCF00DF8F6C /* MCSession+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00549AD72CEDDDCF00DF8F6C /* MCSession+.swift */; };
1515
0080E86A2CE19EC40095B958 /* NearbyNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0080E8672CE19EC40095B958 /* NearbyNetworkService.swift */; };
16+
00CA7A102D2E08DA00116F9E /* NearbyNetworkProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00CA7A0F2D2E08DA00116F9E /* NearbyNetworkProtocol.swift */; };
1617
5B7C6EBF2CDB6C6E0024704A /* DataSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7C6EBE2CDB6C6E0024704A /* DataSource.framework */; };
1718
5B7C6EC02CDB6C6E0024704A /* DataSource.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7C6EBE2CDB6C6E0024704A /* DataSource.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1819
A83D2AB02D23BAFC007EC41F /* NearbyNetworkListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83D2AAF2D23BAFC007EC41F /* NearbyNetworkListener.swift */; };
@@ -51,6 +52,7 @@
5152
00549AD52CEDDDB100DF8F6C /* MCSessionState+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MCSessionState+.swift"; sourceTree = "<group>"; };
5253
00549AD72CEDDDCF00DF8F6C /* MCSession+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MCSession+.swift"; sourceTree = "<group>"; };
5354
0080E8672CE19EC40095B958 /* NearbyNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyNetworkService.swift; sourceTree = "<group>"; };
55+
00CA7A0F2D2E08DA00116F9E /* NearbyNetworkProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyNetworkProtocol.swift; sourceTree = "<group>"; };
5456
5B7C6E652CDB6A560024704A /* NearbyNetwork.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NearbyNetwork.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5557
5B7C6EBE2CDB6C6E0024704A /* DataSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataSource.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5658
A83D2AAF2D23BAFC007EC41F /* NearbyNetworkListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NearbyNetworkListener.swift; sourceTree = "<group>"; };
@@ -107,6 +109,7 @@
107109
isa = PBXGroup;
108110
children = (
109111
00549AD32CEDDDA300DF8F6C /* Common */,
112+
00CA7A0F2D2E08DA00116F9E /* NearbyNetworkProtocol.swift */,
110113
0080E8672CE19EC40095B958 /* NearbyNetworkService.swift */,
111114
002DEC942D22A99F00ED7EE3 /* RefactoredNearbyNetworkService.swift */,
112115
A83D2AAF2D23BAFC007EC41F /* NearbyNetworkListener.swift */,
@@ -297,6 +300,7 @@
297300
A83D2AB22D23BE88007EC41F /* NearbyNetworkBrowser.swift in Sources */,
298301
00549AD62CEDDDB700DF8F6C /* MCSessionState+.swift in Sources */,
299302
A83D2AB02D23BAFC007EC41F /* NearbyNetworkListener.swift in Sources */,
303+
00CA7A102D2E08DA00116F9E /* NearbyNetworkProtocol.swift in Sources */,
300304
00549AD82CEDDDCF00DF8F6C /* MCSession+.swift in Sources */,
301305
002DEC952D22A99F00ED7EE3 /* RefactoredNearbyNetworkService.swift in Sources */,
302306
0080E86A2CE19EC40095B958 /* NearbyNetworkService.swift in Sources */,

NearbyNetwork/NearbyNetwork/Sources/NearbyNetworkBrowser.swift

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,45 @@
55
// Created by 최정인 on 12/31/24.
66
//
77

8+
import DataSource
89
import Foundation
910
import Network
1011
import OSLog
1112

1213
public protocol NearbyNetworkBrowserDelegate: AnyObject {
1314
func nearbyNetworkBrowserDidFindPeer(
1415
_ sender: NearbyNetworkBrowser,
15-
hostName: String,
16-
connectedPeerInfo: [String])
16+
foundPeers: [RefactoredNetworkConnection])
1717
}
1818

1919
public final class NearbyNetworkBrowser {
2020
private let nwBrowser: NWBrowser
2121
private let browserQueue: DispatchQueue
2222
private let serviceType: String
2323
private let logger: Logger
24+
private var foundPeers: [RefactoredNetworkConnection: NWEndpoint] {
25+
didSet {
26+
let foundPeers = foundPeers
27+
.keys
28+
.sorted(by: { $0.name < $1.name })
29+
delegate?.nearbyNetworkBrowserDidFindPeer(self, foundPeers: Array(foundPeers))
30+
}
31+
}
2432
weak var delegate: NearbyNetworkBrowserDelegate?
2533

2634
init(serviceType: String) {
35+
let option = NWProtocolFramer.Options(definition: NearbyNetworkProtocol.definition)
36+
let parameter = NWParameters.tcp
37+
parameter.defaultProtocolStack
38+
.applicationProtocols
39+
.insert(option, at: 0)
2740
nwBrowser = NWBrowser(
2841
for: .bonjourWithTXTRecord(type: serviceType, domain: nil),
29-
using: .tcp)
42+
using: parameter)
3043
self.browserQueue = DispatchQueue.global()
3144
self.serviceType = serviceType
3245
self.logger = Logger()
46+
self.foundPeers = [:]
3347
configure()
3448
}
3549

@@ -38,30 +52,51 @@ public final class NearbyNetworkBrowser {
3852
}
3953

4054
private func browserHandler(results: Set<NWBrowser.Result>, changes: Set<NWBrowser.Result.Change>) {
41-
for result in results {
42-
switch result.metadata {
43-
case .bonjour(let foundedPeerData):
44-
let dictionary = foundedPeerData.dictionary
45-
guard
46-
let hostName = dictionary[NearbyNetworkKey.host.rawValue],
47-
let connectedPeerInfo = dictionary[NearbyNetworkKey.connectedPeerInfo.rawValue]
48-
else {
49-
logger.log(level: .error, "connection의 데이터 값이 유효하지 않습니다.")
50-
return
51-
}
52-
53-
delegate?.nearbyNetworkBrowserDidFindPeer(
54-
self,
55-
hostName: hostName,
56-
connectedPeerInfo: connectedPeerInfo
57-
.split(separator: ",")
58-
.map { String($0) })
55+
for change in changes {
56+
switch change {
57+
case .added(let result):
58+
guard let foundPeer = convertMetadata(metadata: result.metadata) else { return }
59+
foundPeers[foundPeer] = result.endpoint
60+
case .removed(let result):
61+
guard let foundPeer = convertMetadata(metadata: result.metadata) else { return }
62+
foundPeers[foundPeer] = nil
5963
default:
60-
logger.log(level: .error, "알 수 없는 피어가 발견되었습니다.")
64+
break
65+
}
66+
}
67+
}
68+
69+
private func convertMetadata(metadata: NWBrowser.Result.Metadata) -> RefactoredNetworkConnection? {
70+
switch metadata {
71+
case .bonjour(let foundedPeerData):
72+
let dictionary = foundedPeerData.dictionary
73+
guard
74+
let peerIDString = dictionary[NearbyNetworkKey.peerID.rawValue],
75+
let peerID = UUID(uuidString: peerIDString),
76+
let hostName = dictionary[NearbyNetworkKey.host.rawValue],
77+
let connectedPeerInfo = dictionary[NearbyNetworkKey.connectedPeerInfo.rawValue]
78+
else {
79+
logger.log(level: .error, "connection의 데이터 값이 유효하지 않습니다.")
80+
return nil
6181
}
82+
83+
let foundPeer = RefactoredNetworkConnection(
84+
id: peerID,
85+
name: hostName,
86+
connectedPeerInfo: connectedPeerInfo
87+
.split(separator: ",")
88+
.map { String($0) })
89+
return foundPeer
90+
default:
91+
logger.log(level: .error, "알 수 없는 피어가 발견되었습니다.")
92+
return nil
6293
}
6394
}
6495

96+
func fetchFoundConnection(networkConnection: RefactoredNetworkConnection) -> NWEndpoint? {
97+
return foundPeers[networkConnection]
98+
}
99+
65100
func startSearching() {
66101
nwBrowser.start(queue: browserQueue)
67102
}

NearbyNetwork/NearbyNetwork/Sources/NearbyNetworkKey.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
public enum NearbyNetworkKey: String {
9+
case peerID
910
case host
1011
case connectedPeerInfo
1112
}

NearbyNetwork/NearbyNetwork/Sources/NearbyNetworkListener.swift

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,45 @@ import Foundation
99
import Network
1010
import OSLog
1111

12-
final class NearbyNetworkListener {
12+
public protocol NearbyNetworkListenerDelegate: AnyObject {
13+
/// 주변 기기와 연결에 성공하였을 때 실행됩니다.
14+
/// - Parameters:
15+
/// - didConnect: 연결된 기기
16+
func nearbyNetworkListener(_ sender: NearbyNetworkListener, didConnect connection: NWConnection)
17+
18+
/// 주변 기기와 연결이 끊겼을 때 실행됩니다.
19+
/// - Parameters:
20+
/// - didDisconnect: 연결이 끊긴 기기
21+
func nearbyNetworkListener(_ sender: NearbyNetworkListener, didDisconnect connection: NWConnection)
22+
23+
/// 주변 기기와 연결에 실패했을 때 실행됩니다.
24+
/// - Parameters:
25+
/// - connection: 연결에 실패한 기기
26+
func nearbyNetworkListenerCannotConnect(_ sender: NearbyNetworkListener, connection: NWConnection)
27+
}
28+
29+
public final class NearbyNetworkListener {
30+
weak var delegate: NearbyNetworkListenerDelegate?
1331
private var nwListener: NWListener?
1432
private let listenerQueue: DispatchQueue
33+
private let peerID: UUID
1534
private let serviceName: String
1635
private let serviceType: String
1736
private let logger: Logger
1837

19-
init(serviceName: String, serviceType: String) {
20-
nwListener = try? NWListener(using: .tcp)
38+
init(
39+
peerID: UUID,
40+
serviceName: String,
41+
serviceType: String
42+
) {
43+
let option = NWProtocolFramer.Options(definition: NearbyNetworkProtocol.definition)
44+
let parameter = NWParameters.tcp
45+
parameter.defaultProtocolStack
46+
.applicationProtocols
47+
.insert(option, at: 0)
48+
nwListener = try? NWListener(using: parameter)
2149
listenerQueue = DispatchQueue.global()
50+
self.peerID = peerID
2251
self.serviceName = serviceName
2352
self.serviceType = serviceType
2453
self.logger = Logger()
@@ -27,12 +56,28 @@ final class NearbyNetworkListener {
2756

2857
private func configure() {
2958
nwListener?.newConnectionHandler = { connection in
59+
connection.stateUpdateHandler = { state in
60+
switch state {
61+
case .ready:
62+
self.logger.log(level: .debug, "\(connection.debugDescription)와 연결되었습니다.")
63+
self.delegate?.nearbyNetworkListener(self, didConnect: connection)
64+
case .failed:
65+
self.logger.log(level: .debug, "\(connection.debugDescription)와 연결에 실패했습니다")
66+
self.delegate?.nearbyNetworkListenerCannotConnect(self, connection: connection)
67+
case .cancelled:
68+
self.logger.log(level: .debug, "\(connection.debugDescription)와 연결이 끊어졌습니다.")
69+
self.delegate?.nearbyNetworkListener(self, didDisconnect: connection)
70+
default:
71+
self.logger.log(level: .debug, "\(connection.debugDescription)와 연결 설정 중입니다.")
72+
}
73+
}
3074
connection.start(queue: self.listenerQueue)
3175
}
3276
}
3377

3478
func startPublishing(hostName: String, connectedPeerInfo: [String]) {
3579
let connectionData = [
80+
NearbyNetworkKey.peerID.rawValue: peerID.uuidString,
3681
NearbyNetworkKey.host.rawValue: hostName,
3782
NearbyNetworkKey.connectedPeerInfo.rawValue: connectedPeerInfo.joined(separator: ",")]
3883
let txtRecord = NWTXTRecord(connectionData)

0 commit comments

Comments
 (0)