From a4cbb5f64a03fd2d6d8d680ce45e380afe2da7bd Mon Sep 17 00:00:00 2001 From: Peter Csajtai Date: Wed, 8 Nov 2023 16:19:22 +0100 Subject: [PATCH] Evaluator warning fixes --- .../kotlin/com/configcat/ConfigService.kt | 2 +- .../kotlin/com/configcat/Evaluator.kt | 116 ++++++++---------- src/commonMain/kotlin/com/configcat/Utils.kt | 5 - .../kotlin/com/configcat/model/Condition.kt | 10 +- .../com/configcat/model/ConditionAccessor.kt | 8 ++ .../kotlin/com/configcat/model/Config.kt | 30 ----- .../kotlin/com/configcat/model/Segment.kt | 2 +- .../com/configcat/model/TargetingRule.kt | 2 +- .../com/configcat/model/UserCondition.kt | 6 +- 9 files changed, 69 insertions(+), 112 deletions(-) create mode 100644 src/commonMain/kotlin/com/configcat/model/ConditionAccessor.kt diff --git a/src/commonMain/kotlin/com/configcat/ConfigService.kt b/src/commonMain/kotlin/com/configcat/ConfigService.kt index cb7eb506..ede42d41 100644 --- a/src/commonMain/kotlin/com/configcat/ConfigService.kt +++ b/src/commonMain/kotlin/com/configcat/ConfigService.kt @@ -24,7 +24,7 @@ internal data class SettingResult(val settings: Map?, val fetch } } -internal class ConfigService constructor( +internal class ConfigService( private val options: ConfigCatOptions, private val configFetcher: ConfigFetcher, private val logger: InternalLogger, diff --git a/src/commonMain/kotlin/com/configcat/Evaluator.kt b/src/commonMain/kotlin/com/configcat/Evaluator.kt index 783b0eb7..5d5a7e4d 100644 --- a/src/commonMain/kotlin/com/configcat/Evaluator.kt +++ b/src/commonMain/kotlin/com/configcat/Evaluator.kt @@ -116,7 +116,7 @@ internal class Evaluator(private val logger: InternalLogger) { var error: String? = null try { evaluateConditionsResult = evaluateConditions( - (rule.conditions ?: arrayOf()) as Array, + rule.conditionAccessors, rule, setting.configSalt, context.key, @@ -162,7 +162,7 @@ internal class Evaluator(private val logger: InternalLogger) { @Suppress("NestedBlockDepth", "CyclomaticComplexMethod", "LongMethod", "LongParameterList") private fun evaluateConditions( - conditions: Array, + conditions: List, targetingRule: TargetingRule?, configSalt: String, contextSalt: String, @@ -170,28 +170,27 @@ internal class Evaluator(private val logger: InternalLogger) { segments: Array, evaluateLogger: EvaluateLogger? ): Boolean { - // Conditions are ANDs so if One is not matching return false, if all matching return true - var firstConditionFlag = true var conditionsEvaluationResult = false var error: String? = null var newLine = false - for (i in conditions.indices) { - val rawCondition = conditions.get(i) - if (firstConditionFlag) { - firstConditionFlag = false - evaluateLogger?.newLine() - evaluateLogger?.append("- IF ") - evaluateLogger?.increaseIndentLevel() - } else { - evaluateLogger?.increaseIndentLevel() - evaluateLogger?.newLine() - evaluateLogger?.append("AND ") + for ((index, condition) in conditions.withIndex()) { + when (index) { + 0 -> { + evaluateLogger?.newLine() + evaluateLogger?.append("- IF ") + evaluateLogger?.increaseIndentLevel() + } + else -> { + evaluateLogger?.increaseIndentLevel() + evaluateLogger?.newLine() + evaluateLogger?.append("AND ") + } } - if (targetingRule == null) { + condition.userCondition?.let { userCondition -> try { conditionsEvaluationResult = evaluateUserCondition( - rawCondition as UserCondition, + userCondition, configSalt, context, contextSalt, @@ -202,50 +201,38 @@ internal class Evaluator(private val logger: InternalLogger) { conditionsEvaluationResult = false } newLine = conditions.size > 1 - } else { - val condition = rawCondition as Condition - if (condition.userCondition != null) { - try { - conditionsEvaluationResult = evaluateUserCondition( - condition.userCondition, - configSalt, - context, - context.key, - evaluateLogger - ) - } catch (evaluatorException: RolloutEvaluatorException) { - error = evaluatorException.message - conditionsEvaluationResult = false - } - newLine = conditions.size > 1 - } else if (condition.segmentCondition != null) { - try { - conditionsEvaluationResult = evaluateSegmentCondition( - condition.segmentCondition, - context, - configSalt, - segments, - evaluateLogger - ) - } catch (evaluatorException: RolloutEvaluatorException) { - error = evaluatorException.message - conditionsEvaluationResult = false - } - newLine = error == null || USER_OBJECT_IS_MISSING != error || conditions.size > 1 - } else if (condition.prerequisiteFlagCondition != null) { - try { - conditionsEvaluationResult = evaluatePrerequisiteFlagCondition( - condition.prerequisiteFlagCondition, - context, - evaluateLogger - ) - } catch (evaluatorException: RolloutEvaluatorException) { - error = evaluatorException.message - conditionsEvaluationResult = false - } - newLine = error == null || conditions.size > 1 + } + + condition.segmentCondition?.let { segmentCondition -> + try { + conditionsEvaluationResult = evaluateSegmentCondition( + segmentCondition, + context, + configSalt, + segments, + evaluateLogger + ) + } catch (evaluatorException: RolloutEvaluatorException) { + error = evaluatorException.message + conditionsEvaluationResult = false + } + newLine = error == null || USER_OBJECT_IS_MISSING != error || conditions.size > 1 + } + + condition.prerequisiteFlagCondition?.let { prerequisiteCondition -> + try { + conditionsEvaluationResult = evaluatePrerequisiteFlagCondition( + prerequisiteCondition, + context, + evaluateLogger + ) + } catch (evaluatorException: RolloutEvaluatorException) { + error = evaluatorException.message + conditionsEvaluationResult = false } + newLine = error == null || conditions.size > 1 } + if (targetingRule == null || conditions.size > 1) { evaluateLogger?.logConditionConsequence(conditionsEvaluationResult) } @@ -254,10 +241,10 @@ internal class Evaluator(private val logger: InternalLogger) { break } } - if (targetingRule != null) { + targetingRule?.let { evaluateLogger?.logTargetingRuleConsequence(targetingRule, error, conditionsEvaluationResult, newLine) } - if (error != null) { + error?.let { throw RolloutEvaluatorException(error) } return conditionsEvaluationResult @@ -296,7 +283,7 @@ internal class Evaluator(private val logger: InternalLogger) { @Suppress("SwallowedException") try { val segmentRulesResult = evaluateConditions( - segment.segmentRules as Array, + segment.conditionAccessors, null, configSalt, segmentName, @@ -332,10 +319,7 @@ internal class Evaluator(private val logger: InternalLogger) { require(!prerequisiteFlagKey.isNullOrEmpty() && prerequisiteFlagSetting != null) { "Prerequisite flag key is missing or invalid." } - var visitedKeys: ArrayList? = context.visitedKeys - if (visitedKeys == null) { - visitedKeys = ArrayList() - } + val visitedKeys: ArrayList = context.visitedKeys ?: ArrayList() visitedKeys.add(context.key) if (visitedKeys.contains(prerequisiteFlagKey)) { val dependencyCycle: String = diff --git a/src/commonMain/kotlin/com/configcat/Utils.kt b/src/commonMain/kotlin/com/configcat/Utils.kt index f663ad93..8a10486e 100644 --- a/src/commonMain/kotlin/com/configcat/Utils.kt +++ b/src/commonMain/kotlin/com/configcat/Utils.kt @@ -1,9 +1,7 @@ package com.configcat -import com.configcat.model.FlagValueSerializer import com.soywiz.klock.DateTime import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule internal interface Closeable { fun close() @@ -23,8 +21,5 @@ internal object Constants { val distantFuture = DateTime.now().add(10_000, 0.0) val json = Json { ignoreUnknownKeys = true - serializersModule = SerializersModule { - contextual(Any::class, FlagValueSerializer) - } } } diff --git a/src/commonMain/kotlin/com/configcat/model/Condition.kt b/src/commonMain/kotlin/com/configcat/model/Condition.kt index c3445b45..962fe03b 100644 --- a/src/commonMain/kotlin/com/configcat/model/Condition.kt +++ b/src/commonMain/kotlin/com/configcat/model/Condition.kt @@ -9,11 +9,9 @@ import kotlinx.serialization.Serializable @Serializable public data class Condition( @SerialName(value = "u") - val userCondition: UserCondition? = null, + override val userCondition: UserCondition? = null, @SerialName(value = "s") - val segmentCondition: SegmentCondition? = null, + override val segmentCondition: SegmentCondition? = null, @SerialName(value = "p") - val prerequisiteFlagCondition: PrerequisiteFlagCondition? = null -) { - // No implementation -} + override val prerequisiteFlagCondition: PrerequisiteFlagCondition? = null +) : ConditionAccessor diff --git a/src/commonMain/kotlin/com/configcat/model/ConditionAccessor.kt b/src/commonMain/kotlin/com/configcat/model/ConditionAccessor.kt new file mode 100644 index 00000000..a3a2059c --- /dev/null +++ b/src/commonMain/kotlin/com/configcat/model/ConditionAccessor.kt @@ -0,0 +1,8 @@ +package com.configcat.model + +internal interface ConditionAccessor +{ + val userCondition: UserCondition? + val segmentCondition: SegmentCondition? + val prerequisiteFlagCondition: PrerequisiteFlagCondition? +} \ No newline at end of file diff --git a/src/commonMain/kotlin/com/configcat/model/Config.kt b/src/commonMain/kotlin/com/configcat/model/Config.kt index 4ca4ed9f..ed2421e6 100644 --- a/src/commonMain/kotlin/com/configcat/model/Config.kt +++ b/src/commonMain/kotlin/com/configcat/model/Config.kt @@ -33,33 +33,3 @@ internal data class Config( val empty: Config = Config(null, mapOf(), arrayOf()) } } - -internal object FlagValueSerializer : KSerializer { - override fun deserialize(decoder: Decoder): Any { - val json = decoder as? JsonDecoder - ?: error("Only JsonDecoder is supported.") - val element = json.decodeJsonElement() - val primitive = element as? JsonPrimitive ?: error("Unable to decode $element") - return when (primitive.content) { - "true", "false" -> primitive.content == "true" - else -> primitive.content.toIntOrNull() ?: primitive.content.toDoubleOrNull() ?: primitive.content - } - } - - override fun serialize(encoder: Encoder, value: Any) { - val json = encoder as? JsonEncoder - ?: error("Only JsonEncoder is supported.") - val element: JsonElement = when (value) { - is String -> JsonPrimitive(value) - is Number -> JsonPrimitive(value) - is Boolean -> JsonPrimitive(value) - is JsonElement -> value - else -> throw IllegalArgumentException("Unable to encode $value") - } - json.encodeJsonElement(element) - } - - @OptIn(ExperimentalSerializationApi::class) - override val descriptor: SerialDescriptor = - ContextualSerializer(Any::class, null, emptyArray()).descriptor -} diff --git a/src/commonMain/kotlin/com/configcat/model/Segment.kt b/src/commonMain/kotlin/com/configcat/model/Segment.kt index 5d707c72..4a68e852 100644 --- a/src/commonMain/kotlin/com/configcat/model/Segment.kt +++ b/src/commonMain/kotlin/com/configcat/model/Segment.kt @@ -19,5 +19,5 @@ internal data class Segment( @SerialName("r") val segmentRules: Array ) { - // No implementation + internal val conditionAccessors: List = segmentRules.let { condition -> condition.map { it } } } diff --git a/src/commonMain/kotlin/com/configcat/model/TargetingRule.kt b/src/commonMain/kotlin/com/configcat/model/TargetingRule.kt index a52d2bbf..c37ed637 100644 --- a/src/commonMain/kotlin/com/configcat/model/TargetingRule.kt +++ b/src/commonMain/kotlin/com/configcat/model/TargetingRule.kt @@ -26,7 +26,7 @@ public data class TargetingRule( @SerialName(value = "s") val servedValue: ServedValue? = null ) { - // No implementation + internal val conditionAccessors: List = conditions?.let { condition -> condition.map { it } } ?: listOf() } @Serializable diff --git a/src/commonMain/kotlin/com/configcat/model/UserCondition.kt b/src/commonMain/kotlin/com/configcat/model/UserCondition.kt index fb30e689..88dd162e 100644 --- a/src/commonMain/kotlin/com/configcat/model/UserCondition.kt +++ b/src/commonMain/kotlin/com/configcat/model/UserCondition.kt @@ -34,6 +34,8 @@ public data class UserCondition( */ @SerialName("l") val stringArrayValue: Array? = null -) { - // No implementation +) : ConditionAccessor { + override val userCondition: UserCondition = this + override val segmentCondition: SegmentCondition? = null + override val prerequisiteFlagCondition: PrerequisiteFlagCondition? = null }