Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Sources/SignalRClient/ConnectionProtocol.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

enum ConnectionFeature: String, CaseIterable {
case Reconnect = "reconnect"
case Resend = "resend"
case Disconnected = "disconnected"
}

protocol ConnectionProtocol: AnyObject, Sendable {
func onReceive(_ handler: @escaping Transport.OnReceiveHandler) async
func onClose(_ handler: @escaping Transport.OnCloseHander) async
func start(transferFormat: TransferFormat) async throws
func send(_ data: StringOrData) async throws
func stop(error: Error?) async
var inherentKeepAlive: Bool { get async }
var features: [ConnectionFeature: Any] { get async }
func setFeature(feature: ConnectionFeature, value: Any) async
}
48 changes: 43 additions & 5 deletions Sources/SignalRClient/HttpConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ actor HttpConnection: ConnectionProtocol {
private var accessTokenFactory: (@Sendable () async throws -> String?)?
private var inherentKeepAlivePrivate: Bool = false

public var features: [String: Any] = [:]
public var features: [ConnectionFeature: Any] = [:]
public var baseUrl: String
public var connectionId: String?
public var inherentKeepAlive: Bool {
Expand Down Expand Up @@ -359,9 +359,37 @@ actor HttpConnection: ConnectionProtocol {

private func startTransport(url: String, transferFormat: TransferFormat) async throws {
await transport!.onReceive(self.onReceive)
await transport!.onClose { [weak self] error in
guard let self = self else { return }
await self.handleConnectionClose(error: error)
if (self.features[ConnectionFeature.Reconnect] as? Bool) == true {
await transport!.onClose { [weak self] error in
var callStop = false;
guard let self = self else { return }
if await (self.features[ConnectionFeature.Reconnect] as? Bool) == true {
do {
if let disconnectedHandler = await self.features[ConnectionFeature.Disconnected] as? (Error?) -> Void {
disconnectedHandler(error);
}
try await self.transport?.connect(url: url, transferFormat: transferFormat);
if let resendHandler = await self.features[ConnectionFeature.Resend] as? () -> Void {
resendHandler();
}
} catch {
callStop = true;
}
}
else {
await self.handleConnectionClose(error: error);
return;
}
if callStop {
await self.handleConnectionClose(error: error);
}
}
}
else {
await transport!.onClose { [weak self] error in
guard let self = self else { return }
await self.handleConnectionClose(error: error)
}
}

do {
Expand Down Expand Up @@ -435,6 +463,12 @@ actor HttpConnection: ConnectionProtocol {
if let useStatefulReconnect = options.useStatefulReconnect, useStatefulReconnect {
queryItems.append(URLQueryItem(name: "useStatefulReconnect", value: "true"))
}
else {
if (queryItems.first(where: { $0.name == "useStatefulReconnect" })?.value ?? "false") == "true" {
options.useStatefulReconnect = true;
}
}

negotiateUrlComponents.queryItems = queryItems
return negotiateUrlComponents.url!.absoluteString
}
Expand Down Expand Up @@ -476,7 +510,7 @@ actor HttpConnection: ConnectionProtocol {
let transferFormats = endpoint.transferFormats.compactMap { TransferFormat($0) }
if transferFormats.contains(requestedTransferFormat) {
do {
features["reconnect"] = (transportType == .webSockets && useStatefulReconnect) ? true : nil
self.features[ConnectionFeature.Reconnect] = (transportType == .webSockets && useStatefulReconnect) ? true : false;
let constructedTransport = try await constructTransport(transport: transportType)
return constructedTransport
} catch {
Expand Down Expand Up @@ -511,4 +545,8 @@ actor HttpConnection: ConnectionProtocol {
}
return urlRequest
}

public func setFeature(feature: ConnectionFeature, value: Any) async {
features[feature] = value
}
}
Loading
Loading