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