-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathLayer.kt
More file actions
177 lines (159 loc) · 6.42 KB
/
Copy pathLayer.kt
File metadata and controls
177 lines (159 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package com.statsig.sdk
typealias OnLayerExposure = (layerExposureEventData: LayerExposureEventData) -> Unit
internal typealias OnLayerExposureInternal = (layer: Layer, parameterName: String) -> Unit
/**
* A helper class for interfacing with Layers defined in the Statsig console
*/
class Layer internal constructor(
val name: String,
val ruleID: String? = null,
val groupName: String? = null,
val value: Map<String, Any>,
val secondaryExposures: ArrayList<Map<String, String>> = arrayListOf(),
val allocatedExperiment: String? = null,
val evaluationDetails: EvaluationDetails? = null,
private val onExposure: OnLayerExposureInternal? = null,
) {
companion object {
fun empty(name: String): Layer {
return Layer(name, null, null, mapOf())
}
}
/**
* Gets a value from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getString(key: String, default: String?): String? {
return get(key, default, value)
}
/**
* Gets a value from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getBoolean(key: String, default: Boolean): Boolean {
return get(key, default, value)
}
/**
* Gets a value from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getDouble(key: String, default: Double): Double {
return get<Number>(key, default, value).toDouble()
}
/**
* Gets a value from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getInt(key: String, default: Int): Int {
return get<Number>(key, default, value).toInt()
}
/**
* Gets a value from the layer, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getLong(key: String, default: Long): Long {
return get<Number>(key, default, value).toLong()
}
/**
* Gets a value from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a value from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getArray(key: String, default: Array<*>?): Array<*>? {
var res = value[key] as? Array<*>
if (res == null) {
res = (value[key] as? ArrayList<*>)?.toTypedArray()
}
if (res != null) {
logParameterExposure(key)
}
return res ?: default
}
/**
* Gets a dictionary from the config, falling back to the provided default value
* @param key the index within the Layer to fetch a dictionary from
* @param default the default value to return if the expected key does not exist in the config
* @return the value at the given key, or the default value if not found
*/
fun getDictionary(key: String, default: Map<String, Any>?): Map<String, Any>? {
return get(key, default, value)
}
/**
* Gets a value from the config as a new DynamicConfig, or null if not found
* @param key the index within the Layer to fetch a value from
* @return the value at the given key as a DynamicConfig, or null
*/
fun getConfig(key: String): DynamicConfig? {
return when (val value = get(key, null as Map<String, Any>?, value)) {
is Map<String, Any> -> DynamicConfig(
key,
value,
this.ruleID,
this.groupName,
)
else -> null
}
}
/**
* Legacy exposure data at the layer level. Should NOT be used in new code as this will cause over exposure.
*/
fun getLegacyExposureMetadata(): String {
return Utils.PLAIN_GSON.toJson(
mapOf(
"config" to this.name,
"ruleID" to this.ruleID,
"secondaryExposures" to this.secondaryExposures,
"allocatedExperiment" to this.allocatedExperiment,
),
)
}
private fun logParameterExposure(key: String) {
onExposure?.let {
it(this, key)
}
}
/**
* We should not just expose this function as inline reified is copied to every place it is used.
*/
private inline fun <reified T> get(key: String, default: T, jsonValue: Map<String, Any>): T {
val value = jsonValue[key] as? T
if (value != null) {
logParameterExposure(key)
}
return value ?: default
}
}
internal fun createLayerExposureMetadata(
layer: Layer,
parameterName: String,
configEvaluation: ConfigEvaluation,
): LayerExposureMetadata {
var allocatedExperiment = ""
var exposures = configEvaluation.undelegatedSecondaryExposures
val isExplicit = configEvaluation.explicitParameters?.contains(parameterName) ?: false
if (isExplicit) {
exposures = configEvaluation.secondaryExposures
allocatedExperiment = configEvaluation.configDelegate ?: ""
}
return LayerExposureMetadata(
layer.name,
layer.ruleID ?: "",
allocatedExperiment,
parameterName,
isExplicit.toString(),
exposures,
evaluationDetails = configEvaluation.evaluationDetails,
configVersion = configEvaluation.configVersion,
)
}