fix superClient
This commit is contained in:
parent
3217614f02
commit
362117aa84
@ -10,10 +10,10 @@ import Network
|
|||||||
|
|
||||||
final class SDLSuperClient: @unchecked Sendable {
|
final class SDLSuperClient: @unchecked Sendable {
|
||||||
private let queue = DispatchQueue(label: "com.sdl.SuperClient.queue") // 专用队列保证线程安全
|
private let queue = DispatchQueue(label: "com.sdl.SuperClient.queue") // 专用队列保证线程安全
|
||||||
// 数据流
|
|
||||||
public let messageStream: AsyncThrowingStream<SDLSuperMessage, Error>
|
public let messageStream: AsyncThrowingStream<SDLSuperMessage, Error>
|
||||||
private let messageCont: AsyncThrowingStream<SDLSuperMessage, Error>.Continuation
|
private let messageContinuation: AsyncThrowingStream<SDLSuperMessage, Error>.Continuation
|
||||||
|
|
||||||
|
private let readySignal = AsyncOneShot<Void>()
|
||||||
private let stateLock = NSLock()
|
private let stateLock = NSLock()
|
||||||
private var isStarted = false
|
private var isStarted = false
|
||||||
private var isStopped = false
|
private var isStopped = false
|
||||||
@ -25,9 +25,9 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
init(serverEndpoint: SDLConfiguration.ResolvedServerEndpoint, port: UInt16, maxBufferSize: Int = 2 * 1024 * 1024) {
|
init(serverEndpoint: SDLConfiguration.ResolvedServerEndpoint, port: UInt16, maxBufferSize: Int = 2 * 1024 * 1024) {
|
||||||
self.maxBufferSize = maxBufferSize
|
self.maxBufferSize = maxBufferSize
|
||||||
|
|
||||||
let pairs = AsyncThrowingStream.makeStream(of: SDLSuperMessage.self)
|
let pairs = AsyncThrowingStream.makeStream(of: SDLSuperMessage.self, bufferingPolicy: .bufferingNewest(1024))
|
||||||
self.messageStream = pairs.stream
|
self.messageStream = pairs.stream
|
||||||
self.messageCont = pairs.continuation
|
self.messageContinuation = pairs.continuation
|
||||||
|
|
||||||
let options = NWProtocolTLS.Options()
|
let options = NWProtocolTLS.Options()
|
||||||
serverEndpoint.host.withCString {
|
serverEndpoint.host.withCString {
|
||||||
@ -62,18 +62,30 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let stateStream = self.makeStateStream()
|
|
||||||
defer {
|
defer {
|
||||||
self.stop()
|
self.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
try await withTaskCancellationHandler {
|
try await withTaskCancellationHandler {
|
||||||
|
self.connection.stateUpdateHandler = { [weak self] state in
|
||||||
|
self?.handleConnectionStateUpdate(state)
|
||||||
|
}
|
||||||
self.connection.start(queue: self.queue)
|
self.connection.start(queue: self.queue)
|
||||||
try await self.waitUntilReady(stateStream)
|
try await self.readySignal.wait()
|
||||||
try await self.readLoop()
|
try await self.readLoop()
|
||||||
|
self.finishMessageStream()
|
||||||
} onCancel: {
|
} onCancel: {
|
||||||
|
self.connection.stateUpdateHandler = nil
|
||||||
self.connection.cancel()
|
self.connection.cancel()
|
||||||
}
|
}
|
||||||
|
} catch is CancellationError {
|
||||||
|
self.finishMessageStream()
|
||||||
|
throw CancellationError()
|
||||||
|
} catch {
|
||||||
|
self.finishMessageStream(throwing: error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func makeEndpointHost(address ip: String) -> NWEndpoint.Host {
|
private static func makeEndpointHost(address ip: String) -> NWEndpoint.Host {
|
||||||
@ -88,37 +100,29 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
preconditionFailure("invalid super server IP: \(ip)")
|
preconditionFailure("invalid super server IP: \(ip)")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeStateStream() -> AsyncThrowingStream<NWConnection.State, Error> {
|
private func handleConnectionStateUpdate(_ state: NWConnection.State) {
|
||||||
let connection = self.connection
|
|
||||||
return AsyncThrowingStream(bufferingPolicy: .bufferingNewest(16)) { continuation in
|
|
||||||
connection.stateUpdateHandler = { [weak self] state in
|
|
||||||
SDLLogger.log("[SDLSuperClient] new state: \(state)", category: .super)
|
SDLLogger.log("[SDLSuperClient] new state: \(state)", category: .super)
|
||||||
switch state {
|
switch state {
|
||||||
|
case .ready:
|
||||||
|
Task {
|
||||||
|
await self.readySignal.succeed(())
|
||||||
|
}
|
||||||
case .failed(let error):
|
case .failed(let error):
|
||||||
let wrappedError = SDLSuperError.connectionFailed(error)
|
let wrappedError = SDLSuperError.connectionFailed(error)
|
||||||
self?.finishMessageStream(throwing: wrappedError)
|
Task {
|
||||||
continuation.finish(throwing: wrappedError)
|
await self.readySignal.fail(wrappedError)
|
||||||
|
}
|
||||||
|
self.finishMessageStream(throwing: wrappedError)
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
self?.finishMessageStream(throwing: SDLSuperError.connectionCancelled)
|
let error = SDLSuperError.connectionCancelled
|
||||||
continuation.finish(throwing: SDLSuperError.connectionCancelled)
|
Task {
|
||||||
|
await self.readySignal.fail(error)
|
||||||
|
}
|
||||||
|
self.finishMessageStream(throwing: error)
|
||||||
default:
|
default:
|
||||||
continuation.yield(state)
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func waitUntilReady(_ stateStream: AsyncThrowingStream<NWConnection.State, Error>) async throws {
|
|
||||||
for try await state in stateStream {
|
|
||||||
try Task.checkCancellation()
|
|
||||||
|
|
||||||
if case .ready = state {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw SDLSuperError.connectionCancelled
|
|
||||||
}
|
|
||||||
|
|
||||||
private func readLoop() async throws {
|
private func readLoop() async throws {
|
||||||
let frameParser = SDLSuperFrameParser(maxBufferSize: self.maxBufferSize)
|
let frameParser = SDLSuperFrameParser(maxBufferSize: self.maxBufferSize)
|
||||||
@ -129,7 +133,7 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
for frame in frames {
|
for frame in frames {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
if let message = SDLSuperCodec.decode(frame: frame) {
|
if let message = SDLSuperCodec.decode(frame: frame) {
|
||||||
self.messageCont.yield(message)
|
self.messageContinuation.yield(message)
|
||||||
} else {
|
} else {
|
||||||
throw SDLSuperError.decodeError("invalid message")
|
throw SDLSuperError.decodeError("invalid message")
|
||||||
}
|
}
|
||||||
@ -151,6 +155,7 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
if let error {
|
if let error {
|
||||||
SDLLogger.log("[SDLSuperClient] send data get error: \(error)", category: .super)
|
SDLLogger.log("[SDLSuperClient] send data get error: \(error)", category: .super)
|
||||||
self?.finishMessageStream(throwing: SDLSuperError.writeFailed(error))
|
self?.finishMessageStream(throwing: SDLSuperError.writeFailed(error))
|
||||||
|
self?.connection.cancel()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -191,6 +196,9 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
let connection = self.connection
|
let connection = self.connection
|
||||||
connection.stateUpdateHandler = nil
|
connection.stateUpdateHandler = nil
|
||||||
connection.cancel()
|
connection.cancel()
|
||||||
|
Task {
|
||||||
|
await self.readySignal.fail(SDLSuperError.connectionCancelled)
|
||||||
|
}
|
||||||
self.finishMessageStream()
|
self.finishMessageStream()
|
||||||
|
|
||||||
SDLLogger.log("[SDLSuperClient] stopped", category: .super)
|
SDLLogger.log("[SDLSuperClient] stopped", category: .super)
|
||||||
@ -237,9 +245,9 @@ final class SDLSuperClient: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let error {
|
if let error {
|
||||||
self.messageCont.finish(throwing: error)
|
self.messageContinuation.finish(throwing: error)
|
||||||
} else {
|
} else {
|
||||||
self.messageCont.finish()
|
self.messageContinuation.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,18 +22,6 @@ final class SDLSuperSession: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run() async throws {
|
func run() async throws {
|
||||||
try await self.runLoops()
|
|
||||||
}
|
|
||||||
|
|
||||||
func stop() async {
|
|
||||||
self.client.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func send(type: SDLPacketType, data: Data) async {
|
|
||||||
self.client.send(type: type, data: data)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func runLoops() async throws {
|
|
||||||
SDLLogger.log("[SDLSuperSession] start super client: \(self.serverEndpoint.ip)", category: .super)
|
SDLLogger.log("[SDLSuperSession] start super client: \(self.serverEndpoint.ip)", category: .super)
|
||||||
|
|
||||||
try await withThrowingTaskGroup(of: Void.self) { group in
|
try await withThrowingTaskGroup(of: Void.self) { group in
|
||||||
@ -57,6 +45,14 @@ final class SDLSuperSession: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stop() async {
|
||||||
|
self.client.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(type: SDLPacketType, data: Data) async {
|
||||||
|
self.client.send(type: type, data: data)
|
||||||
|
}
|
||||||
|
|
||||||
private func readLoop() async throws {
|
private func readLoop() async throws {
|
||||||
for try await message in self.client.messageStream {
|
for try await message in self.client.messageStream {
|
||||||
try Task.checkCancellation()
|
try Task.checkCancellation()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user