From f04b0aefe4b1efc5bebca90c5140fe4deff485f1 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 21 Jun 2024 17:24:17 -0700 Subject: [PATCH] fix(datastore): add networking monitor by regular ping --- .../WebSocket/AmplifyNetworkMonitor.swift | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift b/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift index 23eb1ec4e2..8d39e620bb 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/AmplifyNetworkMonitor.swift @@ -5,7 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 // - +import Foundation import Network import Combine @@ -19,6 +19,7 @@ public final class AmplifyNetworkMonitor { } private let monitor: NWPathMonitor + private var pingMonitor: AnyCancellable? private let subject = PassthroughSubject() @@ -38,6 +39,8 @@ public final class AmplifyNetworkMonitor { label: "com.amazonaws.amplify.ios.network.websocket.monitor", qos: .userInitiated )) + + pingMonitor = startPingMonitor() } public func updateState(_ nextState: State) { @@ -46,6 +49,35 @@ public final class AmplifyNetworkMonitor { deinit { subject.send(completion: .finished) + pingMonitor?.cancel() monitor.cancel() } + + private func pingCloudflare() -> Future { + Future { promise in + let oneDNS = URL(string: "https://one.one.one.one")! + var request = URLRequest(url: oneDNS) + request.httpMethod = "HEAD" + request.timeoutInterval = .seconds(3) + + URLSession.shared.dataTask(with: request) { _, response, error in + if let error { + promise(.success(State.offline)) + } else if let httpResponse = response as? HTTPURLResponse { + promise(.success(httpResponse.statusCode == 200 ? State.online : State.offline)) + } + }.resume() + } + } + + private func startPingMonitor() -> AnyCancellable { + return Timer.TimerPublisher(interval: .seconds(3), runLoop: .main, mode: .common) + .autoconnect() + .receive(on: DispatchQueue.global(qos: .default)) + .compactMap { [weak self] _ in self?.pingCloudflare() } + .flatMap { $0 } + .sink { [weak self] state in + self?.updateState(state) + } + } }