Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit

Permalink
Introduce a kill switch for the new feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jaceklyp committed Dec 18, 2024
1 parent e5af352 commit 8cca2ce
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 18 deletions.
28 changes: 16 additions & 12 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import Core

enum AppBehavior: String {

case existing
case stateMachine
case old
case new

}

protocol DDGAppDelegate {
protocol DDGApp {

var privacyProDataReporter: PrivacyProDataReporting? { get }

Expand All @@ -51,18 +51,16 @@ protocol DDGAppDelegate {
realDelegate.privacyProDataReporter
}

func forceOldAppDelegate() {
BoolFileMarker(name: .forceOldAppDelegate)?.mark()
}

private let appBehavior: AppBehavior = {
guard !ProcessInfo().arguments.contains("testing") else { return .existing }
if let appBehavior = AppDependencyProvider.shared.appSettings.appBehavior {
return appBehavior
}
let appBehavior: AppBehavior = Double.random(in: 0..<1) < 0.2 ? .stateMachine : .existing // 20% of users will run through new flow
AppDependencyProvider.shared.appSettings.appBehavior = appBehavior
return appBehavior
BoolFileMarker(name: .forceOldAppDelegate)?.isPresent == true ? .old : .new
}()

private lazy var realDelegate: UIApplicationDelegate & DDGAppDelegate = {
if appBehavior == .existing {
private lazy var realDelegate: UIApplicationDelegate & DDGApp = {
if appBehavior == .old {
return OldAppDelegate(with: self)
} else {
return NewAppDelegate()
Expand Down Expand Up @@ -161,3 +159,9 @@ extension Error {
}

}

private extension BoolFileMarker.Name {

static let forceOldAppDelegate = BoolFileMarker.Name(rawValue: "force-old-app-delegate")

}
1 change: 1 addition & 0 deletions DuckDuckGo/AppLifecycle/AppStates/Active.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct Active: AppState {
private func activateApp(isTesting: Bool = false) {
guard !isTesting else { return } // Leaving this as is for now to ensure this code is never executed, regardless of where it's called from.
// In the future, we may consider creating separate states specifically for testing purposes.

StorageInconsistencyMonitor().didBecomeActive(isProtectedDataAvailable: application.isProtectedDataAvailable)
appDependencies.syncService.initializeIfNeeded()
appDependencies.syncDataProviders.setUpDatabaseCleanersIfNeeded(syncService: appDependencies.syncService)
Expand Down
10 changes: 10 additions & 0 deletions DuckDuckGo/AppLifecycle/AppStates/Background.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Foundation
import Combine
import DDGSync
import UIKit
import Core

struct Background: AppState {

Expand Down Expand Up @@ -70,6 +71,15 @@ struct Background: AppState {
privacyProDataReporter.saveApplicationLastSessionEnded()

resetAppStartTime()

// Kill switch for the new app delegate:
// If the .forceOldAppDelegate flag is set in the config, we mark a file as present.
// This switches the app to the old mode and silently crashes it in the background.
// When reopened, the app will reliably run the old flow.
if ContentBlocking.shared.privacyConfigurationManager.privacyConfig.isEnabled(featureKey: .forceOldAppDelegate) {

Check failure on line 79 in DuckDuckGo/AppLifecycle/AppStates/Background.swift

View workflow job for this annotation

GitHub Actions / Make Release Build

type 'PrivacyFeature' has no member 'forceOldAppDelegate'

Check failure on line 79 in DuckDuckGo/AppLifecycle/AppStates/Background.swift

View workflow job for this annotation

GitHub Actions / Make Release Build

type 'PrivacyFeature' has no member 'forceOldAppDelegate'

Check failure on line 79 in DuckDuckGo/AppLifecycle/AppStates/Background.swift

View workflow job for this annotation

GitHub Actions / Unit Tests

type 'PrivacyFeature' has no member 'forceOldAppDelegate'
(UIApplication.shared.delegate as? AppDelegate)?.forceOldAppDelegate()
fatalError() // we silently crash in the background

Check failure on line 81 in DuckDuckGo/AppLifecycle/AppStates/Background.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

A fatalError call should have a message (fatal_error_message)
}
}

private mutating func suspendSync(syncService: DDGSync) {
Expand Down
8 changes: 5 additions & 3 deletions DuckDuckGo/NewAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@

import UIKit

final class NewAppDelegate: NSObject, UIApplicationDelegate, DDGAppDelegate {
final class NewAppDelegate: NSObject, UIApplicationDelegate, DDGApp {

private let appStateMachine: AppStateMachine = AppStateMachine()

var privacyProDataReporter: PrivacyProDataReporting? {
(appStateMachine.currentState as? Active)?.appDependencies.privacyProDataReporter // just for now, we have to get rid of this antipattern
(appStateMachine.currentState as? Active)?.appDependencies.privacyProDataReporter // just for now, we have to get rid of this anti pattern
}

func initialize() { } // init code will happen inside AppStateMachine/Init state .init()
Expand All @@ -35,7 +35,9 @@ final class NewAppDelegate: NSObject, UIApplicationDelegate, DDGAppDelegate {
}

func applicationDidBecomeActive(_ application: UIApplication) {
appStateMachine.handle(.activating)
if !ProcessInfo().arguments.contains("testing") {
appStateMachine.handle(.activating)
}
}

func applicationWillResignActive(_ application: UIApplication) {
Expand Down
4 changes: 2 additions & 2 deletions DuckDuckGo/OldAppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// AppDelegate.swift
// OldAppDelegate.swift
// DuckDuckGo
//
// Copyright © 2017 DuckDuckGo. All rights reserved.
Expand Down Expand Up @@ -42,7 +42,7 @@ import WebKit
import os.log

@MainActor
final class OldAppDelegate: NSObject, UIApplicationDelegate, DDGAppDelegate {
final class OldAppDelegate: NSObject, UIApplicationDelegate, DDGApp {

private var testing = false
var appIsLaunching = false
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGoTests/AppSettingsMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Foundation
@testable import DuckDuckGo

class AppSettingsMock: AppSettings {
var appBehavior: DuckDuckGo.AppBehavior? = .existing
var appBehavior: DuckDuckGo.AppBehavior? = .new

var defaultTextZoomLevel: DuckDuckGo.TextZoomLevel = .percent100

Expand Down

0 comments on commit 8cca2ce

Please sign in to comment.