123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- package protocol
- import (
- "crypto/rand"
- "fmt"
- "reflect"
- )
- // RandReader is the random reader the protocol package will use to read
- // random bytes from. This is exported for testing, and should not be used.
- var RandReader = rand.Reader
- const idempotencyTokenFillTag = `idempotencyToken`
- // CanSetIdempotencyToken returns true if the struct field should be
- // automatically populated with a Idempotency token.
- //
- // Only *string and string type fields that are tagged with idempotencyToken
- // which are not already set can be auto filled.
- func CanSetIdempotencyToken(v reflect.Value, f reflect.StructField) bool {
- switch u := v.Interface().(type) {
- // To auto fill an Idempotency token the field must be a string,
- // tagged for auto fill, and have a zero value.
- case *string:
- return u == nil && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
- case string:
- return len(u) == 0 && len(f.Tag.Get(idempotencyTokenFillTag)) != 0
- }
- return false
- }
- // GetIdempotencyToken returns a randomly generated idempotency token.
- func GetIdempotencyToken() string {
- b := make([]byte, 16)
- RandReader.Read(b)
- return UUIDVersion4(b)
- }
- // SetIdempotencyToken will set the value provided with a Idempotency Token.
- // Given that the value can be set. Will panic if value is not setable.
- func SetIdempotencyToken(v reflect.Value) {
- if v.Kind() == reflect.Ptr {
- if v.IsNil() && v.CanSet() {
- v.Set(reflect.New(v.Type().Elem()))
- }
- v = v.Elem()
- }
- v = reflect.Indirect(v)
- if !v.CanSet() {
- panic(fmt.Sprintf("unable to set idempotnecy token %v", v))
- }
- b := make([]byte, 16)
- _, err := rand.Read(b)
- if err != nil {
- // TODO handle error
- return
- }
- v.Set(reflect.ValueOf(UUIDVersion4(b)))
- }
- // UUIDVersion4 returns a Version 4 random UUID from the byte slice provided
- func UUIDVersion4(u []byte) string {
- // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
- // 13th character is "4"
- u[6] = (u[6] | 0x40) & 0x4F
- // 17th character is "8", "9", "a", or "b"
- u[8] = (u[8] | 0x80) & 0xBF
- return fmt.Sprintf(`%X-%X-%X-%X-%X`, u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
- }
|