Thanks for your advice!
but, new two problems occurred.
When exchanging values using the NWconnection send and receive methods, the first 4 bytes are missing.
I'm not sure how to fundamentally solve the problem.
Adding 4 extra bytes to the beginning is temporarily postponing the problem...
When the Server responds to the Client after receiving a value with receive, it is not returning the value.
I implemented it thinking that it would be possible to return the value as is by sending it within receive. However, the response data is nil, so I think the response method is incorrect.
public class NetworkSession {
...
internal func send(data: Data) {
connection?.send(content: data, completion: .contentProcessed({ [weak self] error in
if let error {
self?.logger.log("Error sending - \(error)")
}
}))
}
internal func receive() {}
}
public class RequestResponseSession: NetworkSession {
public enum Error: Swift.Error {
case requestTimeout
case connectionReset
case encoding(Swift.Error)
case unableToDecode
case unknown
}
private struct PendingRequest {
var id: UInt32
var completion: Future<Bool, Swift.Error>.Promise
}
private enum Command: String, Codable {
case request
case acknowledge
}
private struct RequestData: Codable {
var command: Command
var requestIdentifier: UInt32
var payload: KeyCodedPayload<UInt8>?
}
public private(set) lazy var messagePublisher = messagesSubject.eraseToAnyPublisher()
public let timeout: DispatchTimeInterval = .seconds(10)
public var disconnectOnFailure: Bool = true
private let dispatchQueue = DispatchQueue(label: "RequestResponseSession.dispatchQueue")
private let messagesSubject = PassthroughSubject<Codable, Never>()
private var pendingRequests = [UInt32: PendingRequest]()
private let keyCoder = KeyCoder()
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
...
private func request<Message: Codable>(id: UInt32, message: Message, completion: @escaping Future<Bool, Swift.Error>.Promise) {
dispatchQueue.async { [weak self] in
guard let self else { return }
guard self.state == .connected else {
completion(.failure(NetworkSession.Error.notConnected))
return
}
self.pendingRequests[id] = PendingRequest(id: id, completion: completion)
do {
let payload = try self.keyCoder.encode(value: message)
let requestData = RequestData(command: .request, requestIdentifier: id, payload: payload)
var encodedRequestData = try self.encoder.encode(requestData)
/// ↓ Problem 1, temporary solution
let addData = try self.encoder.encode("aa")
encodedRequestData = addData + encodedRequestData
self.send(data: encodedRequestData)
} catch {
completion(.failure(Error.encoding(error)))
}
}
}
override func receive() {
guard let connection else { return }
connection.receiveMessage { [weak self] data, context, isComplete, error in
guard let self else { return }
if let error { return }
if let data {
self.dispatchQueue.async {
if let receiveData = self.decode(data: data), receiveData.command != .acknowledge {
/// ↓ Problem2, Server is recieve data and send to Client
do {
var data = try self.encoder.encode(RequestData(command: .acknowledge, requestIdentifier: receiveData.requestIdentifier, payload: nil))
self.send(data: data)
} catch {
print("Error encoding acknowledgment - \(error)")
}
}
}
}
if let context, context.isFinal {
self.disconnect()
} else {
self.receive()
}
}
}
private func decode(data: Data) -> RequestData? {
do {
let requestData = try decoder.decode(RequestData.self, from: data)
switch requestData.command {
case .request:
guard let payload = requestData.payload else { break }
let message = try keyCoder.decode(for: payload.codingKey, data: payload.data)
messagesSubject.send(message)
case .acknowledge:
dispatchQueue.async { [weak self] in
guard let request = self?.pendingRequests[requestData.requestIdentifier] else { return }
request.completion(.success(true))
}
}
return requestData
} catch {
print("Error decoding - \(error)")
}
return nil
}
}
struct KeyCoder: KeyCodable {
var keymap: [UInt8: Codable.Type] {
[
0: Invite.self,
1: User.self,
2: CallAction.self,
3: TextMessage.self,
4: Heartbeat.self,
5: Directory.self
]
}
}
Topic:
App & System Services
SubTopic:
Networking
Tags: