Skip to content

Commit

Permalink
Persistent storage (#359)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenny-statsig authored Sep 18, 2024
1 parent 896d795 commit 1af76f0
Show file tree
Hide file tree
Showing 16 changed files with 764 additions and 126 deletions.
12 changes: 10 additions & 2 deletions src/main/kotlin/com/statsig/sdk/ClientInitializeFormatter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ internal data class ClientConfig(

internal class ClientInitializeFormatter(
private val specStore: SpecStore,
private val evalFun: (ctx: EvaluationContext, config: APIConfig?) -> Unit,
private val evalFun: (ctx: EvaluationContext, config: APIConfig) -> Unit,
private val context: EvaluationContext,
) {
private val user: StatsigUser = context.user
Expand Down Expand Up @@ -172,8 +172,8 @@ internal class ClientInitializeFormatter(
if (delegate != null && delegate != "") {
val delegateSpec = specStore.getConfig(delegate)
var delegateContext = context.asNewEvaluation()
evalFun(delegateContext, delegateSpec)
if (delegateSpec != null) {
evalFun(delegateContext, delegateSpec)
result.allocatedExperimentName = hashName(delegate)
result.isUserInExperiment = delegateContext.evaluation.isExperimentGroup
result.isExperimentActive = delegateSpec.isActive
Expand All @@ -182,6 +182,14 @@ internal class ClientInitializeFormatter(
if (delegateContext.evaluation.groupName != null && delegateContext.evaluation.groupName != "") {
result.group_name = delegateContext.evaluation.groupName
}
} else {
delegateContext.evaluation = ConfigEvaluation(
evaluationDetails = EvaluationDetails(
this.specStore.getLastUpdateTime(),
this.specStore.getInitTime(),
EvaluationReason.UNRECOGNIZED
)
)
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/main/kotlin/com/statsig/sdk/ConfigEvaluation.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.statsig.sdk

import com.statsig.sdk.persistent_storage.StickyValues

class ConfigEvaluation(
var booleanValue: Boolean = false,
var jsonValue: Any? = null,
var ruleID: String = Const.EMPTY_STR,
var groupName: String? = null,
var secondaryExposures: ArrayList<Map<String, String>> = arrayListOf(),
var undelegatedSecondaryExposures: ArrayList<Map<String, String>> = arrayListOf(),
var explicitParameters: Array<String>? = null,
var configDelegate: String? = null,
var evaluationDetails: EvaluationDetails? = null,
var isExperimentGroup: Boolean = false,
) {
internal var isDelegate: Boolean = false

fun addSecondaryExposure(exposure: Map<String, String>) {
secondaryExposures.add(exposure)
if (!isDelegate) {
undelegatedSecondaryExposures.add(exposure)
}
}

// Used to save to PersistentStorage
fun toStickyValues(): StickyValues {
return StickyValues(
value = this.booleanValue,
jsonValue = this.jsonValue,
ruleID = this.ruleID,
groupName = this.groupName,
secondaryExposures = this.secondaryExposures,
explicitParameters = this.explicitParameters,
configDelegate = this.configDelegate,
undelegatedSecondaryExposures = this.undelegatedSecondaryExposures,
time = this.evaluationDetails?.configSyncTime ?: Utils.getTimeInMillis(),
)
}

companion object {
fun fromStickyValues(stickyValues: StickyValues, initTime: Long): ConfigEvaluation {
val evalDetail = EvaluationDetails(
stickyValues.time,
initTime,
EvaluationReason.PERSISTED
)
return ConfigEvaluation(
jsonValue = stickyValues.jsonValue,
booleanValue = stickyValues.value,
ruleID = stickyValues.ruleID,
groupName = stickyValues.groupName,
secondaryExposures = stickyValues.secondaryExposures,
undelegatedSecondaryExposures = stickyValues.undelegatedSecondaryExposures,
explicitParameters = stickyValues.explicitParameters,
configDelegate = stickyValues.configDelegate,
isExperimentGroup = true,
evaluationDetails = evalDetail,
)
}
}
}
6 changes: 5 additions & 1 deletion src/main/kotlin/com/statsig/sdk/EvaluationContext.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.statsig.sdk

import com.statsig.sdk.persistent_storage.UserPersistedValues

internal class EvaluationContext(
var user: StatsigUser,
var evaluation: ConfigEvaluation = ConfigEvaluation(),
var clientSDKKey: String? = null,
var hash: HashAlgo = HashAlgo.SHA256,
var isNested: Boolean = false,
var userPersistedValues: UserPersistedValues? = null,
) {
// Overload without default parameters required for Java
constructor(user: StatsigUser) : this(user, ConfigEvaluation())
Expand All @@ -16,6 +19,7 @@ internal class EvaluationContext(
clientSDKKey = ctx.clientSDKKey,
hash = ctx.hash,
isNested = ctx.isNested,
userPersistedValues = ctx.userPersistedValues
)

internal fun asDelegate(): EvaluationContext {
Expand All @@ -26,7 +30,7 @@ internal class EvaluationContext(

internal fun asNested(): EvaluationContext {
var context = EvaluationContext(this)
context.isNested = isNested
context.isNested = true
return context
}

Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/com/statsig/sdk/EvaluationDetails.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ enum class EvaluationReason(val reason: String) {
DATA_ADAPTER("DataAdapter"),
UNSUPPORTED("Unsupported"),
DEFAULT("Default"),
PERSISTED("Persisted"),
}
Loading

0 comments on commit 1af76f0

Please sign in to comment.