Skip to content

Commit

Permalink
#3 updated uuid by replacing seed method of rand as it deprecated sin…
Browse files Browse the repository at this point in the history
…ce 1.20 of go
  • Loading branch information
Krishnakant C authored and Krishnakant C committed Sep 6, 2024
1 parent cef0d48 commit 5b1379a
Showing 1 changed file with 130 additions and 17 deletions.
147 changes: 130 additions & 17 deletions internal/client/common/uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,89 @@ import (
"fmt"
"math/rand"
"time"

"github.com/google/uuid"
)

// Constants
const (
// Base64 encoded UUID length without padding
// Base64UUIDLength is the length of a base64 encoded UUID without padding.
base64UUIDLength = 22
// UUID size in bytes
// UUIDSize is the size of a UUID in bytes.
uuidSize = 16
)

// Uuid represents a 128-bit UUID
// Uuid represents a 128-bit UUID.
type Uuid struct {
mostSignificantBits int64
leastSignificantBits int64
mostSignificantBits int64 // Most significant 64 bits of the UUID
leastSignificantBits int64 // Least significant 64 bits of the UUID
}

// Predefined reserved UUIDs
var (
OneUUID = NewUuid(0, 1)
// OneUUID is a predefined UUID with most significant bits 0 and least significant bits 1.
OneUUID = NewUuid(0, 1)
// MetadataTopicID is an alias for OneUUID.
MetadataTopicID = OneUUID
ZeroUUID = NewUuid(0, 0)
Reserved = map[Uuid]struct{}{
// ZeroUUID is a predefined UUID with both most and least significant bits set to 0.
ZeroUUID = NewUuid(0, 0)
// Reserved contains a set of predefined reserved UUIDs.
Reserved = map[Uuid]struct{}{
OneUUID: {},
MetadataTopicID: {},
ZeroUUID: {},
}
)

// NewUuid creates a new Uuid from the provided 64-bit parts.
//
// Parameters:
// - mostSigBits: The most significant 64 bits of the UUID.
// - leastSigBits: The least significant 64 bits of the UUID.
//
// Returns:
// - A new Uuid instance representing the combined 128-bit UUID.
//
// Example:
//
// u := NewUuid(0x123456789abcdef0, 0xfedcba9876543210)
// fmt.Println(u.String()) // Output: Base64 encoded UUID
func NewUuid(mostSigBits, leastSigBits int64) Uuid {
return Uuid{
mostSignificantBits: mostSigBits,
leastSignificantBits: leastSigBits,
}
}

// RandomUuid generates a random UUID and ensures it is not in the Reserved set and doesn't start with a dash in its Base64 representation.
// RandomUuid generates a random UUID and ensures it is not in the Reserved set
// and doesn't start with a dash in its Base64 representation.
//
// Returns:
// - A randomly generated Uuid that is not reserved and does not start with a dash.
//
// Example:
//
// randomUUID := RandomUuid()
// fmt.Println(randomUUID.String()) // Output: Random Base64 encoded UUID
func RandomUuid() Uuid {
rand.Seed(time.Now().UnixNano())
// Create a new random source seeded with the current time
source := rand.NewSource(time.Now().UnixNano())
random := rand.New(source)

for {
u := unsafeRandomUuid()
u := unsafeRandomUuid(random)
if _, reserved := Reserved[u]; !reserved && !startsWithDash(u.String()) {
return u
}
}
}

// unsafeRandomUuid generates a UUID using the google/uuid package.
func unsafeRandomUuid() Uuid {
gUUID := uuid.New()
b := gUUID[:]
// unsafeRandomUuid generates a UUID using the google/uuid package with a custom random source.
// It does not check for reserved UUIDs or dash prefixes.
func unsafeRandomUuid(r *rand.Rand) Uuid {
// Generate 16 random bytes
b := make([]byte, uuidSize)
r.Read(b)

// Construct UUID from bytes
return NewUuid(
int64(b[0])<<56|int64(b[1])<<48|int64(b[2])<<40|int64(b[3])<<32|
int64(b[4])<<24|int64(b[5])<<16|int64(b[6])<<8|int64(b[7]),
Expand All @@ -68,17 +98,51 @@ func unsafeRandomUuid() Uuid {
}

// startsWithDash checks if the Base64 encoded UUID string starts with a dash.
//
// Parameters:
// - s: The Base64 encoded UUID string to check.
//
// Returns:
// - true if the string starts with a dash, false otherwise.
//
// Example:
//
// fmt.Println(startsWithDash("-abc")) // Output: true
// fmt.Println(startsWithDash("abc")) // Output: false
func startsWithDash(s string) bool {
return len(s) > 0 && s[0] == '-'
}

// String returns the Base64 encoded representation of the UUID.
//
// Returns:
// - A string representing the UUID in Base64 format.
//
// Example:
//
// u := NewUuid(0x123456789abcdef0, 0xfedcba9876543210)
// fmt.Println(u.String()) // Output: Base64 encoded UUID
func (u Uuid) String() string {
b := u.getBytes()
return base64.RawURLEncoding.EncodeToString(b)
}

// FromString creates a UUID from its Base64 encoded string representation.
//
// Parameters:
// - s: The Base64 encoded string representation of the UUID.
//
// Returns:
// - A Uuid instance if the string is valid, or an error if the string is invalid.
//
// Example:
//
// u, err := FromString("0Aw-Aw0AQNaAQNaAQNaAQNaAQ")
// if err != nil {
// fmt.Println("Error:", err)
// } else {
// fmt.Println(u) // Output: {0 1}
// }
func FromString(s string) (Uuid, error) {
if len(s) > base64UUIDLength {
return Uuid{}, errors.New("input string is too long to be decoded as a base64 UUID")
Expand All @@ -101,6 +165,16 @@ func FromString(s string) (Uuid, error) {
}, nil
}

// getBytes converts the UUID to a byte slice representation.
//
// Returns:
// - A byte slice representing the UUID.
//
// Example:
//
// u := NewUuid(0x123456789abcdef0, 0xfedcba9876543210)
// bytes := u.getBytes()
// fmt.Println(bytes) // Output: [byte representation of the UUID]
func (u Uuid) getBytes() []byte {
b := make([]byte, uuidSize)
copy(b[0:8], []byte{
Expand All @@ -127,6 +201,21 @@ func (u Uuid) getBytes() []byte {
}

// Compare compares two UUIDs lexicographically.
//
// Parameters:
// - other: The other Uuid to compare against.
//
// Returns:
// - 1 if the current UUID is greater than the other,
// - -1 if the current UUID is less than the other,
// - 0 if they are equal.
//
// Example:
//
// u1 := NewUuid(0x123456789abcdef0, 0xfedcba9876543210)
// u2 := NewUuid(0x123456789abcdef0, 0xfedcba9876543211)
// result := u1.Compare(u2)
// fmt.Println(result) // Output: -1 (u1 is less than u2)
func (u Uuid) Compare(other Uuid) int {
if u.mostSignificantBits > other.mostSignificantBits {
return 1
Expand All @@ -144,6 +233,18 @@ func (u Uuid) Compare(other Uuid) int {
}

// ToArray converts a slice of Uuid to an array of [2]int64.
//
// Parameters:
// - slice: A slice of Uuid instances to convert.
//
// Returns:
// - An array of [2]int64 where each element contains the most and least significant bits of the UUID.
//
// Example:
//
// uuids := []Uuid{NewUuid(0, 1), NewUuid(0, 2)}
// arr := ToArray(uuids)
// fmt.Println(arr) // Output: [[0 1] [0 2]]
func ToArray(slice []Uuid) [][2]int64 {
arr := make([][2]int64, len(slice))
for i, u := range slice {
Expand All @@ -153,6 +254,18 @@ func ToArray(slice []Uuid) [][2]int64 {
}

// ToList converts an array of [2]int64 to a slice of Uuid.
//
// Parameters:
// - arr: An array of [2]int64 to convert.
//
// Returns:
// - A slice of Uuid instances created from the provided array.
//
// Example:
//
// arr := [][2]int64{{0, 1}, {0, 2}}
// uuids := ToList(arr)
// fmt.Println(uuids[0].String()) // Output: Base64 encoded UUID of {0 1}
func ToList(arr [][2]int64) []Uuid {
slice := make([]Uuid, len(arr))
for i, v := range arr {
Expand Down

0 comments on commit 5b1379a

Please sign in to comment.