Files
go-trustlog/internal/helpers/uuid.go

67 lines
1.9 KiB
Go
Raw Permalink Normal View History

package helpers
import (
"crypto/rand"
"encoding/binary"
"fmt"
"time"
)
const (
// UUID v7 格式常量.
uuidRandomBytesSize = 10 // UUID中随机字节部分的大小
uuidVersion7 = 0x7000 // UUID v7的版本位
uuidVariant = 0x80 // UUID的变体位
uuidTimeMask = 0xFFFF // 时间戳掩码
uuidTimeShift = 16 // 时间戳位移
uuidVariantMask = 0x3F // 变体掩码
)
// NewUUIDv7 生成 UUID v7 并去除连字符.
func NewUUIDv7() string {
// 获取当前时间戳Unix 毫秒时间戳)
now := time.Now().UnixMilli()
// 生成随机字节
randBytes := make([]byte, uuidRandomBytesSize)
_, err := rand.Read(randBytes)
if err != nil {
// 如果随机数生成失败,使用时间戳加一些伪随机值作为备选方案
return fmt.Sprintf("%016x%016x", now, time.Now().UnixNano())
}
// 版本和变体位
// 版本: 0x7 (0111) << 12
// 变体: 0x2 (10) << 6
versionVariant := uint16(uuidVersion7 | uuidVariant)
// 构建 UUID 字节数组
var uuid [16]byte
// 时间戳低32位 (4 bytes)
//nolint:gosec // UUID格式要求的类型转换
binary.BigEndian.PutUint32(uuid[0:4], uint32(now>>uuidTimeShift))
// 时间戳中16位 + 版本 (2 bytes)
//nolint:gosec // UUID格式要求的类型转换
binary.BigEndian.PutUint16(uuid[4:6], uint16(now&uuidTimeMask))
// 时间戳高16位 + 变体 (2 bytes)
binary.BigEndian.PutUint16(uuid[6:8], versionVariant)
// 随机数部分 (8 bytes)
copy(uuid[8:16], randBytes[:8])
// 设置变体位 (第8个字节的高两位为10)
uuid[8] = (uuid[8] & uuidVariantMask) | uuidVariant
// 转换为十六进制字符串并去除连字符
return fmt.Sprintf("%08x%04x%04x%04x%08x%04x",
binary.BigEndian.Uint32(uuid[0:4]),
binary.BigEndian.Uint16(uuid[4:6]),
binary.BigEndian.Uint16(uuid[6:8]),
binary.BigEndian.Uint16(uuid[8:10]),
binary.BigEndian.Uint32(uuid[10:14]),
binary.BigEndian.Uint16(uuid[14:16]))
}