github.com/aavshr/aws-sdk-go@v1.41.3/private/protocol/idempotency.go (about) 1 package protocol 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "reflect" 7 ) 8 9 // RandReader is the random reader the protocol package will use to read 10 // random bytes from. This is exported for testing, and should not be used. 11 var RandReader = rand.Reader 12 13 const idempotencyTokenFillTag = `idempotencyToken` 14 15 // CanSetIdempotencyToken returns true if the struct field should be 16 // automatically populated with a Idempotency token. 17 // 18 // Only *string and string type fields that are tagged with idempotencyToken 19 // which are not already set can be auto filled. 20 func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool { 21 switch u := v.Interface().(type) { 22 // To auto fill an Idempotency token the field must be a string, 23 // tagged for auto fill, and have a zero value. 24 case *string: 25 return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 26 case string: 27 return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0 28 } 29 30 return false 31 } 32 33 // GetIdempotencyToken returns a randomly generated idempotency token. 34 func GetIdempotencyToken() string { 35 b := make([]byte, 16) 36 RandReader.Read(b) 37 38 return UUIDVersion4(b) 39 } 40 41 // SetIdempotencyToken will set the value provided with a Idempotency Token. 42 // Given that the value can be set. Will panic if value is not setable. 43 func SetIdempotencyToken(v reflect.Value) { 44 if v.Kind() == reflect.Ptr { 45 if v.IsNil() && v.CanSet() { 46 v.Set(reflect.New(v.Type().Elem())) 47 } 48 v = v.Elem() 49 } 50 v = reflect.Indirect(v) 51 52 if !v.CanSet() { 53 panic(fmt.Sprintf("unable to set idempotnecy token %v", v)) 54 } 55 56 b := make([]byte, 16) 57 _, err := rand.Read(b) 58 if err != nil { 59 // TODO handle error 60 return 61 } 62 63 v.Set(reflect.ValueOf(UUIDVersion4(b))) 64 } 65 66 // UUIDVersion4 returns a Version 4 random UUID from the byte slice provided 67 func UUIDVersion4(u []byte) string { 68 // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29 69 // 13th character is "4" 70 u[6] = (u[6] | 0x40) & 0x4F 71 // 17th character is "8", "9", "a", or "b" 72 u[8] = (u[8] | 0x80) & 0xBF 73 74 return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) 75 }