Skip to content

Instantly share code, notes, and snippets.

@wdshin
Created August 13, 2018 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wdshin/e80521a92b265c195c6da90dc05b5585 to your computer and use it in GitHub Desktop.
Save wdshin/e80521a92b265c195c6da90dc05b5585 to your computer and use it in GitHub Desktop.
package common
import (
"net"
"github.com/labstack/gommon/log"
"io"
"crypto/rand"
"time"
"sync/atomic"
"encoding/binary"
"strconv"
)
// UUID 64Bit using Timestamp(32Bit) + HostID(16Bit) + sequence(16Bit)
// ascending by timestamp
type UUID64 uint64
// these variables should be set outside this package
var UUID64MyHostID uint16 = 1
var UUID64MyHostSeq uint8 = 3
var hardwareAddr []byte
var clockSeq uint32
var clockSeq16 uint32
var MyHostIPV4 net.IP
var MyHostIPV4Bytes []byte
var MyHostIPV4Last2Bytes [2]byte
func getMyHostIPV4() (net.IP) {
netInterfaceAddresses, err := net.InterfaceAddrs()
if err != nil { return nil }
for _, netInterfaceAddress := range netInterfaceAddresses {
networkIp, ok := netInterfaceAddress.(*net.IPNet)
if ok && !networkIp.IP.IsLoopback() && networkIp.IP.To4() != nil {
ip := networkIp.IP
//log.Info().Msg("Resolved Host IP: " + ip.String())
return ip
}
}
return nil
}
func InitUUID() {
log.Print("common.InitUUID")
if interfaces, err := net.Interfaces(); err == nil {
for _, i := range interfaces {
if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
hardwareAddr = i.HardwareAddr
break
}
}
}
if hardwareAddr == nil {
// If we failed to obtain the MAC address of the current computer,
// we will use a randomly generated 6 byte sequence instead and set
// the multicast bit as recommended in RFC 4122.
hardwareAddr = make([]byte, 6)
_, err := io.ReadFull(rand.Reader, hardwareAddr)
if err != nil {
panic(err)
}
hardwareAddr[0] = hardwareAddr[0] | 0x01
}
MyHostIPV4 = getMyHostIPV4()
MyHostIPV4Bytes = MyHostIPV4.To4()
MyHostIPV4Last2Bytes[0] = MyHostIPV4Bytes[2]
MyHostIPV4Last2Bytes[1] = MyHostIPV4Bytes[3]
// initialize the clock sequence with a random number
var clockSeqRand [2]byte
io.ReadFull(rand.Reader, clockSeqRand[:])
clockSeq = uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0])
clockSeq16 = 0
//uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0])
}
var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
func UUID64FromTimeHostID(aTime time.Time) UUID64 {
utcTime := aTime.In(time.UTC)
t := int32(utcTime.Unix())
//t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100)
clock16 := atomic.AddUint32(&clockSeq16, 1)
//log.Print("clock16 : ",clock16)
return TimeUUIDWithHostID(t, uint16(clock16))
}
func TimeUUIDWithHostID(t int32, clock uint16) UUID64 {
u := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
// unix time stamp
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
// clock sequence ( 16 bit )
u[4] = byte(clock )
u[5] = byte(clock >> 8 )
//log.Print("t : ",t , " clock : ",clock, " MyHostSeq: ", UUID64MyHostSeq , " u[4]:", u[4], " u[5]:", u[5])
// host id( 8+6 bit )
// host seq ( 2 bit )
u[6] = byte(UUID64MyHostID >> 8) << 2 | ( byte(UUID64MyHostSeq) & 0x03 )
u[7] = byte(UUID64MyHostID)
//log.Print("UUID64MyHostID:",UUID64MyHostID ," u[6]:", u[6], " u[7]:", u[7])
var u64 uint64
u64 = binary.LittleEndian.Uint64(u)
return UUID64(u64)
}
func UUID64FromTimeHostIDParam(aTime time.Time,hostID uint16,hostSeq uint8) UUID64 {
utcTime := aTime.In(time.UTC)
t := int32(utcTime.Unix())
//t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100)
clock16 := atomic.AddUint32(&clockSeq16, 1)
//log.Print("clock16 : ",clock16)
return TimeUUIDWithHostIDParam(t, uint16(clock16),hostID,hostSeq)
}
func TimeUUIDWithHostIDParam(t int32, clock uint16,hostID uint16,hostSeq uint8) UUID64 {
u := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
u[4] = byte(clock )
u[5] = byte(clock >> 8 )
//log.Print("t : ",t , " clock : ",clock, " MyHostSeq: ", UUID64MyHostSeq , " u[4]:", u[4], " u[5]:", u[5])
u[6] = byte(hostID >> 8) << 2 | ( byte(hostSeq) & 0x03 )
u[7] = byte(hostID)
//log.Print("UUID64MyHostID:",UUID64MyHostID ," u[6]:", u[6], " u[7]:", u[7])
var u64 uint64
u64 = binary.LittleEndian.Uint64(u)
return UUID64(u64)
}
func UUID64FromTimeHostIPV2(aTime time.Time) UUID64 {
utcTime := aTime.In(time.UTC)
t := int32(utcTime.Unix())
//t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100)
clock16 := atomic.AddUint32(&clockSeq16, 1)
//log.Print("clock16 : ",clock16)
return TimeUUIDWithHostIPV2(t, uint16(clock16))
}
func TimeUUIDWithHostIPV2(t int32, clock uint16) UUID64 {
u := []byte{0x00, 0x01, 0x08, 0x00, 0x08, 0x01, 0xab, 0x01}
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
//u[4], u[5] = byte(t>>40), byte(t>>32)
//u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
u[4] = byte(clock >> 8)
u[5] = byte(clock)
//log.Print("t : ",t , " clock : ",clock, " u[4]:", u[4], " u[5]:", u[5])
u[6] = MyHostIPV4Last2Bytes[0]
u[7] = MyHostIPV4Last2Bytes[1]
var u64 uint64
u64 = binary.LittleEndian.Uint64(u)
return UUID64(u64)
}
func (u UUID64) Timestamp() uint32 {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(u))
b4 := []byte{0x00, 0x01, 0x08, 0x00}
b4[0] , b4[1] , b4[2] , b4[3] = b[3], b[2], b[1], b[0]
return binary.LittleEndian.Uint32(b4)
}
func (u UUID64) Clock() uint16 {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(u))
b2 := []byte{0x00, 0x01}
b2[0] , b2[1] = b[4], b[5]
var r uint16 = binary.LittleEndian.Uint16(b2)
return r
}
func (u UUID64) HostSeq() uint8 {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(u))
return ( b[6] & 0x03 )
}
func (u UUID64) HostID() uint16 {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(u))
b2 := []byte{0x00, 0x01}
b[6] = b[6] >> 2
b2[0] , b2[1] = b[7], b[6]
//var r uint16 = binary.LittleEndian.Uint16(b2)
//return r //& 0xCFFF >> 2
return binary.LittleEndian.Uint16(b2)
}
func (u UUID64) HostName() string {
// todo optimize
return strconv.FormatUint(uint64(u.HostID()),10) + "." + strconv.FormatUint(uint64(u.HostSeq()),10)
}
func (u UUID64) String() string {
return strconv.FormatUint(uint64(u),10)
}
func (u UUID64) IPV2() [2]byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(u))
var r [2]byte
r[0] = b[6]
r[1] = b[7]
return r
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment