Skip to content

Commit

Permalink
Update the status observer for snooze.
Browse files Browse the repository at this point in the history
  • Loading branch information
samsymons committed Jul 4, 2024
1 parent dab08b1 commit 5dad425
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 13 deletions.
19 changes: 16 additions & 3 deletions Sources/NetworkProtection/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
private let tunnelHealth: NetworkProtectionTunnelHealthStore
private let controllerErrorStore: NetworkProtectionTunnelErrorStore
private let knownFailureStore: NetworkProtectionKnownFailureStore
private let snoozeTimingStore: NetworkProtectionSnoozeTimingStore

// MARK: - Cancellables

Expand All @@ -374,6 +375,7 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
tunnelHealthStore: NetworkProtectionTunnelHealthStore,
controllerErrorStore: NetworkProtectionTunnelErrorStore,
knownFailureStore: NetworkProtectionKnownFailureStore = NetworkProtectionKnownFailureStore(),
snoozeTimingStore: NetworkProtectionSnoozeTimingStore,
keychainType: KeychainType,
tokenStore: NetworkProtectionTokenStore,
debugEvents: EventMapping<NetworkProtectionError>?,
Expand All @@ -392,6 +394,7 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
self.tunnelHealth = tunnelHealthStore
self.controllerErrorStore = controllerErrorStore
self.knownFailureStore = knownFailureStore
self.snoozeTimingStore = snoozeTimingStore
self.settings = settings
self.defaults = defaults
self.isSubscriptionEnabled = isSubscriptionEnabled
Expand Down Expand Up @@ -559,6 +562,8 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
open func handleConnectionStatusChange(old: ConnectionStatus, new: ConnectionStatus) {
os_log("⚫️ Connection Status Change: %{public}s -> %{public}s", log: .networkProtectionPixel, type: .debug, old.description, new.description)

// TODO: Handle snooze

switch (old, new) {
case (_, .connecting), (_, .reasserting):
providerEvents.fire(.reportConnectionAttempt(attempt: .connecting))
Expand Down Expand Up @@ -1601,10 +1606,9 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {

await stopMonitors()
self.connectionStatus = .snoozing
self.snoozeTimingStore.activeTiming = .init(startDate: Date(), duration: duration)
self.adapter.snooze { error in
if error == nil {
self.notificationsPresenter.showSnoozeBeganNotification()

let timer = DispatchSource.makeTimerSource(queue: self.timerQueue)
timer.schedule(deadline: .now() + duration, repeating: .never)
timer.setEventHandler {
Expand All @@ -1616,13 +1620,22 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
}

timer.resume()
} else {
self.snoozeTimingStore.reset()
}
}
}

private func cancelSnooze() async {
os_log("Ending snooze mode", log: .networkProtection)
self.notificationsPresenter.showSnoozeEndedNotification()

guard snoozeTimingStore.activeTiming != nil else {
assertionFailure("Tried to cancel snooze when it was not active")
return
}

notificationsPresenter.showSnoozeEndedNotification()
snoozeTimingStore.reset()
try? await startTunnel(onDemand: false)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class ConnectionStatusObserverThroughSession: ConnectionStatusObserver {

// MARK: - Notifications
private let notificationCenter: NotificationCenter
private let platformSnoozeTimingStore: NetworkProtectionSnoozeTimingStore
private let platformNotificationCenter: NotificationCenter
private let platformDidWakeNotification: Notification.Name
private var cancellables = Set<AnyCancellable>()
Expand All @@ -49,11 +50,13 @@ public class ConnectionStatusObserverThroughSession: ConnectionStatusObserver {

public init(tunnelSessionProvider: TunnelSessionProvider,
notificationCenter: NotificationCenter = .default,
platformSnoozeTimingStore: NetworkProtectionSnoozeTimingStore,
platformNotificationCenter: NotificationCenter,
platformDidWakeNotification: Notification.Name,
log: OSLog = .networkProtection) {

self.notificationCenter = notificationCenter
self.platformSnoozeTimingStore = platformSnoozeTimingStore
self.platformNotificationCenter = platformNotificationCenter
self.platformDidWakeNotification = platformDidWakeNotification
self.tunnelSessionProvider = tunnelSessionProvider
Expand All @@ -74,8 +77,12 @@ public class ConnectionStatusObserverThroughSession: ConnectionStatusObserver {
self?.handleStatusChangeNotification(notification)
}.store(in: &cancellables)

notificationCenter.publisher(for: .snoozeDidChange).sink { [weak self] notification in
self?.handleStatusRefreshNotification(notification)
}.store(in: &cancellables)

platformNotificationCenter.publisher(for: platformDidWakeNotification).sink { [weak self] notification in
self?.handleDidWake(notification)
self?.handleStatusRefreshNotification(notification)
}.store(in: &cancellables)
}

Expand All @@ -89,7 +96,7 @@ public class ConnectionStatusObserverThroughSession: ConnectionStatusObserver {

// MARK: - Handling Notifications

private func handleDidWake(_ notification: Notification) {
private func handleStatusRefreshNotification(_ notification: Notification) {
Task {
guard let session = await tunnelSessionProvider.activeSession() else {
return
Expand Down Expand Up @@ -128,8 +135,12 @@ public class ConnectionStatusObserverThroughSession: ConnectionStatusObserver {

switch internalStatus {
case .connected:
let connectedDate = connectedDate(from: session)
status = .connected(connectedDate: connectedDate)
if platformSnoozeTimingStore.activeTiming != nil {
status = .snoozing
} else {
let connectedDate = connectedDate(from: session)
status = .connected(connectedDate: connectedDate)
}
case .connecting:
status = .connecting
case .reasserting:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public protocol NetworkProtectionNotificationsPresenter {
/// Present a "expired subscription" notification to the user.
func showEntitlementNotification()

func showSnoozeBeganNotification()

func showSnoozeEndedNotification()

}
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ final public class NetworkProtectionNotificationsPresenterTogglableDecorator: Ne
}
}

public func showSnoozeBeganNotification() {
wrappeePresenter.showSnoozeBeganNotification()
}

public func showSnoozeEndedNotification() {
wrappeePresenter.showSnoozeEndedNotification()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// NetworkProtectionSnoozeTimingStore.swift
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import Common

final public class NetworkProtectionSnoozeTimingStore {

public struct SnoozeTiming: Codable, Equatable {
let startDate: Date
let duration: TimeInterval

var endDate: Date {
return startDate.addingTimeInterval(duration)
}
}

private static let activeSnoozeTimingKey = "com.duckduckgo.NetworkProtectionSnoozeTimingStore.activeTiming"

private let userDefaults: UserDefaults
private let notificationCenter: NotificationCenter

public init(userDefaults: UserDefaults = .standard, notificationCenter: NotificationCenter = .default) {
self.userDefaults = userDefaults
self.notificationCenter = notificationCenter
}

public var activeTiming: SnoozeTiming? {
get {
guard let data = userDefaults.data(forKey: Self.activeSnoozeTimingKey) else { return nil }
return try? JSONDecoder().decode(SnoozeTiming.self, from: data)
}

set {
if let newValue, let data = try? JSONEncoder().encode(newValue) {
userDefaults.set(data, forKey: Self.activeSnoozeTimingKey)
} else {
userDefaults.removeObject(forKey: Self.activeSnoozeTimingKey)
}

notificationCenter.post(name: .snoozeDidChange, object: nil)
}
}

public func reset() {
activeTiming = nil
}

}

extension NSNotification.Name {

static let snoozeDidChange: NSNotification.Name = Notification.Name(rawValue: "com.duckduckgo.browserServicesKit.vpn.snoozeDidChange")

}

0 comments on commit 5dad425

Please sign in to comment.