Skip to content

Commit 67e58f4

Browse files
committed
optimized connect method init
1 parent f4f9134 commit 67e58f4

6 files changed

Lines changed: 937 additions & 92 deletions

File tree

Sources/NetworkConnectivityKit/ConnectivityConfiguration.swift

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,54 @@ import Foundation
1010
// MARK: - ConnectivityConfiguration
1111

1212
public extension NetworkConnectivityKit {
13+
/// Configuration settings for network connectivity testing.
14+
///
15+
/// This struct encapsulates URLSession configuration options specifically optimized
16+
/// for connectivity testing scenarios. It provides sensible defaults for timeout,
17+
/// caching behavior, and cellular access that work well for quick connectivity checks.
18+
///
19+
/// ## Example
20+
/// ```swift
21+
/// // Use default configuration (3s timeout, ignore cache)
22+
/// let config = ConnectivityConfiguration.default
23+
///
24+
/// // Create custom configuration
25+
/// let customConfig = ConnectivityConfiguration(
26+
/// timeout: 5.0,
27+
/// cachePolicy: .ignoreCache,
28+
/// allowsCellularAccess: true
29+
/// )
30+
/// ```
1331
struct ConnectivityConfiguration: Sendable {
32+
/// The underlying URLSession used for network requests.
1433
public let urlSession: URLSession
1534

35+
/// Creates a configuration with an existing URLSession.
36+
///
37+
/// - Parameter urlSession: The URLSession to use for connectivity testing
1638
public init(urlSession: URLSession) {
1739
self.urlSession = urlSession
1840
}
1941

42+
/// Creates a configuration with a URLSessionConfiguration.
43+
///
44+
/// - Parameter urlSessionConfig: The URLSessionConfiguration to use
2045
public init(urlSessionConfig: URLSessionConfiguration) {
2146
self.init(urlSession: URLSession(configuration: urlSessionConfig))
2247
}
2348

49+
/// Creates a configuration with specific timeout and caching settings.
50+
///
51+
/// This is the most commonly used initializer, providing fine-grained control
52+
/// over the key parameters that affect connectivity testing performance.
53+
///
54+
/// - Parameters:
55+
/// - timeout: Request timeout in seconds. Defaults to 3 seconds for quick results.
56+
/// Use `nil` to apply system default timeouts.
57+
/// - cachePolicy: Caching strategy for requests. Defaults to `.ignoreCache` for
58+
/// accurate connectivity testing.
59+
/// - allowsCellularAccess: Whether to allow requests over cellular connections.
60+
/// Defaults to `true`.
2461
public init(timeout: TimeInterval? = 3,
2562
cachePolicy: ConnectivityConfiguration.CachePolicy = .ignoreCache,
2663
allowsCellularAccess: Bool = true)
@@ -32,42 +69,87 @@ public extension NetworkConnectivityKit {
3269
self.init(urlSessionConfig: config)
3370
}
3471

35-
/// Default configuration for URLSession
36-
/// Using 3 seconds timeout and ignore cache
72+
/// Default configuration optimized for connectivity testing.
73+
///
74+
/// This configuration uses:
75+
/// - 3-second timeout for quick results
76+
/// - Cache ignored to ensure fresh connectivity tests
77+
/// - Cellular access allowed for comprehensive testing
3778
public static let `default` = ConnectivityConfiguration()
3879
}
3980
}
4081

4182
// MARK: - CachePolicy
4283

4384
public extension NetworkConnectivityKit.ConnectivityConfiguration {
85+
/// Caching policies for connectivity testing requests.
86+
///
87+
/// Different caching strategies affect how fresh the connectivity test results are.
88+
/// For most connectivity testing scenarios, ignoring cache provides the most
89+
/// accurate real-time connectivity status.
4490
enum CachePolicy {
91+
/// Ignores all cached responses and always makes fresh network requests.
92+
///
93+
/// This is the recommended policy for connectivity testing as it ensures
94+
/// you're testing actual network connectivity rather than cached responses.
4595
case ignoreCache
96+
97+
/// Uses a custom caching policy with optional URLCache.
98+
///
99+
/// - Parameters:
100+
/// - policy: The URLRequest cache policy to use
101+
/// - urlCache: Optional custom URLCache instance, or `nil` to use default
46102
case useCache(policy: URLRequest.CachePolicy, urlCache: URLCache?)
47103
}
48104
}
49105

50106
// MARK: - Method chaining
51107

