Create & Init Project...
This commit is contained in:
244
uuid/g.go
Normal file
244
uuid/g.go
Normal file
@ -0,0 +1,244 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Difference in 100-nanosecond intervals between
|
||||
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
|
||||
const epochStart = 122192928000000000
|
||||
|
||||
type epochFunc func() time.Time
|
||||
type hwAddrFunc func() (net.HardwareAddr, error)
|
||||
|
||||
var (
|
||||
global = newRFC4122Generator()
|
||||
|
||||
posixUID = uint32(os.Getuid())
|
||||
posixGID = uint32(os.Getgid())
|
||||
)
|
||||
|
||||
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||
func NewV1() (UUID, error) {
|
||||
return global.NewV1()
|
||||
}
|
||||
|
||||
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||
func NewV2(domain byte) (UUID, error) {
|
||||
return global.NewV2(domain)
|
||||
}
|
||||
|
||||
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||
func NewV3(ns UUID, name string) UUID {
|
||||
return global.NewV3(ns, name)
|
||||
}
|
||||
|
||||
// NewV4 returns random generated UUID.
|
||||
func NewV4() (UUID, error) {
|
||||
return global.NewV4()
|
||||
}
|
||||
|
||||
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||
func NewV5(ns UUID, name string) UUID {
|
||||
return global.NewV5(ns, name)
|
||||
}
|
||||
|
||||
// Generator provides interface for generating UUIDs.
|
||||
type Generator interface {
|
||||
NewV1() (UUID, error)
|
||||
NewV2(domain byte) (UUID, error)
|
||||
NewV3(ns UUID, name string) UUID
|
||||
NewV4() (UUID, error)
|
||||
NewV5(ns UUID, name string) UUID
|
||||
}
|
||||
|
||||
// Default generator implementation.
|
||||
type rfc4122Generator struct {
|
||||
clockSequenceOnce sync.Once
|
||||
hardwareAddrOnce sync.Once
|
||||
storageMutex sync.Mutex
|
||||
|
||||
rand io.Reader
|
||||
|
||||
epochFunc epochFunc
|
||||
hwAddrFunc hwAddrFunc
|
||||
lastTime uint64
|
||||
clockSequence uint16
|
||||
hardwareAddr [6]byte
|
||||
}
|
||||
|
||||
func newRFC4122Generator() Generator {
|
||||
return &rfc4122Generator{
|
||||
epochFunc: time.Now,
|
||||
hwAddrFunc: defaultHWAddrFunc,
|
||||
rand: rand.Reader,
|
||||
}
|
||||
}
|
||||
|
||||
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||
func (g *rfc4122Generator) NewV1() (UUID, error) {
|
||||
u := UUID{}
|
||||
|
||||
timeNow, clockSeq, err := g.getClockSequence()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
|
||||
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||
|
||||
hardwareAddr, err := g.getHardwareAddr()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u.SetVersion(V1)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||
func (g *rfc4122Generator) NewV2(domain byte) (UUID, error) {
|
||||
u, err := g.NewV1()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
switch domain {
|
||||
case DomainPerson:
|
||||
binary.BigEndian.PutUint32(u[:], posixUID)
|
||||
case DomainGroup:
|
||||
binary.BigEndian.PutUint32(u[:], posixGID)
|
||||
}
|
||||
|
||||
u[9] = domain
|
||||
|
||||
u.SetVersion(V2)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||
func (g *rfc4122Generator) NewV3(ns UUID, name string) UUID {
|
||||
u := newFromHash(md5.New(), ns, name)
|
||||
u.SetVersion(V3)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// NewV4 returns random generated UUID.
|
||||
func (g *rfc4122Generator) NewV4() (UUID, error) {
|
||||
u := UUID{}
|
||||
if _, err := g.rand.Read(u[:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
u.SetVersion(V4)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||
func (g *rfc4122Generator) NewV5(ns UUID, name string) UUID {
|
||||
u := newFromHash(sha1.New(), ns, name)
|
||||
u.SetVersion(V5)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// Returns epoch and clock sequence.
|
||||
func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
|
||||
var err error
|
||||
g.clockSequenceOnce.Do(func() {
|
||||
buf := make([]byte, 2)
|
||||
if _, err = g.rand.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
g.clockSequence = binary.BigEndian.Uint16(buf)
|
||||
})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
g.storageMutex.Lock()
|
||||
defer g.storageMutex.Unlock()
|
||||
|
||||
timeNow := g.getEpoch()
|
||||
// Clock didn't change since last UUID generation.
|
||||
// Should increase clock sequence.
|
||||
if timeNow <= g.lastTime {
|
||||
g.clockSequence++
|
||||
}
|
||||
g.lastTime = timeNow
|
||||
|
||||
return timeNow, g.clockSequence, nil
|
||||
}
|
||||
|
||||
// Returns hardware address.
|
||||
func (g *rfc4122Generator) getHardwareAddr() ([]byte, error) {
|
||||
var err error
|
||||
g.hardwareAddrOnce.Do(func() {
|
||||
if hwAddr, err := g.hwAddrFunc(); err == nil {
|
||||
copy(g.hardwareAddr[:], hwAddr)
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize hardwareAddr randomly in case
|
||||
// of real network interfaces absence.
|
||||
if _, err = g.rand.Read(g.hardwareAddr[:]); err != nil {
|
||||
return
|
||||
}
|
||||
// Set multicast bit as recommended by RFC 4122
|
||||
g.hardwareAddr[0] |= 0x01
|
||||
})
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return g.hardwareAddr[:], nil
|
||||
}
|
||||
|
||||
// Returns difference in 100-nanosecond intervals between
|
||||
// UUID epoch (October 15, 1582) and current time.
|
||||
func (g *rfc4122Generator) getEpoch() uint64 {
|
||||
return epochStart + uint64(g.epochFunc().UnixNano()/100)
|
||||
}
|
||||
|
||||
// Returns UUID based on hashing of namespace UUID and name.
|
||||
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
|
||||
u := UUID{}
|
||||
h.Write(ns[:])
|
||||
h.Write([]byte(name))
|
||||
copy(u[:], h.Sum(nil))
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// Returns hardware address.
|
||||
func defaultHWAddrFunc() (net.HardwareAddr, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if len(iface.HardwareAddr) >= 6 {
|
||||
return iface.HardwareAddr, nil
|
||||
}
|
||||
}
|
||||
return []byte{}, fmt.Errorf("uuid: no HW address found")
|
||||
}
|
129
uuid/uuid.go
Normal file
129
uuid/uuid.go
Normal file
@ -0,0 +1,129 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// Size of a UUID in bytes.
|
||||
const Size = 16
|
||||
|
||||
// UUID representation compliant with specification
|
||||
// described in RFC 4122.
|
||||
type UUID [Size]byte
|
||||
|
||||
// UUID versions
|
||||
const (
|
||||
_ byte = iota
|
||||
V1
|
||||
V2
|
||||
V3
|
||||
V4
|
||||
V5
|
||||
)
|
||||
|
||||
// UUID layout variants.
|
||||
const (
|
||||
VariantNCS byte = iota
|
||||
VariantRFC4122
|
||||
VariantMicrosoft
|
||||
VariantFuture
|
||||
)
|
||||
|
||||
// UUID DCE domains.
|
||||
const (
|
||||
DomainPerson = iota
|
||||
DomainGroup
|
||||
DomainOrg
|
||||
)
|
||||
|
||||
// String parse helpers.
|
||||
var (
|
||||
urnPrefix = []byte("urn:uuid:")
|
||||
byteGroups = []int{8, 4, 4, 4, 12}
|
||||
)
|
||||
|
||||
// Nil is special form of UUID that is specified to have all
|
||||
// 128 bits set to zero.
|
||||
var Nil = UUID{}
|
||||
|
||||
// Equal returns true if u1 and u2 equals, otherwise returns false.
|
||||
func Equal(u1 UUID, u2 UUID) bool {
|
||||
return bytes.Equal(u1[:], u2[:])
|
||||
}
|
||||
|
||||
// Version returns algorithm version used to generate UUID.
|
||||
func (u UUID) Version() byte {
|
||||
return u[6] >> 4
|
||||
}
|
||||
|
||||
// Variant returns UUID layout variant.
|
||||
func (u UUID) Variant() byte {
|
||||
switch {
|
||||
case (u[8] >> 7) == 0x00:
|
||||
return VariantNCS
|
||||
case (u[8] >> 6) == 0x02:
|
||||
return VariantRFC4122
|
||||
case (u[8] >> 5) == 0x06:
|
||||
return VariantMicrosoft
|
||||
case (u[8] >> 5) == 0x07:
|
||||
fallthrough
|
||||
default:
|
||||
return VariantFuture
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns bytes slice representation of UUID.
|
||||
func (u UUID) Bytes() []byte {
|
||||
return u[:]
|
||||
}
|
||||
|
||||
// Returns canonical string representation of UUID:
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (u UUID) String() string {
|
||||
buf := make([]byte, 36)
|
||||
|
||||
hex.Encode(buf[0:8], u[0:4])
|
||||
buf[8] = '-'
|
||||
hex.Encode(buf[9:13], u[4:6])
|
||||
buf[13] = '-'
|
||||
hex.Encode(buf[14:18], u[6:8])
|
||||
buf[18] = '-'
|
||||
hex.Encode(buf[19:23], u[8:10])
|
||||
buf[23] = '-'
|
||||
hex.Encode(buf[24:], u[10:])
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// SetVersion sets version bits.
|
||||
func (u *UUID) SetVersion(v byte) {
|
||||
u[6] = (u[6] & 0x0f) | (v << 4)
|
||||
}
|
||||
|
||||
// SetVariant sets variant bits.
|
||||
func (u *UUID) SetVariant(v byte) {
|
||||
switch v {
|
||||
case VariantNCS:
|
||||
u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
|
||||
case VariantRFC4122:
|
||||
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
|
||||
case VariantMicrosoft:
|
||||
u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
|
||||
case VariantFuture:
|
||||
fallthrough
|
||||
default:
|
||||
u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
|
||||
}
|
||||
}
|
||||
|
||||
// Must is a helper that wraps a call to a function returning (UUID, error)
|
||||
// and panics if the error is non-nil. It is intended for use in variable
|
||||
// initializations such as
|
||||
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
|
||||
func Must(u UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
Reference in New Issue
Block a user