|
|
- package uuid
-
- /***************
- * Date: 14/02/14
- * Time: 7:44 PM
- ***************/
-
- import (
- "crypto/md5"
- "crypto/rand"
- "crypto/sha1"
- "encoding/binary"
- "log"
- seed "math/rand"
- "net"
- )
-
- const (
- length = 16
-
- // 3F used by RFC4122 although 1F works for all
- variantSet = 0x3F
-
- // rather than using 0xC0 we use 0xE0 to retrieve the variant
- // The result is the same for all other variants
- // 0x80 and 0xA0 are used to identify RFC4122 compliance
- variantGet = 0xE0
- )
-
- var (
- // nodeID is the default Namespace node
- nodeId = []byte{
- // 00.192.79.212.48.200
- 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
- }
- // The following standard UUIDs are for use with V3 or V5 UUIDs.
- NamespaceDNS = &Struct{0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
- NamespaceURL = &Struct{0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
- NamespaceOID = &Struct{0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
- NamespaceX500 = &Struct{0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
-
- state State
- )
-
- func init() {
- seed.Seed((int64(timestamp())^int64(gregorianToUNIXOffset))*0x6ba7b814<<0x6ba7b812 | 1391463463)
- state = State{
- randomNode: true,
- randomSequence: true,
- past: Timestamp((1391463463 * 10000000) + (100 * 10) + gregorianToUNIXOffset),
- node: nodeId,
- sequence: uint16(seed.Int()) & 0x3FFF,
- saver: nil,
- }
- }
-
- // NewV1 will generate a new RFC4122 version 1 UUID
- func NewV1() UUID {
- state.Lock()
- defer state.Unlock()
- now := currentUUIDTimestamp()
- state.read(now, currentUUIDNodeId())
- state.persist()
- return formatV1(now, uint16(1), ReservedRFC4122, state.node)
- }
-
- // NewV3 will generate a new RFC4122 version 3 UUID
- // V3 is based on the MD5 hash of a namespace identifier UUID and
- // any type which implements the UniqueName interface for the name.
- // For strings and slices cast to a Name type
- func NewV3(pNs UUID, pName UniqueName) UUID {
- o := new(Array)
- // Set all bits to MD5 hash generated from namespace and name.
- Digest(o, pNs, pName, md5.New())
- o.setRFC4122Variant()
- o.setVersion(3)
- return o
- }
-
- // NewV4 will generate a new RFC4122 version 4 UUID
- // A cryptographically secure random UUID.
- func NewV4() UUID {
- o := new(Array)
- // Read random values (or pseudo-randomly) into Array type.
- _, err := rand.Read(o[:length])
- if err != nil {
- panic(err)
- }
- o.setRFC4122Variant()
- o.setVersion(4)
- return o
- }
-
- // NewV5 will generate a new RFC4122 version 5 UUID
- // Generate a UUID based on the SHA-1 hash of a namespace
- // identifier and a name.
- func NewV5(pNs UUID, pName UniqueName) UUID {
- o := new(Array)
- Digest(o, pNs, pName, sha1.New())
- o.setRFC4122Variant()
- o.setVersion(5)
- return o
- }
-
- // either generates a random node when there is an error or gets
- // the pre initialised one
- func currentUUIDNodeId() (node net.HardwareAddr) {
- if state.randomNode {
- b := make([]byte, 16+6)
- _, err := rand.Read(b)
- if err != nil {
- log.Println("UUID.currentUUIDNodeId error:", err)
- node = nodeId
- return
- }
- h := sha1.New()
- h.Write(b)
- binary.Write(h, binary.LittleEndian, state.sequence)
- node = h.Sum(nil)[:6]
- if err != nil {
- log.Println("UUID.currentUUIDNodeId error:", err)
- node = nodeId
- return
- }
- // Mark as randomly generated
- node[0] |= 0x01
- } else {
- node = state.node
- }
- return
- }
-
- // Unmarshal data into struct for V1 UUIDs
- func formatV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode []byte) UUID {
- o := new(Struct)
- o.timeLow = uint32(pNow & 0xFFFFFFFF)
- o.timeMid = uint16((pNow >> 32) & 0xFFFF)
- o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF)
- o.timeHiAndVersion |= uint16(pVersion << 12)
- o.sequenceLow = byte(state.sequence & 0xFF)
- o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8)
- o.sequenceHiAndVariant |= pVariant
- o.node = pNode
- o.size = length
- return o
- }
|