fix quicClient

This commit is contained in:
anlicheng 2026-04-28 16:23:01 +08:00
parent 26dc6b5152
commit d900fdb379
2 changed files with 128 additions and 82 deletions

View File

@ -181,12 +181,6 @@ actor SDLContextActor {
try await Task.sleep(for: .seconds(0.3))
SDLLogger.log("[SDLContext] start quic client: \(self.config.serverHost)")
// self.quicWorker = Task {
// for await message in await quicClient.messageStream {
// await self.handleQUICMessage(message: message)
// }
// }
try await withThrowingTaskGroup { group in
defer {
group.cancelAll()
@ -196,16 +190,19 @@ actor SDLContextActor {
for await message in await quicClient.messageStream {
await self.handleQUICMessage(message: message)
}
throw SDLQUICClientExit.transportClosed("messageStream finished")
}
group.addTask {
let exit = await quicClient.run()
switch exit {
case .normal, .cancelled:
case .normal:
return
case .cancelled:
if Task.isCancelled {
return
}
throw exit
case .transportClosed, .readFailed, .writeFailed:
throw exit
}
@ -222,9 +219,11 @@ actor SDLContextActor {
throw error
}
}
throw SDLQUICClientExit.cancelled
}
try await group.next()
while let _ = try await group.next() {
()
}
}
}

View File

@ -66,6 +66,8 @@ actor SDLQUICClient {
public var eventStream: AsyncStream<SDLQUICEvent>
private let eventCont: AsyncStream<SDLQUICEvent>.Continuation
private var didFinishStreams = false
private let connection: NWConnection
private let queue = DispatchQueue(label: "com.sdl.QUICClient.queue") // 线
@ -92,51 +94,38 @@ actor SDLQUICClient {
}
func start() {
connection.stateUpdateHandler = { state in
SDLLogger.log("[SDLQUICClient] new state: \(state)", for: .debug)
switch state {
case .ready:
connection.stateUpdateHandler = { [weak self] state in
Task {
await self.readyState.markReady()
}
case .failed(let error):
Task {
await self.readyState.markFailed(error)
}
self.eventCont.yield(.failed(error))
case .cancelled:
Task {
await self.readyState.markCancelled()
}
self.eventCont.yield(.cancelled)
case .setup, .preparing:
Task {
await self.readyState.markConnecting()
}
default:
()
await self?.handleConnectionStateUpdate(state)
}
}
connection.start(queue: self.queue)
}
private func handleConnectionStateUpdate(_ state: NWConnection.State) async {
SDLLogger.log("[SDLQUICClient] new state: \(state)", for: .debug)
switch state {
case .ready:
await self.readyState.markReady()
case .failed(let error):
await self.readyState.markFailed(error)
self.emitEvent(.failed(error))
case .cancelled:
await self.readyState.markCancelled()
self.emitEvent(.cancelled)
case .setup, .preparing:
await self.readyState.markConnecting()
default:
()
}
}
func waitReady(timeout: Duration = .seconds(5)) async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
try await self.readyState.waitReady()
}
group.addTask {
try await Task.sleep(for: timeout)
throw SDLQUICError.timeout
}
try await group.next()
group.cancelAll()
}
try await self.readyState.waitReady(timeout: timeout)
}
func run() async -> SDLQUICClientExit {
await withTaskCancellationHandler {
await withTaskGroup(of: SDLQUICClientExit.self) { group in
group.addTask {
await self.readLoop()
@ -148,9 +137,16 @@ actor SDLQUICClient {
let exit = await group.next() ?? .normal
group.cancelAll()
await self.stop()
self.finishStreams()
return exit
}
} onCancel: {
Task {
await self.stop()
}
}
}
func send(type: SDLPacketType, data: Data) {
@ -163,7 +159,9 @@ actor SDLQUICClient {
connection.send(content: packet, completion: .contentProcessed { [weak self] error in
if let error {
SDLLogger.log("[SDLQUICClient] send data get error: \(error)", for: .debug)
self?.eventCont.yield(.writeFailed(error))
Task {
await self?.emitEvent(.writeFailed(error))
}
}
})
}
@ -183,16 +181,33 @@ actor SDLQUICClient {
return .cancelled
}
func stop() {
func stop() async {
self.connection.cancel()
await self.readyState.markCancelled()
self.finishStreams()
}
func close(_ exit: SDLQUICClientExit = .normal) async {
private func emitEvent(_ event: SDLQUICEvent) {
guard !self.didFinishStreams else {
return
}
self.eventCont.yield(event)
}
private func finishStreams() {
guard !self.didFinishStreams else {
return
}
self.didFinishStreams = true
self.messageCont.finish()
self.eventCont.finish()
}
deinit {
self.messageCont.finish()
self.connection.cancel()
self.finishStreams()
}
}
@ -209,24 +224,56 @@ extension SDLQUICClient {
}
private var state: State = .idle
private var continuations: [CheckedContinuation<Void, Error>] = []
private var continuations: [UUID: CheckedContinuation<Void, Error>] = [:]
func waitReady() async throws {
func waitReady(timeout: Duration) async throws {
let id = UUID()
let timeoutTask = Task {
try? await Task.sleep(for: timeout)
if Task.isCancelled {
return
}
await self.cancelWaiter(id: id, throwing: SDLQUICError.timeout)
}
defer {
timeoutTask.cancel()
}
try await withTaskCancellationHandler {
try await withCheckedThrowingContinuation { continuation in
self.addWaiter(id: id, continuation: continuation)
}
} onCancel: {
timeoutTask.cancel()
Task {
await self.cancelWaiter(id: id, throwing: CancellationError())
}
}
}
private func addWaiter(id: UUID, continuation: CheckedContinuation<Void, Error>) {
switch state {
case .ready:
return
continuation.resume()
case .failed(let error):
throw error
continuation.resume(throwing: error)
case .cancelled:
throw CancellationError()
continuation.resume(throwing: CancellationError())
case .idle, .connecting:
try await withCheckedThrowingContinuation { continuation in
continuations.append(continuation)
continuations[id] = continuation
}
}
private func cancelWaiter(id: UUID, throwing error: Error) {
guard let continuation = continuations.removeValue(forKey: id) else {
return
}
continuation.resume(throwing: error)
}
func markConnecting() {
@ -244,7 +291,7 @@ extension SDLQUICClient {
let list = continuations
continuations.removeAll()
for continuation in list {
for continuation in list.values {
continuation.resume()
}
}
@ -255,7 +302,7 @@ extension SDLQUICClient {
let list = continuations
continuations.removeAll()
for continuation in list {
for continuation in list.values {
continuation.resume(throwing: error)
}
}
@ -266,7 +313,7 @@ extension SDLQUICClient {
let list = continuations
continuations.removeAll()
for continuation in list {
for continuation in list.values {
continuation.resume(throwing: CancellationError())
}
}