@@ -77,11 +77,11 @@ internal class Evaluator(
77
77
}
78
78
79
79
fun getVariants (configName : String ): Map <String , Map <String , Any >> {
80
- var variants: MutableMap <String , Map <String , Any >> = HashMap ()
80
+ val variants: MutableMap <String , Map <String , Any >> = HashMap ()
81
81
val config = specStore.getConfig(configName) ? : return variants
82
82
83
83
var previousAllocation = 0.0
84
- for (r: APIRule in config!! .rules) {
84
+ for (r: APIRule in config.rules) {
85
85
val value = r.returnValue.toString()
86
86
val cond = r.conditions[0 ]
87
87
var percent = 0.0
@@ -163,8 +163,18 @@ internal class Evaluator(
163
163
return this .evaluateConfig(user, specStore.getConfig(dynamicConfigName))
164
164
}
165
165
166
- fun getClientInitializeResponse (user : StatsigUser , hash : HashAlgo = HashAlgo .SHA256 , clientSDKKey : String? = null): Map <String , Any > {
167
- return ClientInitializeFormatter (this .specStore, this ::evaluateConfig, user, hash, clientSDKKey).getFormattedResponse()
166
+ fun getClientInitializeResponse (
167
+ user : StatsigUser ,
168
+ hash : HashAlgo = HashAlgo .SHA256 ,
169
+ clientSDKKey : String? = null
170
+ ): Map <String , Any > {
171
+ return ClientInitializeFormatter (
172
+ this .specStore,
173
+ this ::evaluateConfig,
174
+ user,
175
+ hash,
176
+ clientSDKKey
177
+ ).getFormattedResponse()
168
178
}
169
179
170
180
fun getLayer (user : StatsigUser , layerName : String ): ConfigEvaluation {
@@ -293,7 +303,7 @@ internal class Evaluator(
293
303
undelegatedSecondaryExposures.addAll(secondaryExposures)
294
304
secondaryExposures.addAll(delegatedResult.secondaryExposures)
295
305
296
- var evaluation = ConfigEvaluation (
306
+ val evaluation = ConfigEvaluation (
297
307
fetchFromServer = delegatedResult.fetchFromServer,
298
308
booleanValue = delegatedResult.booleanValue,
299
309
jsonValue = delegatedResult.jsonValue,
@@ -333,7 +343,7 @@ internal class Evaluator(
333
343
)
334
344
}
335
345
336
- private fun conditionFromString (input : String? ): ConfigCondition ? {
346
+ private fun conditionFromString (input : String? ): ConfigCondition {
337
347
return when (input) {
338
348
" PUBLIC" , " public" -> ConfigCondition .PUBLIC
339
349
" FAIL_GATE" , " fail_gate" -> ConfigCondition .FAIL_GATE
@@ -352,23 +362,25 @@ internal class Evaluator(
352
362
private fun evaluateCondition (user : StatsigUser , condition : APICondition ): ConfigEvaluation {
353
363
try {
354
364
var value: Any?
355
- val conditionEnum : ConfigCondition ?
356
- conditionEnum = try {
365
+ val field : String = Utils .toStringOrEmpty(condition.field)
366
+ val conditionEnum: ConfigCondition ? = try {
357
367
conditionFromString(condition.type)
358
368
} catch (e: java.lang.IllegalArgumentException ) {
359
369
errorBoundary.logException(" evaluateCondition:condition" , e)
360
370
println (" [Statsig]: An exception was caught: $e " )
361
371
null
362
372
}
373
+
363
374
when (conditionEnum) {
364
375
ConfigCondition .PUBLIC ->
365
376
return ConfigEvaluation (fetchFromServer = false , booleanValue = true )
366
377
367
378
ConfigCondition .FAIL_GATE , ConfigCondition .PASS_GATE -> {
368
- val result = this .checkGate(user, condition.targetValue as String )
379
+ val name = Utils .toStringOrEmpty(condition.targetValue)
380
+ val result = this .checkGate(user, name)
369
381
val newExposure =
370
382
mapOf (
371
- " gate" to condition.targetValue ,
383
+ " gate" to name ,
372
384
" gateValue" to result.booleanValue.toString(),
373
385
" ruleID" to result.ruleID,
374
386
)
@@ -390,38 +402,38 @@ internal class Evaluator(
390
402
}
391
403
392
404
ConfigCondition .IP_BASED -> {
393
- value = getFromUser(user, condition. field)
405
+ value = getFromUser(user, field)
394
406
if (value == null ) {
395
407
val ipString = getFromUser(user, " ip" )?.toString()
396
- if (ipString == null ) {
397
- return ConfigEvaluation (fetchFromServer = false , booleanValue = false )
408
+ value = if (ipString == null ) {
409
+ null
398
410
} else {
399
- value = CountryLookup .lookupIPString(ipString)
411
+ CountryLookup .lookupIPString(ipString)
400
412
}
401
413
}
402
414
}
403
415
404
416
ConfigCondition .UA_BASED -> {
405
- value = getFromUser(user, condition. field)
417
+ value = getFromUser(user, field)
406
418
if (value == null && ! condition.field.equals(" browser_version" )) {
407
- value = getFromUserAgent(user, condition. field)
419
+ value = getFromUserAgent(user, field)
408
420
}
409
421
}
410
422
411
423
ConfigCondition .USER_FIELD -> {
412
- value = getFromUser(user, condition. field)
424
+ value = getFromUser(user, field)
413
425
}
414
426
415
427
ConfigCondition .CURRENT_TIME -> {
416
428
value = System .currentTimeMillis().toString()
417
429
}
418
430
419
431
ConfigCondition .ENVIRONMENT_FIELD -> {
420
- value = getFromEnvironment(user, condition. field)
432
+ value = getFromEnvironment(user, field)
421
433
}
422
434
423
435
ConfigCondition .USER_BUCKET -> {
424
- val salt = getValueAsString(condition.additionalValues[" salt" ])
436
+ val salt = getValueAsString(condition.additionalValues?. let { it [" salt" ] } )
425
437
val unitID = getUnitID(user, condition.idType) ? : " "
426
438
value = computeUserHash(" $salt .$unitID " ).mod(1000UL )
427
439
}
@@ -487,7 +499,7 @@ internal class Evaluator(
487
499
" version_gt" -> {
488
500
return ConfigEvaluation (
489
501
false ,
490
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
502
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
491
503
versionCompare(v1, v2) > 0
492
504
},
493
505
)
@@ -496,7 +508,7 @@ internal class Evaluator(
496
508
" version_gte" -> {
497
509
return ConfigEvaluation (
498
510
false ,
499
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
511
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
500
512
versionCompare(v1, v2) >= 0
501
513
},
502
514
)
@@ -505,7 +517,7 @@ internal class Evaluator(
505
517
" version_lt" -> {
506
518
return ConfigEvaluation (
507
519
false ,
508
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
520
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
509
521
versionCompare(v1, v2) < 0
510
522
},
511
523
)
@@ -514,7 +526,7 @@ internal class Evaluator(
514
526
" version_lte" -> {
515
527
return ConfigEvaluation (
516
528
false ,
517
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
529
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
518
530
versionCompare(v1, v2) <= 0
519
531
},
520
532
)
@@ -523,7 +535,7 @@ internal class Evaluator(
523
535
" version_eq" -> {
524
536
return ConfigEvaluation (
525
537
false ,
526
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
538
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
527
539
versionCompare(v1, v2) == 0
528
540
},
529
541
)
@@ -532,7 +544,7 @@ internal class Evaluator(
532
544
" version_neq" -> {
533
545
return ConfigEvaluation (
534
546
false ,
535
- versionCompareHelper(value, condition.targetValue as String ) { v1: String , v2: String ->
547
+ versionCompareHelper(value, condition.targetValue) { v1: String , v2: String ->
536
548
versionCompare(v1, v2) != 0
537
549
},
538
550
)
@@ -611,15 +623,22 @@ internal class Evaluator(
611
623
}
612
624
613
625
" str_matches" -> {
626
+ val targetValue = getValueAsString(condition.targetValue)
627
+ ? : return ConfigEvaluation (
628
+ fetchFromServer = false ,
629
+ booleanValue = false ,
630
+ )
631
+
614
632
val strValue =
615
633
getValueAsString(value)
616
634
? : return ConfigEvaluation (
617
635
fetchFromServer = false ,
618
636
booleanValue = false ,
619
637
)
638
+
620
639
return ConfigEvaluation (
621
640
fetchFromServer = false ,
622
- booleanValue = Regex (condition. targetValue as String ).containsMatchIn(strValue),
641
+ booleanValue = Regex (targetValue).containsMatchIn(strValue),
623
642
)
624
643
}
625
644
@@ -667,7 +686,7 @@ internal class Evaluator(
667
686
}
668
687
669
688
" in_segment_list" , " not_in_segment_list" -> {
670
- val idList = specStore.getIDList(condition.targetValue as String )
689
+ val idList = specStore.getIDList(Utils .toStringOrEmpty( condition.targetValue) )
671
690
val stringValue = getValueAsString(value)
672
691
if (idList != null && stringValue != null ) {
673
692
val bytes =
@@ -702,14 +721,20 @@ internal class Evaluator(
702
721
target : Any? ,
703
722
compare : (value: String , target: String ) -> Boolean ,
704
723
): Boolean {
705
- var strValue = getValueAsString(value) ? : return false
706
- var iterable =
707
- if (target is Iterable <* >) {
708
- target
709
- } else if (target is Array <* >) {
710
- target.asIterable()
711
- } else {
712
- return false
724
+ val strValue = getValueAsString(value) ? : return false
725
+ val iterable =
726
+ when (target) {
727
+ is Iterable <* > -> {
728
+ target
729
+ }
730
+
731
+ is Array <* > -> {
732
+ target.asIterable()
733
+ }
734
+
735
+ else -> {
736
+ return false
737
+ }
713
738
}
714
739
715
740
for (match in iterable) {
@@ -780,7 +805,7 @@ internal class Evaluator(
780
805
return null
781
806
}
782
807
return try {
783
- var epoch: Long = getEpoch(input) ? : return parseISOTimestamp(input)
808
+ val epoch: Long = getEpoch(input) ? : return parseISOTimestamp(input)
784
809
val instant = Instant .ofEpochMilli(epoch)
785
810
Date .from(instant)
786
811
} catch (e: Exception ) {
@@ -789,8 +814,8 @@ internal class Evaluator(
789
814
}
790
815
791
816
private fun versionCompare (v1 : String , v2 : String ): Int {
792
- var parts1 = v1.split(" ." )
793
- var parts2 = v2.split(" ." )
817
+ val parts1 = v1.split(" ." )
818
+ val parts2 = v2.split(" ." )
794
819
795
820
var i = 0
796
821
while (i < parts1.size.coerceAtLeast(parts2.size)) {
@@ -859,31 +884,43 @@ internal class Evaluator(
859
884
if (input == null ) {
860
885
return null
861
886
}
887
+
862
888
if (input is String ) {
863
889
return input.toDoubleOrNull()
864
890
}
865
- if (input is Number ) {
891
+
892
+ if (input is ULong ) {
866
893
return input.toDouble()
867
894
}
868
- if (input is ULong ) {
895
+
896
+ if (input is Double ) {
897
+ return input
898
+ }
899
+
900
+ if (input is Number ) {
869
901
return input.toDouble()
870
902
}
871
- return input as ? Double
903
+
904
+ return null
872
905
}
873
906
874
907
private fun contains (targets : Any? , value : Any? , ignoreCase : Boolean ): Boolean {
875
908
if (targets == null || value == null ) {
876
909
return false
877
910
}
878
- var iterable: Iterable <* >
879
- if (targets is Iterable <* >) {
880
- iterable = targets
881
- } else if (targets is Array < * >) {
882
- iterable = targets.asIterable()
883
- } else {
884
- return false
885
- }
911
+ val iterable: Iterable <* > = when (targets) {
912
+ is Iterable <* > -> {
913
+ targets
914
+ }
915
+
916
+ is Array < * > -> {
917
+ targets.asIterable()
918
+ }
886
919
920
+ else -> {
921
+ return false
922
+ }
923
+ }
887
924
for (option in iterable) {
888
925
if ((option is String ) && (value is String ) && option.equals(value, ignoreCase)) {
889
926
return true
@@ -892,7 +929,6 @@ internal class Evaluator(
892
929
return true
893
930
}
894
931
}
895
-
896
932
return false
897
933
}
898
934
@@ -931,21 +967,9 @@ internal class Evaluator(
931
967
private fun browserVersionFromUserAgent (userAgent : String ): String {
932
968
val agent = uaParser.parseUserAgent(userAgent)
933
969
return arrayOf(
934
- if (agent.major.isNullOrBlank()) {
935
- " 0"
936
- } else {
937
- agent.major
938
- },
939
- if (agent.minor.isNullOrBlank()) {
940
- " 0"
941
- } else {
942
- agent.minor
943
- },
944
- if (agent.patch.isNullOrBlank()) {
945
- " 0"
946
- } else {
947
- agent.patch
948
- },
970
+ if (agent.major.isNullOrBlank()) " 0" else agent.major,
971
+ if (agent.minor.isNullOrBlank()) " 0" else agent.minor,
972
+ if (agent.patch.isNullOrBlank()) " 0" else agent.patch,
949
973
).joinToString(" ." )
950
974
}
951
975
0 commit comments