5
5
// SPDX-License-Identifier: Apache-2.0
6
6
//
7
7
8
-
8
+ import Foundation
9
9
import Network
10
10
import Combine
11
11
@@ -19,6 +19,7 @@ public final class AmplifyNetworkMonitor {
19
19
}
20
20
21
21
private let monitor : NWPathMonitor
22
+ private var pingMonitor : AnyCancellable ?
22
23
23
24
private let subject = PassthroughSubject < State , Never > ( )
24
25
@@ -38,6 +39,8 @@ public final class AmplifyNetworkMonitor {
38
39
label: " com.amazonaws.amplify.ios.network.websocket.monitor " ,
39
40
qos: . userInitiated
40
41
) )
42
+
43
+ pingMonitor = startPingMonitor ( )
41
44
}
42
45
43
46
public func updateState( _ nextState: State ) {
@@ -46,6 +49,35 @@ public final class AmplifyNetworkMonitor {
46
49
47
50
deinit {
48
51
subject. send ( completion: . finished)
52
+ pingMonitor? . cancel ( )
49
53
monitor. cancel ( )
50
54
}
55
+
56
+ private func pingCloudflare( ) -> Future < State , Never > {
57
+ Future { promise in
58
+ let oneDNS = URL ( string: " https://1.1.1.1 " ) !
59
+ var request = URLRequest ( url: oneDNS)
60
+ request. httpMethod = " HEAD "
61
+ request. timeoutInterval = . seconds( 2 )
62
+
63
+ URLSession . shared. dataTask ( with: request) { _, response, error in
64
+ if let error {
65
+ promise ( . success( State . offline) )
66
+ } else if let httpResponse = response as? HTTPURLResponse {
67
+ promise ( . success( httpResponse. statusCode < 400 ? State . online : State . offline) )
68
+ }
69
+ } . resume ( )
70
+ }
71
+ }
72
+
73
+ private func startPingMonitor( ) -> AnyCancellable {
74
+ return Timer . TimerPublisher ( interval: . seconds( 2 ) , runLoop: . main, mode: . common)
75
+ . autoconnect ( )
76
+ . receive ( on: DispatchQueue . global ( qos: . default) )
77
+ . compactMap { [ weak self] _ in self ? . pingCloudflare ( ) }
78
+ . flatMap { $0 }
79
+ . sink { [ weak self] state in
80
+ self ? . updateState ( state)
81
+ }
82
+ }
51
83
}
0 commit comments