Skip to content

Commit 5ac21cf

Browse files
Refresh core feature flags with periodic update manager
1 parent 7c5839b commit 5ac21cf

File tree

2 files changed

+81
-3
lines changed

2 files changed

+81
-3
lines changed

app/src/main/java/com/protonvpn/android/ProtonApplication.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import com.evernote.android.state.StateSaver;
3131
import com.protonvpn.android.api.DohEnabled;
32+
import com.protonvpn.android.appconfig.CoreFeatureFlagUpdater;
3233
import com.protonvpn.android.appconfig.periodicupdates.PeriodicUpdateManager;
3334
import com.protonvpn.android.auth.usecase.CloseSessionOnForceLogout;
3435
import com.protonvpn.android.components.RestartHandler;
@@ -79,7 +80,6 @@
7980
import kotlinx.coroutines.ExecutorsKt;
8081
import me.proton.core.accountmanager.data.AccountStateHandler;
8182
import me.proton.core.eventmanager.data.CoreEventManagerStarter;
82-
import me.proton.core.featureflag.data.FeatureFlagRefreshStarter;
8383
import me.proton.core.humanverification.presentation.HumanVerificationStateHandler;
8484
import me.proton.core.util.kotlin.CoreLogger;
8585

@@ -100,9 +100,9 @@ interface DependencyEntryPoints {
100100
CertificateRepository getCertificateRepository();
101101
CloseSessionOnForceLogout getCloseSessionOnForceLogout();
102102
CoreEventManagerStarter getCoreEventManagerStarter();
103+
CoreFeatureFlagUpdater getCoreFeatureFlagRefresher();
103104
CurrentStateLogger getCurrentStateLogger();
104105
DohEnabled.Provider getDohEnabledProvider();
105-
FeatureFlagRefreshStarter getFeatureFlagRefreshStarter();
106106
HumanVerificationStateHandler getHumanVerificationStateHandler();
107107
LogcatLogCapture getLogcatLogCapture();
108108
MaintenanceTracker getMaintenanceTracker();
@@ -167,8 +167,8 @@ public void initDependencies() {
167167
dependencies.getAccountStateHandler().start();
168168
dependencies.getCertificateRepository();
169169
dependencies.getCloseSessionOnForceLogout();
170+
dependencies.getCoreFeatureFlagRefresher().start();
170171
dependencies.getDohEnabledProvider();
171-
dependencies.getFeatureFlagRefreshStarter().start();
172172
dependencies.getHumanVerificationStateHandler().observe();
173173
dependencies.getMaintenanceTracker();
174174
dependencies.getNotificationPermissionManager();
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2023 Proton AG
3+
*
4+
* This file is part of ProtonVPN.
5+
*
6+
* ProtonVPN is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* ProtonVPN is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
package com.protonvpn.android.appconfig
20+
21+
import com.protonvpn.android.appconfig.periodicupdates.IsInForeground
22+
import com.protonvpn.android.appconfig.periodicupdates.PeriodicActionResult
23+
import com.protonvpn.android.appconfig.periodicupdates.PeriodicUpdateManager
24+
import com.protonvpn.android.appconfig.periodicupdates.PeriodicUpdateSpec
25+
import com.protonvpn.android.appconfig.periodicupdates.registerAction
26+
import com.protonvpn.android.auth.usecase.CurrentUser
27+
import kotlinx.coroutines.CoroutineScope
28+
import kotlinx.coroutines.flow.Flow
29+
import kotlinx.coroutines.flow.distinctUntilChangedBy
30+
import kotlinx.coroutines.flow.launchIn
31+
import kotlinx.coroutines.flow.map
32+
import kotlinx.coroutines.flow.onEach
33+
import me.proton.core.domain.entity.UserId
34+
import me.proton.core.featureflag.domain.ExperimentalProtonFeatureFlag
35+
import me.proton.core.featureflag.domain.FeatureFlagManager
36+
import java.util.concurrent.TimeUnit
37+
import javax.inject.Inject
38+
import javax.inject.Singleton
39+
40+
@OptIn(ExperimentalProtonFeatureFlag::class)
41+
@Singleton
42+
class CoreFeatureFlagUpdater @Inject constructor(
43+
private val scope: CoroutineScope,
44+
private val currentUser: CurrentUser,
45+
private val featureFlagManager: FeatureFlagManager,
46+
private val periodicUpdateManager: PeriodicUpdateManager,
47+
@IsInForeground inForeground: Flow<Boolean>,
48+
) {
49+
private val coreFeatureFlagsUpdate = periodicUpdateManager.registerAction(
50+
"core_feature_flags",
51+
::refreshInternal,
52+
{ currentUser.user()?.userId },
53+
PeriodicUpdateSpec(UPDATE_DELAY_FOREGROUND, setOf(inForeground)),
54+
PeriodicUpdateSpec(UPDATE_DELAY_BACKGROUND, setOf()),
55+
)
56+
57+
fun start() {
58+
// No persistency so far for feature flags, so we need to always force refresh on start.
59+
// We also need to refresh each time user changes
60+
currentUser.vpnUserFlow
61+
.distinctUntilChangedBy { Pair(it?.userId, it?.planName) }
62+
.map { it?.userId }
63+
.onEach {
64+
periodicUpdateManager.executeNow(coreFeatureFlagsUpdate, it)
65+
}.launchIn(scope)
66+
}
67+
68+
private fun refreshInternal(userId: UserId?) : PeriodicActionResult<Unit> {
69+
featureFlagManager.refreshAll(userId)
70+
// No way to check if the refresh succeeded, worst case it'll try again later
71+
return PeriodicActionResult(Unit, isSuccess = true)
72+
}
73+
74+
companion object {
75+
private val UPDATE_DELAY_FOREGROUND = TimeUnit.HOURS.toMillis(2)
76+
private val UPDATE_DELAY_BACKGROUND = TimeUnit.HOURS.toMillis(12)
77+
}
78+
}

0 commit comments

Comments
 (0)