52108
public extension NetworkConnectivityKit.ConnectivityConfiguration {
109+
/// Returns a new configuration with the specified timeout.
110+
///
111+
/// This method follows a fluent interface pattern, allowing you to chain
112+
/// configuration modifications.
113+
///
114+
/// - Parameter timeout: The new timeout value in seconds, or `nil` for system defaults
115+
/// - Returns: A new configuration instance with the updated timeout
116+
///
117+
/// ## Example
118+
/// ```swift
119+
/// let config = ConnectivityConfiguration.default
120+
/// .timeout(5.0)
121+
/// .ignoreCache()
122+
/// ```
53123
func timeout(_ timeout: TimeInterval?) -> Self {
54124
let urlSessionConfig = urlSession.configuration
55125
urlSessionConfig.setTimeout(timeout)
56126
return .init(urlSessionConfig: urlSessionConfig)
57127
}
58128

129+
/// Returns a new configuration with the specified cache policy.
130+
///
131+
/// - Parameter cachePolicy: The cache policy to use for requests
132+
/// - Returns: A new configuration instance with the updated cache policy
59133
func cachePolicy(_ cachePolicy: NetworkConnectivityKit.ConnectivityConfiguration.CachePolicy) -> Self {
60134
let urlSessionConfig = urlSession.configuration
61135
urlSessionConfig.setCachePolicy(cachePolicy)
62136
return .init(urlSessionConfig: urlSessionConfig)
63137
}
64138

139+
/// Returns a new configuration that ignores cache.
140+
///
141+
/// This is a convenience method equivalent to `.cachePolicy(.ignoreCache)`.
142+
///
143+
/// - Returns: A new configuration instance that ignores cache
65144
func ignoreCache() -> Self {
66145
cachePolicy(.ignoreCache)
67146
}
68147
}
69148

