|
| 1 | +package optimizely |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "hash/fnv" |
| 6 | + "math" |
| 7 | +) |
| 8 | + |
| 9 | +var BUCKETING_ID_TEMPLATE = "{%v}{%v}" |
| 10 | +var MAX_HASH_VALUE = math.Exp2(32) |
| 11 | + |
| 12 | +// generate_bucket_value generates an unit32 value for a bucket |
| 13 | +func generate_bucket_value(bucketing_id string) uint32 { |
| 14 | + h := fnv.New32a() |
| 15 | + bucket_slice := []byte(bucketing_id) |
| 16 | + h.Write(bucket_slice) |
| 17 | + return h.Sum32() |
| 18 | +} |
| 19 | + |
| 20 | +// Given an experiment key, returns the traffic allocation within that experiment |
| 21 | +// experiment_key: key of experiment |
| 22 | +// experiments: array of ExperimentEntities |
| 23 | +// Returns: pointer to array of TrafficAllocationEntities |
| 24 | +func get_traffic_allocations(experiment_key string, experiments []ExperimentEntity) []TrafficAllocationEntity { |
| 25 | + for i := 0; i < len(experiments); i++ { |
| 26 | + if experiments[i].Key == experiment_key { // Id or Key? |
| 27 | + return experiments[i].TrafficAllocation |
| 28 | + } |
| 29 | + } |
| 30 | + return nil |
| 31 | +} |
| 32 | + |
| 33 | +// Bucket determines for a given experiment key and bucketing ID determines ID of variation to be shown to visitor. |
| 34 | +// experiment_key: Key representing experiment for which visitor is to be bucketed. |
| 35 | +// user_id: ID for user. |
| 36 | +// Returns: Variation ID for variation in which the visitor with ID user_id will be put in |
| 37 | +// If no variation, return empty string (TODO: move to error) |
| 38 | +func (client *OptimizelyClient) Bucket(experiment_key string, user_id string) string { |
| 39 | + var experiment_id = "" |
| 40 | + for j := 0; j < len(client.project_config.Experiments); j++ { |
| 41 | + if client.project_config.Experiments[j].Key == experiment_id { |
| 42 | + experiment_id = client.project_config.Experiments[j].Id |
| 43 | + } |
| 44 | + } |
| 45 | + var bucketing_id = fmt.Sprintf(BUCKETING_ID_TEMPLATE, user_id, experiment_id) |
| 46 | + var bucketing_number = generate_bucket_value(bucketing_id) |
| 47 | + var traffic_allocations = get_traffic_allocations(experiment_key, client.project_config.Experiments) |
| 48 | + for i := 0; i < len(traffic_allocations); i++ { |
| 49 | + current_end_of_range := traffic_allocations[i].EndOfRange |
| 50 | + if bucketing_number <= uint32(current_end_of_range) { |
| 51 | + return traffic_allocations[i].EntityId |
| 52 | + } |
| 53 | + } |
| 54 | + return "" |
| 55 | + |
| 56 | +} |
0 commit comments