Created
August 13, 2018 17:30
-
-
Save wdshin/e80521a92b265c195c6da90dc05b5585 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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