70149
private extension URLSessionConfiguration {
150+
/// Sets timeout intervals for requests and resources.
151+
///
152+
/// - Parameter timeout: The timeout interval in seconds, or `nil` for defaults
71153
func setTimeout(_ timeout: TimeInterval?) {
72154
if let timeout {
73155
timeoutIntervalForRequest = timeout
@@ -78,26 +160,38 @@ private extension URLSessionConfiguration {
78160
}
79161
}
80162

163+
/// Configures the caching policy for the session.
164+
///
165+
/// - Parameter policy: The cache policy to apply
81166
func setCachePolicy(_ policy: NetworkConnectivityKit.ConnectivityConfiguration.CachePolicy) {
82167
switch policy {
83-
case .ignoreCache:
84-
requestCachePolicy = .reloadIgnoringCacheData
85-
urlCache = nil
86-
case .useCache(let policy, let urlCache):
87-
requestCachePolicy = policy
88-
self.urlCache = urlCache
168+
case .ignoreCache:
169+
requestCachePolicy = .reloadIgnoringCacheData
170+
urlCache = nil
171+
case let .useCache(policy, urlCache):
172+
requestCachePolicy = policy
173+
self.urlCache = urlCache
89174
}
90175
}
91176

177+
/// Sets whether cellular access is allowed for requests.
178+
///
179+
/// - Parameter allowsCellularAccess: Whether to allow cellular connections
92180
func setAllowsCellularAccess(_ allowsCellularAccess: Bool) {
93181
self.allowsCellularAccess = allowsCellularAccess
94182
}
95183
}
96184

97185
private extension NetworkConnectivityKit {
98-
/// Default timeout interval of URLSession, Apple doc:
186+
/// Default timeout interval for URLSession requests.
187+
///
188+
/// Based on Apple's documentation for NSURLSessionConfiguration.timeoutIntervalForRequest:
99189
/// https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408259-timeoutintervalforrequest
100-
/// https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408153-timeoutintervalforresource
101190
static let defaultTimeoutIntervalForRequest: TimeInterval = 60.0
191+
192+
/// Default timeout interval for URLSession resources.
193+
///
194+
/// Based on Apple's documentation for NSURLSessionConfiguration.timeoutIntervalForResource:
195+
/// https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408153-timeoutintervalforresource
102196
static let defaultTimeoutIntervalForResource: TimeInterval = 7 * 24 * 60 * 60.0
103197
}

Sources/NetworkConnectivityKit/ConnectivityMethod.swift

Lines changed: 150 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,83 @@ import Foundation
1010
// MARK: - ConnectivityMethod
1111

1212
public extension NetworkConnectivityKit {
13+
/// Represents a method for testing network connectivity to a specific endpoint.
14+
///
15+
/// A connectivity method encapsulates:
16+
/// - The target URL request
17+
/// - Validation logic for determining success
18+
/// - Configuration settings for the network request
19+
///
20+
/// ## Example
21+
/// ```swift
22+
/// // Create a custom connectivity method
23+
/// let method = ConnectivityMethod(
24+
/// url: URL(string: "https://example.com/ping")!,
25+
/// validation: .generate200Validation
26+
/// )
27+
/// ```
1328
struct ConnectivityMethod: Sendable {
29+
/// The URL request to be performed for connectivity testing.
1430
public let urlRequest: URLRequest
31+
32+
/// The validation logic used to determine if the response indicates successful connectivity.
1533
public let validation: ConnectivityValidation
34+
35+
/// The configuration settings for the underlying URLSession.
1636
public let configuration: ConnectivityConfiguration
1737

38+
/// Creates a connectivity method with a custom URL request.
39+
///
40+
/// - Parameters:
41+
/// - urlRequest: The URL request to perform
42+
/// - validation: The validation logic for the response
43+
/// - configuration: The URLSession configuration (defaults to `.default`)
1844
public init(urlRequest: URLRequest, validation: ConnectivityValidation, configuration: ConnectivityConfiguration = .default) {
1945
self.urlRequest = urlRequest
2046
self.validation = validation
2147
self.configuration = configuration
2248
}
2349

50+
/// Creates a connectivity method with a URL.
51+
///
52+
/// - Parameters:
53+
/// - url: The target URL for connectivity testing
54+
/// - validation: The validation logic for the response
55+
/// - configuration: The URLSession configuration (defaults to `.default`)
2456
public init(url: URL, validation: ConnectivityValidation, configuration: ConnectivityConfiguration = .default) {
2557
self.init(urlRequest: URLRequest(url: url, configuration: configuration), validation: validation, configuration: configuration)
2658
}
2759

60+
/// Creates a connectivity method with a static URL string.
61+
///
62+
/// This initializer is designed for compile-time URL strings that are guaranteed to be valid.
63+
/// It provides better safety and eliminates the need for optional handling when working with
64+
/// hardcoded URLs like built-in connectivity endpoints.
65+
///
66+
/// - Parameters:
67+
/// - staticURLString: The static URL string for connectivity testing (must be valid at compile time)
68+
/// - validation: The validation logic for the response
69+
/// - configuration: The URLSession configuration (defaults to `.default`)
70+
///
71+
/// ## Example
72+
/// ```swift
73+
/// let method = ConnectivityMethod(
74+
/// staticURLString: "http://www.gstatic.com/generate_204",
75+
/// validation: .generate204Validation
76+
/// )
77+
/// ```
78+
public init(staticURLString: StaticString, validation: ConnectivityValidation, configuration: ConnectivityConfiguration = .default) {
79+
let url = URL(staticString: staticURLString)
80+
self.init(url: url, validation: validation, configuration: configuration)
81+
}
82+
83+
/// Creates a connectivity method with a URL string.
84+
///
85+
/// - Parameters:
86+
/// - urlString: The target URL string for connectivity testing
87+
/// - validation: The validation logic for the response
88+
/// - configuration: The URLSession configuration (defaults to `.default`)
89+
/// - Returns: A new connectivity method, or `nil` if the URL string is invalid
2890
public init?(urlString: String, validation: ConnectivityValidation, configuration: ConnectivityConfiguration = .default) {
2991
guard let url = URL(string: urlString) else {
3092
return nil
@@ -39,24 +101,79 @@ public extension NetworkConnectivityKit {
39101
// refer: https://en.wikipedia.org/wiki/Captive_portal
40102

41103
public extension NetworkConnectivityKit.ConnectivityMethod {
42-
static let appleCaptive = Self(urlString: "http://captive.apple.com", validation: .generate200Validation)
43-
44-
static let appleLibrary = Self(urlString: "http://www.apple.com/library/test/success.html", validation: .generate200Validation)
45-
46-
static let googleGstatic = Self(urlString: "http://www.gstatic.com/generate_204", validation: .generate204Validation)
47-
48-
static let cloudflare = Self(urlString: "http://cp.cloudflare.com/generate_204", validation: .generate204Validation)
49-
50-
static let microsoft = Self(urlString: "http://www.msftconnecttest.com/connecttest.txt", validation: .generate200Validation)
51-
52-
static let vivoWifi = Self(urlString: "http://wifi.vivo.com.cn/generate_204", validation: .generate204Validation)
53-
54-
static let miuiConnect = Self(urlString: "http://connect.rom.miui.com/generate_204", validation: .generate204Validation)
104+
/// Apple's captive portal detection endpoint.
105+
///
106+
/// This endpoint is used by Apple devices to detect captive portals and network connectivity.
107+
/// It expects a 200 status code with specific content for successful connectivity.
108+
///
109+
/// **URL**: `http://captive.apple.com`
110+
/// **Expected Response**: HTTP 200 with "Success" content
111+
static let appleCaptive = Self(staticURLString: "http://captive.apple.com", validation: .generate200Validation)
112+
113+
/// Apple's library test endpoint for connectivity verification.
114+
///
115+
/// This is an alternative Apple endpoint that provides a reliable connectivity test
116+
/// with a simple success page response.
117+
///
118+
/// **URL**: `http://www.apple.com/library/test/success.html`
119+
/// **Expected Response**: HTTP 200 status code
120+
static let appleLibrary = Self(staticURLString: "http://www.apple.com/library/test/success.html", validation: .generate200Validation)
121+
122+
/// Google's lightweight connectivity check endpoint.
123+
///
124+
/// This endpoint returns a 204 (No Content) status code for successful connectivity
125+
/// and is widely used for network connectivity testing due to its minimal response size.
126+
///
127+
/// **URL**: `http://www.gstatic.com/generate_204`
128+
/// **Expected Response**: HTTP 204 (No Content)
129+
static let googleGstatic = Self(staticURLString: "http://www.gstatic.com/generate_204", validation: .generate204Validation)
130+
131+
/// Cloudflare's connectivity check endpoint.
132+
///
133+
/// Cloudflare provides this endpoint specifically for captive portal detection
134+
/// and connectivity verification with a 204 response.
135+
///
136+
/// **URL**: `http://cp.cloudflare.com/generate_204`
137+
/// **Expected Response**: HTTP 204 (No Content)
138+
static let cloudflare = Self(staticURLString: "http://cp.cloudflare.com/generate_204", validation: .generate204Validation)
139+
140+
/// Microsoft's connectivity test endpoint.
141+
///
142+
/// This endpoint is used by Microsoft systems for network connectivity verification
143+
/// and returns a simple text response.
144+
///
145+
/// **URL**: `http://www.msftconnecttest.com/connecttest.txt`
146+
/// **Expected Response**: HTTP 200 status code
147+
static let microsoft = Self(staticURLString: "http://www.msftconnecttest.com/connecttest.txt", validation: .generate200Validation)
148+
149+
/// Vivo WiFi connectivity check endpoint.
150+
///
151+
/// This endpoint is commonly used in networks with Vivo devices and provides
152+
/// reliable connectivity testing in those environments.
153+
///
154+
/// **URL**: `http://wifi.vivo.com.cn/generate_204`
155+
/// **Expected Response**: HTTP 204 (No Content)
156+
static let vivoWifi = Self(staticURLString: "http://wifi.vivo.com.cn/generate_204", validation: .generate204Validation)
157+
158+
/// MIUI (Xiaomi) connectivity check endpoint.
159+
///
160+
/// This endpoint is used by MIUI systems for network connectivity verification
161+
/// and captive portal detection.
162+
///
163+
/// **URL**: `http://connect.rom.miui.com/generate_204`
164+
/// **Expected Response**: HTTP 204 (No Content)
165+
static let miuiConnect = Self(staticURLString: "http://connect.rom.miui.com/generate_204", validation: .generate204Validation)
55166
}
56167

57168
// MARK: - Perform Request
58169

59170
extension NetworkConnectivityKit.ConnectivityMethod {
171+
/// Performs the connectivity check request and validates the response.
172+
///
173+
/// This method executes the network request using the configured URLSession
174+
/// and applies the validation logic to determine connectivity success.
175+
///
176+
/// - Returns: `true` if the request succeeds and passes validation, `false` otherwise
60177
func performRequest() async -> Bool {
61178
do {
62179
let response = try await configuration.urlSession.data(for: urlRequest)
@@ -82,6 +199,8 @@ extension NetworkConnectivityKit.ConnectivityMethod: Hashable, Equatable {
82199
}
83200
}
84201

202+
// MARK: - URLRequest Extension
203+
85204
private extension URLRequest {
86205
init(url: URL, configuration: NetworkConnectivityKit.ConnectivityConfiguration) {
87206
let configuration = configuration.urlSession.configuration
@@ -92,3 +211,21 @@ private extension URLRequest {
92211
self = request
93212
}
94213
}
214+
215+
// MARK: - URL Extension for StaticString
216+
217+
extension URL {
218+
/// Creates a URL from a static string, providing compile-time safety for hardcoded URLs.
219+
///
220+
/// This initializer is designed for cases where the URL string is known at compile time
221+
/// and should always be valid. If the static string cannot be converted to a valid URL,
222+
/// the application will terminate with a fatal error, helping catch invalid URLs early.
223+
///
224+
/// - Parameter staticString: A static string containing a valid URL
225+
init(staticString: StaticString) {
226+
guard let url = Self(string: "\(staticString)") else {
227+
fatalError("Invalid static URL string: \(staticString)")
228+
}
229+
self = url
230+
}
231+
}

0 commit comments

Comments
 (0)