fix quicClient
This commit is contained in:
parent
b37bebd7b2
commit
7b549981af
@ -18,6 +18,7 @@ enum SDLQUICError: Error {
|
||||
case timeout
|
||||
case decodeError(String)
|
||||
case packetTooLarge
|
||||
case waitReadyAlreadyInProgress
|
||||
}
|
||||
|
||||
enum SDLQUICEvent: Error {
|
||||
@ -56,7 +57,17 @@ actor SDLQUICClient {
|
||||
// 最大缓冲区区为2M
|
||||
private let maxBufferSize: Int
|
||||
|
||||
private let readyState = SDLQUICReadyState()
|
||||
private enum ReadyStatus {
|
||||
case idle
|
||||
case connecting
|
||||
case ready
|
||||
case failed(Error)
|
||||
case cancelled
|
||||
}
|
||||
|
||||
private var readyStatus: ReadyStatus = .idle
|
||||
private var readyContinuation: CheckedContinuation<Void, Error>?
|
||||
private var readyTimeoutTask: Task<Void, Never>?
|
||||
|
||||
// 消息流
|
||||
public var messageStream: AsyncStream<SDLQUICInboundMessage>
|
||||
@ -106,22 +117,22 @@ actor SDLQUICClient {
|
||||
SDLLogger.log("[SDLQUICClient] new state: \(state)", for: .debug)
|
||||
switch state {
|
||||
case .ready:
|
||||
await self.readyState.markReady()
|
||||
self.markReady()
|
||||
case .failed(let error):
|
||||
await self.readyState.markFailed(error)
|
||||
self.markFailed(error)
|
||||
self.emitEvent(.failed(error))
|
||||
case .cancelled:
|
||||
await self.readyState.markCancelled()
|
||||
self.markCancelled()
|
||||
self.emitEvent(.cancelled)
|
||||
case .setup, .preparing:
|
||||
await self.readyState.markConnecting()
|
||||
self.markConnecting()
|
||||
default:
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
func waitReady(timeout: Duration = .seconds(5)) async throws {
|
||||
try await self.readyState.waitReady(timeout: timeout)
|
||||
try await self.waitReadyUntilStateChanged(timeout: timeout)
|
||||
}
|
||||
|
||||
func run() async -> SDLQUICClientExit {
|
||||
@ -183,7 +194,7 @@ actor SDLQUICClient {
|
||||
|
||||
func stop() async {
|
||||
self.connection.cancel()
|
||||
await self.readyState.markCancelled()
|
||||
self.markCancelled()
|
||||
self.finishStreams()
|
||||
}
|
||||
|
||||
@ -210,110 +221,100 @@ actor SDLQUICClient {
|
||||
// --MARK: Ready状态机
|
||||
extension SDLQUICClient {
|
||||
|
||||
actor SDLQUICReadyState {
|
||||
enum State {
|
||||
case idle
|
||||
case connecting
|
||||
case ready
|
||||
case failed(Error)
|
||||
case cancelled
|
||||
}
|
||||
|
||||
private var state: State = .idle
|
||||
private var continuations: [UUID: CheckedContinuation<Void, Error>] = [:]
|
||||
|
||||
func waitReady(timeout: Duration) async throws {
|
||||
let id = UUID()
|
||||
let timeoutTask = Task {
|
||||
try? await Task.sleep(for: timeout)
|
||||
if Task.isCancelled {
|
||||
return
|
||||
}
|
||||
self.cancelWaiter(id: id, throwing: SDLQUICError.timeout)
|
||||
}
|
||||
|
||||
defer {
|
||||
timeoutTask.cancel()
|
||||
}
|
||||
private func waitReadyUntilStateChanged(timeout: Duration) async throws {
|
||||
try Task.checkCancellation()
|
||||
|
||||
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 {
|
||||
switch self.readyStatus {
|
||||
case .ready:
|
||||
continuation.resume()
|
||||
|
||||
case .failed(let error):
|
||||
continuation.resume(throwing: error)
|
||||
|
||||
case .cancelled:
|
||||
continuation.resume(throwing: CancellationError())
|
||||
|
||||
continuation.resume(throwing: SDLQUICError.connectionCancelled)
|
||||
case .idle, .connecting:
|
||||
continuations[id] = continuation
|
||||
guard self.readyContinuation == nil else {
|
||||
continuation.resume(throwing: SDLQUICError.waitReadyAlreadyInProgress)
|
||||
return
|
||||
}
|
||||
self.readyContinuation = continuation
|
||||
self.readyTimeoutTask?.cancel()
|
||||
self.readyTimeoutTask = Task {
|
||||
do {
|
||||
try await Task.sleep(for: timeout)
|
||||
if !Task.isCancelled {
|
||||
await self.cancelReadyWaiter(throwing: SDLQUICError.timeout)
|
||||
}
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} onCancel: {
|
||||
Task {
|
||||
await self.cancelReadyWaiter(throwing: CancellationError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func cancelWaiter(id: UUID, throwing error: Error) {
|
||||
guard let continuation = continuations.removeValue(forKey: id) else {
|
||||
private func cancelReadyWaiter(throwing error: Error) {
|
||||
guard let continuation = self.readyContinuation else {
|
||||
return
|
||||
}
|
||||
|
||||
self.readyContinuation = nil
|
||||
self.readyTimeoutTask?.cancel()
|
||||
self.readyTimeoutTask = nil
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
|
||||
func markConnecting() {
|
||||
switch state {
|
||||
private func markConnecting() {
|
||||
switch self.readyStatus {
|
||||
case .idle:
|
||||
state = .connecting
|
||||
self.readyStatus = .connecting
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func markReady() {
|
||||
state = .ready
|
||||
private func markReady() {
|
||||
self.readyStatus = .ready
|
||||
self.resumeReadyWaiter()
|
||||
}
|
||||
|
||||
let list = continuations
|
||||
continuations.removeAll()
|
||||
private func markFailed(_ error: Error) {
|
||||
self.readyStatus = .failed(error)
|
||||
self.resumeReadyWaiter(throwing: error)
|
||||
}
|
||||
|
||||
for continuation in list.values {
|
||||
private func markCancelled() {
|
||||
self.readyStatus = .cancelled
|
||||
self.resumeReadyWaiter(throwing: SDLQUICError.connectionCancelled)
|
||||
}
|
||||
|
||||
private func resumeReadyWaiter() {
|
||||
guard let continuation = self.readyContinuation else {
|
||||
return
|
||||
}
|
||||
|
||||
self.readyContinuation = nil
|
||||
self.readyTimeoutTask?.cancel()
|
||||
self.readyTimeoutTask = nil
|
||||
continuation.resume()
|
||||
}
|
||||
|
||||
private func resumeReadyWaiter(throwing error: Error) {
|
||||
guard let continuation = self.readyContinuation else {
|
||||
return
|
||||
}
|
||||
|
||||
func markFailed(_ error: Error) {
|
||||
state = .failed(error)
|
||||
|
||||
let list = continuations
|
||||
continuations.removeAll()
|
||||
|
||||
for continuation in list.values {
|
||||
self.readyContinuation = nil
|
||||
self.readyTimeoutTask?.cancel()
|
||||
self.readyTimeoutTask = nil
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
func markCancelled() {
|
||||
state = .cancelled
|
||||
|
||||
let list = continuations
|
||||
continuations.removeAll()
|
||||
|
||||
for continuation in list.values {
|
||||
continuation.resume(throwing: CancellationError())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --MARK: Reader
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user