feature
2015-03-16
feature/flag.go
First pass at an implementation. Implement the calculation to determine whether a string is included in the partition or not, using crc32 to coerce the string to an evenly distributed uint32, and a modulo to turn it into a percentage. Implement a store to keep track of available flags and the level of the partition for each flag. Implement an API to retrieve, create, and modify these available flags.
| paddy@0 | 1 package feature |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "hash/crc32" |
| paddy@0 | 5 "log" |
| paddy@0 | 6 ) |
| paddy@0 | 7 |
| paddy@0 | 8 type Flag struct { |
| paddy@0 | 9 ID string |
| paddy@0 | 10 Limit int |
| paddy@0 | 11 } |
| paddy@0 | 12 |
| paddy@0 | 13 func (f Flag) calcOffset() int { |
| paddy@0 | 14 return calcValue(f.ID) |
| paddy@0 | 15 } |
| paddy@0 | 16 |
| paddy@0 | 17 func (f Flag) Permit(candidate string) bool { |
| paddy@0 | 18 if f.Limit >= 100 { |
| paddy@0 | 19 return true |
| paddy@0 | 20 } |
| paddy@0 | 21 if f.Limit <= 0 { |
| paddy@0 | 22 return false |
| paddy@0 | 23 } |
| paddy@0 | 24 return (calcValue(candidate)+f.calcOffset())%100 <= f.Limit |
| paddy@0 | 25 } |
| paddy@0 | 26 |
| paddy@0 | 27 type FlagSet struct { |
| paddy@0 | 28 flags map[string]bool |
| paddy@0 | 29 } |
| paddy@0 | 30 |
| paddy@0 | 31 func (set FlagSet) Check(flag string) bool { |
| paddy@0 | 32 pass, ok := set.flags[flag] |
| paddy@0 | 33 if !ok { |
| paddy@0 | 34 log.Println("Checked for flag that wasn't in response:", flag) |
| paddy@0 | 35 pass = false |
| paddy@0 | 36 } |
| paddy@0 | 37 return pass |
| paddy@0 | 38 } |
| paddy@0 | 39 |
| paddy@0 | 40 func calcValue(in string) int { |
| paddy@0 | 41 return int(crc32.ChecksumIEEE([]byte(in)) % 100) |
| paddy@0 | 42 } |
| paddy@0 | 43 |
| paddy@0 | 44 /* |
| paddy@0 | 45 |
| paddy@0 | 46 Client has one function: |
| paddy@0 | 47 |
| paddy@0 | 48 1. func (c Client) Load(in string) FlagSet -- loads the flagset with "in" as the parameter to gate on |
| paddy@0 | 49 |
| paddy@0 | 50 // TODO Have the client cache FlagSets in memory by the parameter being gated on; we can reuse FlagSets for a minute or two |
| paddy@0 | 51 |
| paddy@0 | 52 */ |