From dcfc81904b25ed7530a2b4b44163d2b9a5541976 Mon Sep 17 00:00:00 2001 From: Tanmay Ranjan Date: Thu, 4 Apr 2024 12:11:53 +0530 Subject: [PATCH 1/5] Try catch handled in all extension function --- .../com/featurevisor/sdk/DatafileReader.kt | 2 +- .../featurevisor/sdk/Instance+Activation.kt | 44 +++++----- .../com/featurevisor/sdk/Instance+Feature.kt | 81 ++++++++++++------- .../com/featurevisor/sdk/Instance+Fetch.kt | 14 ++-- .../com/featurevisor/sdk/Instance+Segments.kt | 75 +++++++++-------- .../com/featurevisor/sdk/Instance+Variable.kt | 25 ++++-- .../featurevisor/sdk/Instance+Variation.kt | 14 ++-- .../kotlin/com/featurevisor/sdk/Instance.kt | 67 +++++++++++++++ 8 files changed, 221 insertions(+), 101 deletions(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt index eef4c77..b9eb953 100644 --- a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt +++ b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt @@ -8,7 +8,7 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.Segment import com.featurevisor.types.SegmentKey -class DatafileReader constructor( +class DatafileReader ( datafileJson: DatafileContent, ) { diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt index 3454b0b..ba13213 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt @@ -7,27 +7,31 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.VariationValue fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? { - val evaluation = evaluateVariation(featureKey, context) - val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null - val finalContext = interceptContext?.invoke(context) ?: context - val captureContext = mutableMapOf() - val attributesForCapturing = datafileReader.getAllAttributes() - .filter { it.capture == true } + return try { + val evaluation = evaluateVariation(featureKey, context) + val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null + val finalContext = interceptContext?.invoke(context) ?: context + val captureContext = mutableMapOf() + val attributesForCapturing = datafileReader.getAllAttributes() + .filter { it.capture == true } - attributesForCapturing.forEach { attribute -> - finalContext[attribute.key]?.let { - captureContext[attribute.key] = it - } - } + attributesForCapturing.forEach { attribute -> + finalContext[attribute.key]?.let { + captureContext[attribute.key] = it + } + } - emitter.emit( - ACTIVATION, - featureKey, - variationValue, - finalContext, - captureContext, - evaluation - ) + emitter.emit( + ACTIVATION, + featureKey, + variationValue, + finalContext, + captureContext, + evaluation + ) - return variationValue + variationValue + }catch (e:Exception){ + null + } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt index 46cd705..01b3478 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt @@ -8,11 +8,19 @@ import com.featurevisor.types.Force import com.featurevisor.types.Traffic fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? { - return datafileReader.getFeature(featureKey) + return try { + datafileReader.getFeature(featureKey) + }catch (e:Exception){ + null + } } fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{ - return datafileReader.getFeature(featureKey) + return try { + datafileReader.getFeature(featureKey) + }catch (e:Exception){ + null + } } internal fun FeaturevisorInstance.findForceFromFeature( @@ -20,18 +28,21 @@ internal fun FeaturevisorInstance.findForceFromFeature( context: Context, datafileReader: DatafileReader, ): Force? { + return try { + feature.force?.firstOrNull { force -> + when { + force.conditions != null -> allConditionsAreMatched(force.conditions, context) + force.segments != null -> allGroupSegmentsAreMatched( + force.segments, + context, + datafileReader + ) - return feature.force?.firstOrNull { force -> - when { - force.conditions != null -> allConditionsAreMatched(force.conditions, context) - force.segments != null -> allGroupSegmentsAreMatched( - force.segments, - context, - datafileReader - ) - - else -> false + else -> false + } } + }catch (e:Exception){ + null } } @@ -40,9 +51,12 @@ internal fun FeaturevisorInstance.getMatchedTraffic( context: Context, datafileReader: DatafileReader, ): Traffic? { - - return traffic.firstOrNull { trafficItem -> - allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader) + return try { + traffic.firstOrNull { trafficItem -> + allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader) + } + }catch (e:Exception){ + null } } @@ -50,17 +64,20 @@ internal fun FeaturevisorInstance.getMatchedAllocation( traffic: Traffic, bucketValue: Int, ): Allocation? { - - return traffic.allocation.firstOrNull { allocation -> - with(allocation.range) { - bucketValue in this.first()..this.last() + return try { + traffic.allocation.firstOrNull { allocation -> + with(allocation.range) { + bucketValue in this.first()..this.last() + } } + }catch (e:Exception){ + null } } data class MatchedTrafficAndAllocation( - val matchedTraffic: Traffic?, - val matchedAllocation: Allocation?, + val matchedTraffic: Traffic?=null, + val matchedAllocation: Allocation?=null, ) internal fun FeaturevisorInstance.getMatchedTrafficAndAllocation( @@ -70,16 +87,18 @@ internal fun FeaturevisorInstance.getMatchedTrafficAndAllocation( datafileReader: DatafileReader, logger: Logger?, ): MatchedTrafficAndAllocation { - - var matchedAllocation: Allocation? = null - val matchedTraffic = traffic.firstOrNull { trafficItem -> - if (allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader)) { - matchedAllocation = getMatchedAllocation(trafficItem, bucketValue) - true - } else { - false + return try { + var matchedAllocation: Allocation? = null + val matchedTraffic = traffic.firstOrNull { trafficItem -> + if (allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader)) { + matchedAllocation = getMatchedAllocation(trafficItem, bucketValue) + true + } else { + false + } } + MatchedTrafficAndAllocation(matchedTraffic, matchedAllocation) + }catch (e:Exception){ + MatchedTrafficAndAllocation() } - - return MatchedTrafficAndAllocation(matchedTraffic, matchedAllocation) } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt index ea950c8..911ad6e 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt @@ -15,11 +15,15 @@ internal fun FeaturevisorInstance.fetchDatafileContent( handleDatafileFetch: DatafileFetchHandler? = null, completion: (Result) -> Unit, ) { - handleDatafileFetch?.let { handleFetch -> - val result = handleFetch(url) - completion(result) - } ?: run { - fetchDatafileContentFromUrl(url, completion) + try { + handleDatafileFetch?.let { handleFetch -> + val result = handleFetch(url) + completion(result) + } ?: run { + fetchDatafileContentFromUrl(url, completion) + } + }catch (e:Exception){ + completion(Result.failure(FeaturevisorError.InvalidUrl(url))) } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt index b71d893..9946c83 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt @@ -12,17 +12,22 @@ internal fun FeaturevisorInstance.segmentIsMatched( featureKey: FeatureKey, context: Context, ): VariationValue? { - val evaluation = evaluateVariation(featureKey, context) + return try { + val evaluation = evaluateVariation(featureKey, context) + var variationValue: VariationValue? = null - if (evaluation.variationValue != null) { - return evaluation.variationValue - } + if (evaluation.variationValue != null) { + variationValue = evaluation.variationValue + } - if (evaluation.variation != null) { - return evaluation.variation.value - } + if (evaluation.variation != null) { + variationValue = evaluation.variation.value + } - return null + variationValue + } catch (e: Exception) { + null + } } internal fun segmentIsMatched(segment: Segment, context: Context): Boolean { @@ -34,40 +39,44 @@ internal fun FeaturevisorInstance.allGroupSegmentsAreMatched( context: Context, datafileReader: DatafileReader, ): Boolean { - return when (groupSegments) { - is Plain -> { - val segmentKey = groupSegments.segment - if (segmentKey == "*") { - true - } else { - datafileReader.getSegment(segmentKey)?.let { - segmentIsMatched(it, context) - } ?: false + return try { + when (groupSegments) { + is Plain -> { + val segmentKey = groupSegments.segment + if (segmentKey == "*") { + true + } else { + datafileReader.getSegment(segmentKey)?.let { + segmentIsMatched(it, context) + } ?: false + } } - } - is Multiple -> { - groupSegments.segments.all { - allGroupSegmentsAreMatched(it, context, datafileReader) + is Multiple -> { + groupSegments.segments.all { + allGroupSegmentsAreMatched(it, context, datafileReader) + } } - } - is And -> { - groupSegments.segment.and.all { - allGroupSegmentsAreMatched(it, context, datafileReader) + is And -> { + groupSegments.segment.and.all { + allGroupSegmentsAreMatched(it, context, datafileReader) + } } - } - is Or -> { - groupSegments.segment.or.any { - allGroupSegmentsAreMatched(it, context, datafileReader) + is Or -> { + groupSegments.segment.or.any { + allGroupSegmentsAreMatched(it, context, datafileReader) + } } - } - is Not -> { - groupSegments.segment.not.all { - allGroupSegmentsAreMatched(it, context, datafileReader).not() + is Not -> { + groupSegments.segment.not.all { + allGroupSegmentsAreMatched(it, context, datafileReader).not() + } } } + }catch (e:Exception){ + false } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt index 925f20d..16fd2e5 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt @@ -11,6 +11,7 @@ import com.featurevisor.types.VariableValue.IntValue import com.featurevisor.types.VariableValue.JsonValue import com.featurevisor.types.VariableValue.ObjectValue import com.featurevisor.types.VariableValue.StringValue +import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement @@ -21,13 +22,17 @@ fun FeaturevisorInstance.getVariable( variableKey: VariableKey, context: Context = emptyMap(), ): VariableValue? { - val evaluation = evaluateVariable( - featureKey = featureKey, - variableKey = variableKey, - context = context - ) + return try { + val evaluation = evaluateVariable( + featureKey = featureKey, + variableKey = variableKey, + context = context + ) - return evaluation.variableValue + evaluation.variableValue + } catch (e: Exception) { + null + } } fun FeaturevisorInstance.getVariableBoolean( @@ -97,3 +102,11 @@ inline fun FeaturevisorInstance.getVariableJSON( } } +@Serializable +data class CountriesWithStringValueAndSeparateDefault( + val country: Map?, + val default: String?, +) + + + diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt index 5a9eb2a..dcb83a1 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt @@ -5,10 +5,14 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.VariationValue internal fun FeaturevisorInstance.getVariation(featureKey: FeatureKey, context: Context): VariationValue? { - val evaluation = evaluateVariation(featureKey, context) - return when { - evaluation.variationValue != null -> evaluation.variationValue - evaluation.variation != null -> evaluation.variation.value - else -> null + return try { + val evaluation = evaluateVariation(featureKey, context) + return when { + evaluation.variationValue != null -> evaluation.variationValue + evaluation.variation != null -> evaluation.variation.value + else -> null + } + }catch (e:Exception){ + null } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index 9e9b2b1..bdbbf86 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -7,6 +7,7 @@ import com.featurevisor.sdk.FeaturevisorError.MissingDatafileOptions import com.featurevisor.types.* import com.featurevisor.types.EventName.* import kotlinx.coroutines.Job +import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json @@ -15,6 +16,72 @@ typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue typealias InterceptContext = (Context) -> Context typealias DatafileFetchHandler = (datafileUrl: String) -> Result +fun main(args: Array) { + + var abc:FeaturevisorInstance? = null + var isReady:Boolean = false + abc = FeaturevisorInstance.createInstance( + options = InstanceOptions( + configureBucketKey = null, + configureBucketValue = null, + datafileUrl = "https://features.fe.indazn.com/staging/datafile-tag-android.json", + logger = Logger.createLogger( + levels = listOf( + Logger.LogLevel.ERROR, + Logger.LogLevel.DEBUG, + Logger.LogLevel.WARN, + Logger.LogLevel.INFO + ) , + handle = { _, message, _ -> + println(message) + } + ), +// onReady = { +// isReady = true +// println("onReady $it") +// +// val value = abc?.getVariableJSON("live_preroll_ads","live_preroll_ads_custom_tags", getContext()) +// println("Value : $value") +// +// }, +// onError = { +// println("onError $it") +// } + ) + ) + + + val value = abc?.getVariableJSON("live_preroll_ads","live_preroll_ads_custom_tags", getContext()) + println("Value : $value") + + +// if (isReady){ +// val value = abc.getVariableJSON>("live_preroll_ads","live_preroll_watched_duration", getContext()) +// println("Value : $value") +// }else{ +// println("Not Ready") +// } + +} + + +private fun getContext(): Map = + mapOf( + "deviceId" to AttributeValue.StringValue("45645"), + "version_code" to AttributeValue.StringValue(""), + "app_info_version" to AttributeValue.StringValue(""), + "Platform" to AttributeValue.StringValue("Android"), + "BillingCountry" to AttributeValue.StringValue("In"), + "GeolocatedCountry" to AttributeValue.StringValue("In"), + "device_os" to AttributeValue.StringValue("Android"), + "DevMode" to AttributeValue.BooleanValue(false), + "device_model" to AttributeValue.StringValue("5dfgfcx"), + "device_language" to AttributeValue.StringValue("en"), + "user_status" to AttributeValue.StringValue("Active") + ) + + + class FeaturevisorInstance private constructor(options: InstanceOptions) { companion object { From 07db757caa3d21b8acc22edc1fc23b179920079f Mon Sep 17 00:00:00 2001 From: Tanmay Ranjan Date: Thu, 4 Apr 2024 12:30:29 +0530 Subject: [PATCH 2/5] print log in case of exception --- .../featurevisor/sdk/Instance+Activation.kt | 1 + .../com/featurevisor/sdk/Instance+Feature.kt | 8 ++- .../com/featurevisor/sdk/Instance+Segments.kt | 2 + .../com/featurevisor/sdk/Instance+Variable.kt | 9 +-- .../featurevisor/sdk/Instance+Variation.kt | 3 +- .../kotlin/com/featurevisor/sdk/Instance.kt | 66 ------------------- 6 files changed, 15 insertions(+), 74 deletions(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt index ba13213..d1c3ae3 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt @@ -32,6 +32,7 @@ fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emp variationValue }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in activate() -> $e") null } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt index 01b3478..97c549e 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt @@ -11,6 +11,7 @@ fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? { return try { datafileReader.getFeature(featureKey) }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in getFeatureByKey() -> $e") null } } @@ -19,6 +20,7 @@ fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{ return try { datafileReader.getFeature(featureKey) }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in getFeature() -> $e") null } } @@ -42,6 +44,7 @@ internal fun FeaturevisorInstance.findForceFromFeature( } } }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in findForceFromFeature() -> $e") null } } @@ -56,6 +59,7 @@ internal fun FeaturevisorInstance.getMatchedTraffic( allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader) } }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in getMatchedTraffic() -> $e") null } } @@ -71,6 +75,7 @@ internal fun FeaturevisorInstance.getMatchedAllocation( } } }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in getMatchedAllocation() -> $e") null } } @@ -99,6 +104,7 @@ internal fun FeaturevisorInstance.getMatchedTrafficAndAllocation( } MatchedTrafficAndAllocation(matchedTraffic, matchedAllocation) }catch (e:Exception){ - MatchedTrafficAndAllocation() + FeaturevisorInstance.companionLogger?.error("Exception in getMatchedTrafficAndAllocation() -> $e") + MatchedTrafficAndAllocation() } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt index 9946c83..e1dc814 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt @@ -26,6 +26,7 @@ internal fun FeaturevisorInstance.segmentIsMatched( variationValue } catch (e: Exception) { + FeaturevisorInstance.companionLogger?.error("Exception in segmentIsMatched() -> $e") null } } @@ -77,6 +78,7 @@ internal fun FeaturevisorInstance.allGroupSegmentsAreMatched( } } }catch (e:Exception){ + FeaturevisorInstance.companionLogger?.error("Exception in allGroupSegmentsAreMatched() -> $e") false } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt index 16fd2e5..f3d48e4 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt @@ -31,6 +31,7 @@ fun FeaturevisorInstance.getVariable( evaluation.variableValue } catch (e: Exception) { + FeaturevisorInstance.companionLogger?.error("Exception in getVariable() -> $e") null } } @@ -85,6 +86,7 @@ inline fun FeaturevisorInstance.getVariableObject( val encoded = Json.encodeToJsonElement(objectValue?.value) return Json.decodeFromJsonElement(encoded) } catch (e: Exception) { + FeaturevisorInstance.companionLogger?.error("Exception in getVariableObject() -> $e") null } } @@ -98,15 +100,10 @@ inline fun FeaturevisorInstance.getVariableJSON( return try { Json.decodeFromString(json!!.value) } catch (e: Exception) { + FeaturevisorInstance.companionLogger?.error("Exception in getVariableJSON() -> $e") null } } -@Serializable -data class CountriesWithStringValueAndSeparateDefault( - val country: Map?, - val default: String?, -) - diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt index dcb83a1..a57ddb9 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt @@ -13,6 +13,7 @@ internal fun FeaturevisorInstance.getVariation(featureKey: FeatureKey, context: else -> null } }catch (e:Exception){ - null + FeaturevisorInstance.companionLogger?.error("Exception in getVariation() -> $e") + null } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index bdbbf86..a906bd5 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -16,72 +16,6 @@ typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue typealias InterceptContext = (Context) -> Context typealias DatafileFetchHandler = (datafileUrl: String) -> Result -fun main(args: Array) { - - var abc:FeaturevisorInstance? = null - var isReady:Boolean = false - abc = FeaturevisorInstance.createInstance( - options = InstanceOptions( - configureBucketKey = null, - configureBucketValue = null, - datafileUrl = "https://features.fe.indazn.com/staging/datafile-tag-android.json", - logger = Logger.createLogger( - levels = listOf( - Logger.LogLevel.ERROR, - Logger.LogLevel.DEBUG, - Logger.LogLevel.WARN, - Logger.LogLevel.INFO - ) , - handle = { _, message, _ -> - println(message) - } - ), -// onReady = { -// isReady = true -// println("onReady $it") -// -// val value = abc?.getVariableJSON("live_preroll_ads","live_preroll_ads_custom_tags", getContext()) -// println("Value : $value") -// -// }, -// onError = { -// println("onError $it") -// } - ) - ) - - - val value = abc?.getVariableJSON("live_preroll_ads","live_preroll_ads_custom_tags", getContext()) - println("Value : $value") - - -// if (isReady){ -// val value = abc.getVariableJSON>("live_preroll_ads","live_preroll_watched_duration", getContext()) -// println("Value : $value") -// }else{ -// println("Not Ready") -// } - -} - - -private fun getContext(): Map = - mapOf( - "deviceId" to AttributeValue.StringValue("45645"), - "version_code" to AttributeValue.StringValue(""), - "app_info_version" to AttributeValue.StringValue(""), - "Platform" to AttributeValue.StringValue("Android"), - "BillingCountry" to AttributeValue.StringValue("In"), - "GeolocatedCountry" to AttributeValue.StringValue("In"), - "device_os" to AttributeValue.StringValue("Android"), - "DevMode" to AttributeValue.BooleanValue(false), - "device_model" to AttributeValue.StringValue("5dfgfcx"), - "device_language" to AttributeValue.StringValue("en"), - "user_status" to AttributeValue.StringValue("Active") - ) - - - class FeaturevisorInstance private constructor(options: InstanceOptions) { companion object { From c36861d539cec55603a03900051bf0a2d4300735 Mon Sep 17 00:00:00 2001 From: Tanmay Ranjan Date: Thu, 4 Apr 2024 13:06:46 +0530 Subject: [PATCH 3/5] handle empty data file before fetching data file and remove try catch --- .../featurevisor/sdk/Instance+Activation.kt | 45 +++++----- .../com/featurevisor/sdk/Instance+Feature.kt | 87 +++++++------------ .../com/featurevisor/sdk/Instance+Fetch.kt | 14 ++- .../com/featurevisor/sdk/Instance+Segments.kt | 77 +++++++--------- .../com/featurevisor/sdk/Instance+Variable.kt | 22 ++--- .../featurevisor/sdk/Instance+Variation.kt | 15 ++-- .../kotlin/com/featurevisor/sdk/Instance.kt | 11 ++- 7 files changed, 110 insertions(+), 161 deletions(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt index d1c3ae3..3454b0b 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Activation.kt @@ -7,32 +7,27 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.VariationValue fun FeaturevisorInstance.activate(featureKey: FeatureKey, context: Context = emptyMap()): VariationValue? { - return try { - val evaluation = evaluateVariation(featureKey, context) - val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null - val finalContext = interceptContext?.invoke(context) ?: context - val captureContext = mutableMapOf() - val attributesForCapturing = datafileReader.getAllAttributes() - .filter { it.capture == true } + val evaluation = evaluateVariation(featureKey, context) + val variationValue = evaluation.variation?.value ?: evaluation.variationValue ?: return null + val finalContext = interceptContext?.invoke(context) ?: context + val captureContext = mutableMapOf() + val attributesForCapturing = datafileReader.getAllAttributes() + .filter { it.capture == true } - attributesForCapturing.forEach { attribute -> - finalContext[attribute.key]?.let { - captureContext[attribute.key] = it - } - } + attributesForCapturing.forEach { attribute -> + finalContext[attribute.key]?.let { + captureContext[attribute.key] = it + } + } - emitter.emit( - ACTIVATION, - featureKey, - variationValue, - finalContext, - captureContext, - evaluation - ) + emitter.emit( + ACTIVATION, + featureKey, + variationValue, + finalContext, + captureContext, + evaluation + ) - variationValue - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in activate() -> $e") - null - } + return variationValue } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt index 97c549e..46cd705 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Feature.kt @@ -8,21 +8,11 @@ import com.featurevisor.types.Force import com.featurevisor.types.Traffic fun FeaturevisorInstance.getFeatureByKey(featureKey: String): Feature? { - return try { - datafileReader.getFeature(featureKey) - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getFeatureByKey() -> $e") - null - } + return datafileReader.getFeature(featureKey) } fun FeaturevisorInstance.getFeature(featureKey: String): Feature?{ - return try { - datafileReader.getFeature(featureKey) - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getFeature() -> $e") - null - } + return datafileReader.getFeature(featureKey) } internal fun FeaturevisorInstance.findForceFromFeature( @@ -30,22 +20,18 @@ internal fun FeaturevisorInstance.findForceFromFeature( context: Context, datafileReader: DatafileReader, ): Force? { - return try { - feature.force?.firstOrNull { force -> - when { - force.conditions != null -> allConditionsAreMatched(force.conditions, context) - force.segments != null -> allGroupSegmentsAreMatched( - force.segments, - context, - datafileReader - ) - else -> false - } + return feature.force?.firstOrNull { force -> + when { + force.conditions != null -> allConditionsAreMatched(force.conditions, context) + force.segments != null -> allGroupSegmentsAreMatched( + force.segments, + context, + datafileReader + ) + + else -> false } - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in findForceFromFeature() -> $e") - null } } @@ -54,13 +40,9 @@ internal fun FeaturevisorInstance.getMatchedTraffic( context: Context, datafileReader: DatafileReader, ): Traffic? { - return try { - traffic.firstOrNull { trafficItem -> - allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader) - } - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getMatchedTraffic() -> $e") - null + + return traffic.firstOrNull { trafficItem -> + allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader) } } @@ -68,21 +50,17 @@ internal fun FeaturevisorInstance.getMatchedAllocation( traffic: Traffic, bucketValue: Int, ): Allocation? { - return try { - traffic.allocation.firstOrNull { allocation -> - with(allocation.range) { - bucketValue in this.first()..this.last() - } + + return traffic.allocation.firstOrNull { allocation -> + with(allocation.range) { + bucketValue in this.first()..this.last() } - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getMatchedAllocation() -> $e") - null } } data class MatchedTrafficAndAllocation( - val matchedTraffic: Traffic?=null, - val matchedAllocation: Allocation?=null, + val matchedTraffic: Traffic?, + val matchedAllocation: Allocation?, ) internal fun FeaturevisorInstance.getMatchedTrafficAndAllocation( @@ -92,19 +70,16 @@ internal fun FeaturevisorInstance.getMatchedTrafficAndAllocation( datafileReader: DatafileReader, logger: Logger?, ): MatchedTrafficAndAllocation { - return try { - var matchedAllocation: Allocation? = null - val matchedTraffic = traffic.firstOrNull { trafficItem -> - if (allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader)) { - matchedAllocation = getMatchedAllocation(trafficItem, bucketValue) - true - } else { - false - } + + var matchedAllocation: Allocation? = null + val matchedTraffic = traffic.firstOrNull { trafficItem -> + if (allGroupSegmentsAreMatched(trafficItem.segments, context, datafileReader)) { + matchedAllocation = getMatchedAllocation(trafficItem, bucketValue) + true + } else { + false } - MatchedTrafficAndAllocation(matchedTraffic, matchedAllocation) - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getMatchedTrafficAndAllocation() -> $e") - MatchedTrafficAndAllocation() } + + return MatchedTrafficAndAllocation(matchedTraffic, matchedAllocation) } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt index 911ad6e..ea950c8 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt @@ -15,15 +15,11 @@ internal fun FeaturevisorInstance.fetchDatafileContent( handleDatafileFetch: DatafileFetchHandler? = null, completion: (Result) -> Unit, ) { - try { - handleDatafileFetch?.let { handleFetch -> - val result = handleFetch(url) - completion(result) - } ?: run { - fetchDatafileContentFromUrl(url, completion) - } - }catch (e:Exception){ - completion(Result.failure(FeaturevisorError.InvalidUrl(url))) + handleDatafileFetch?.let { handleFetch -> + val result = handleFetch(url) + completion(result) + } ?: run { + fetchDatafileContentFromUrl(url, completion) } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt index e1dc814..b71d893 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Segments.kt @@ -12,23 +12,17 @@ internal fun FeaturevisorInstance.segmentIsMatched( featureKey: FeatureKey, context: Context, ): VariationValue? { - return try { - val evaluation = evaluateVariation(featureKey, context) - var variationValue: VariationValue? = null + val evaluation = evaluateVariation(featureKey, context) - if (evaluation.variationValue != null) { - variationValue = evaluation.variationValue - } - - if (evaluation.variation != null) { - variationValue = evaluation.variation.value - } + if (evaluation.variationValue != null) { + return evaluation.variationValue + } - variationValue - } catch (e: Exception) { - FeaturevisorInstance.companionLogger?.error("Exception in segmentIsMatched() -> $e") - null + if (evaluation.variation != null) { + return evaluation.variation.value } + + return null } internal fun segmentIsMatched(segment: Segment, context: Context): Boolean { @@ -40,45 +34,40 @@ internal fun FeaturevisorInstance.allGroupSegmentsAreMatched( context: Context, datafileReader: DatafileReader, ): Boolean { - return try { - when (groupSegments) { - is Plain -> { - val segmentKey = groupSegments.segment - if (segmentKey == "*") { - true - } else { - datafileReader.getSegment(segmentKey)?.let { - segmentIsMatched(it, context) - } ?: false - } + return when (groupSegments) { + is Plain -> { + val segmentKey = groupSegments.segment + if (segmentKey == "*") { + true + } else { + datafileReader.getSegment(segmentKey)?.let { + segmentIsMatched(it, context) + } ?: false } + } - is Multiple -> { - groupSegments.segments.all { - allGroupSegmentsAreMatched(it, context, datafileReader) - } + is Multiple -> { + groupSegments.segments.all { + allGroupSegmentsAreMatched(it, context, datafileReader) } + } - is And -> { - groupSegments.segment.and.all { - allGroupSegmentsAreMatched(it, context, datafileReader) - } + is And -> { + groupSegments.segment.and.all { + allGroupSegmentsAreMatched(it, context, datafileReader) } + } - is Or -> { - groupSegments.segment.or.any { - allGroupSegmentsAreMatched(it, context, datafileReader) - } + is Or -> { + groupSegments.segment.or.any { + allGroupSegmentsAreMatched(it, context, datafileReader) } + } - is Not -> { - groupSegments.segment.not.all { - allGroupSegmentsAreMatched(it, context, datafileReader).not() - } + is Not -> { + groupSegments.segment.not.all { + allGroupSegmentsAreMatched(it, context, datafileReader).not() } } - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in allGroupSegmentsAreMatched() -> $e") - false } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt index f3d48e4..925f20d 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variable.kt @@ -11,7 +11,6 @@ import com.featurevisor.types.VariableValue.IntValue import com.featurevisor.types.VariableValue.JsonValue import com.featurevisor.types.VariableValue.ObjectValue import com.featurevisor.types.VariableValue.StringValue -import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement @@ -22,18 +21,13 @@ fun FeaturevisorInstance.getVariable( variableKey: VariableKey, context: Context = emptyMap(), ): VariableValue? { - return try { - val evaluation = evaluateVariable( - featureKey = featureKey, - variableKey = variableKey, - context = context - ) + val evaluation = evaluateVariable( + featureKey = featureKey, + variableKey = variableKey, + context = context + ) - evaluation.variableValue - } catch (e: Exception) { - FeaturevisorInstance.companionLogger?.error("Exception in getVariable() -> $e") - null - } + return evaluation.variableValue } fun FeaturevisorInstance.getVariableBoolean( @@ -86,7 +80,6 @@ inline fun FeaturevisorInstance.getVariableObject( val encoded = Json.encodeToJsonElement(objectValue?.value) return Json.decodeFromJsonElement(encoded) } catch (e: Exception) { - FeaturevisorInstance.companionLogger?.error("Exception in getVariableObject() -> $e") null } } @@ -100,10 +93,7 @@ inline fun FeaturevisorInstance.getVariableJSON( return try { Json.decodeFromString(json!!.value) } catch (e: Exception) { - FeaturevisorInstance.companionLogger?.error("Exception in getVariableJSON() -> $e") null } } - - diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt index a57ddb9..5a9eb2a 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Variation.kt @@ -5,15 +5,10 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.VariationValue internal fun FeaturevisorInstance.getVariation(featureKey: FeatureKey, context: Context): VariationValue? { - return try { - val evaluation = evaluateVariation(featureKey, context) - return when { - evaluation.variationValue != null -> evaluation.variationValue - evaluation.variation != null -> evaluation.variation.value - else -> null - } - }catch (e:Exception){ - FeaturevisorInstance.companionLogger?.error("Exception in getVariation() -> $e") - null + val evaluation = evaluateVariation(featureKey, context) + return when { + evaluation.variationValue != null -> evaluation.variationValue + evaluation.variation != null -> evaluation.variation.value + else -> null } } diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index a906bd5..c6770f9 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -7,7 +7,6 @@ import com.featurevisor.sdk.FeaturevisorError.MissingDatafileOptions import com.featurevisor.types.* import com.featurevisor.types.EventName.* import kotlinx.coroutines.Job -import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json @@ -16,6 +15,15 @@ typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue typealias InterceptContext = (Context) -> Context typealias DatafileFetchHandler = (datafileUrl: String) -> Result +var emptyDatafile = DatafileContent( + schemaVersion = "1", + revision = "unknown", + attributes = emptyList(), + segments = emptyList(), + features = emptyList(), + +) + class FeaturevisorInstance private constructor(options: InstanceOptions) { companion object { @@ -92,6 +100,7 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) { } datafileUrl != null -> { + datafileReader = DatafileReader(options.datafile?: emptyDatafile) fetchDatafileContent(datafileUrl) { result -> if (result.isSuccess) { datafileReader = DatafileReader(result.getOrThrow()) From 2f164c0a1ad13d11c969ef67a2aad6eabac81a32 Mon Sep 17 00:00:00 2001 From: Tanmay Ranjan Date: Thu, 4 Apr 2024 13:08:47 +0530 Subject: [PATCH 4/5] revert constructor in data file reader --- src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt index b9eb953..eef4c77 100644 --- a/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt +++ b/src/main/kotlin/com/featurevisor/sdk/DatafileReader.kt @@ -8,7 +8,7 @@ import com.featurevisor.types.FeatureKey import com.featurevisor.types.Segment import com.featurevisor.types.SegmentKey -class DatafileReader ( +class DatafileReader constructor( datafileJson: DatafileContent, ) { From 1846d75bde7b5583c266b5e57d865074a2d6a689 Mon Sep 17 00:00:00 2001 From: Tanmay Ranjan Date: Thu, 4 Apr 2024 13:49:22 +0530 Subject: [PATCH 5/5] extra line removed --- src/main/kotlin/com/featurevisor/sdk/Instance.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index c6770f9..6beecac 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -21,7 +21,6 @@ var emptyDatafile = DatafileContent( attributes = emptyList(), segments = emptyList(), features = emptyList(), - ) class FeaturevisorInstance private constructor(options: InstanceOptions) {