guid.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package guid
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "strings"
  9. "sync"
  10. "time"
  11. )
  12. // GUID is a unique identifier designed to virtually guarantee non-conflict between values generated
  13. // across a distributed system.
  14. type GUID struct {
  15. timeHighAndVersion uint16
  16. timeMid uint16
  17. timeLow uint32
  18. clockSeqHighAndReserved uint8
  19. clockSeqLow uint8
  20. node [6]byte
  21. }
  22. // Format enumerates the values that are supported by Parse and Format
  23. type Format string
  24. // These constants define the possible string formats available via this implementation of Guid.
  25. const (
  26. FormatB Format = "B" // {00000000-0000-0000-0000-000000000000}
  27. FormatD Format = "D" // 00000000-0000-0000-0000-000000000000
  28. FormatN Format = "N" // 00000000000000000000000000000000
  29. FormatP Format = "P" // (00000000-0000-0000-0000-000000000000)
  30. FormatX Format = "X" // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
  31. FormatDefault Format = FormatD
  32. )
  33. // CreationStrategy enumerates the values that are supported for populating the bits of a new Guid.
  34. type CreationStrategy string
  35. // These constants define the possible creation strategies available via this implementation of Guid.
  36. const (
  37. CreationStrategyVersion1 CreationStrategy = "version1"
  38. CreationStrategyVersion2 CreationStrategy = "version2"
  39. CreationStrategyVersion3 CreationStrategy = "version3"
  40. CreationStrategyVersion4 CreationStrategy = "version4"
  41. CreationStrategyVersion5 CreationStrategy = "version5"
  42. )
  43. var emptyGUID GUID
  44. // NewGUID generates and returns a new globally unique identifier
  45. func NewGUID() GUID {
  46. result, err := version4()
  47. if err != nil {
  48. panic(err) //Version 4 (pseudo-random GUID) doesn't use anything that could fail.
  49. }
  50. return result
  51. }
  52. var knownStrategies = map[CreationStrategy]func() (GUID, error){
  53. CreationStrategyVersion1: version1,
  54. CreationStrategyVersion4: version4,
  55. }
  56. // NewGUIDs generates and returns a new globally unique identifier that conforms to the given strategy.
  57. func NewGUIDs(strategy CreationStrategy) (GUID, error) {
  58. if creator, present := knownStrategies[strategy]; present {
  59. result, err := creator()
  60. return result, err
  61. }
  62. return emptyGUID, errors.New("Unsupported CreationStrategy")
  63. }
  64. // Empty returns a copy of the default and empty GUID.
  65. func Empty() GUID {
  66. return emptyGUID
  67. }
  68. var knownFormats = map[Format]string{
  69. FormatN: "%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
  70. FormatD: "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  71. FormatB: "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
  72. FormatP: "(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
  73. FormatX: "{0x%08x,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}",
  74. }
  75. // MarshalJSON writes a GUID as a JSON string.
  76. func (guid GUID) MarshalJSON() (marshaled []byte, err error) {
  77. buf := bytes.Buffer{}
  78. _, err = buf.WriteRune('"')
  79. buf.WriteString(guid.String())
  80. buf.WriteRune('"')
  81. marshaled = buf.Bytes()
  82. return
  83. }
  84. // Parse instantiates a GUID from a text representation of the same GUID.
  85. // This is the inverse of function family String()
  86. func Parse(value string) (GUID, error) {
  87. var guid GUID
  88. for _, fullFormat := range knownFormats {
  89. parity, err := fmt.Sscanf(
  90. value,
  91. fullFormat,
  92. &guid.timeLow,
  93. &guid.timeMid,
  94. &guid.timeHighAndVersion,
  95. &guid.clockSeqHighAndReserved,
  96. &guid.clockSeqLow,
  97. &guid.node[0],
  98. &guid.node[1],
  99. &guid.node[2],
  100. &guid.node[3],
  101. &guid.node[4],
  102. &guid.node[5])
  103. if parity == 11 && err == nil {
  104. return guid, err
  105. }
  106. }
  107. return emptyGUID, fmt.Errorf("\"%s\" is not in a recognized format", value)
  108. }
  109. // String returns a text representation of a GUID in the default format.
  110. func (guid GUID) String() string {
  111. return guid.Stringf(FormatDefault)
  112. }
  113. // Stringf returns a text representation of a GUID that conforms to the specified format.
  114. // If an unrecognized format is provided, the empty string is returned.
  115. func (guid GUID) Stringf(format Format) string {
  116. if format == "" {
  117. format = FormatDefault
  118. }
  119. fullFormat, present := knownFormats[format]
  120. if !present {
  121. return ""
  122. }
  123. return fmt.Sprintf(
  124. fullFormat,
  125. guid.timeLow,
  126. guid.timeMid,
  127. guid.timeHighAndVersion,
  128. guid.clockSeqHighAndReserved,
  129. guid.clockSeqLow,
  130. guid.node[0],
  131. guid.node[1],
  132. guid.node[2],
  133. guid.node[3],
  134. guid.node[4],
  135. guid.node[5])
  136. }
  137. // UnmarshalJSON parses a GUID from a JSON string token.
  138. func (guid *GUID) UnmarshalJSON(marshaled []byte) (err error) {
  139. if len(marshaled) < 2 {
  140. err = errors.New("JSON GUID must be surrounded by quotes")
  141. return
  142. }
  143. stripped := marshaled[1 : len(marshaled)-1]
  144. *guid, err = Parse(string(stripped))
  145. return
  146. }
  147. // Version reads a GUID to parse which mechanism of generating GUIDS was employed.
  148. // Values returned here are documented in rfc4122.txt.
  149. func (guid GUID) Version() uint {
  150. return uint(guid.timeHighAndVersion >> 12)
  151. }
  152. var unixToGregorianOffset = time.Date(1970, 01, 01, 0, 0, 00, 0, time.UTC).Sub(time.Date(1582, 10, 15, 0, 0, 0, 0, time.UTC))
  153. // getRFC4122Time returns a 60-bit count of 100-nanosecond intervals since 00:00:00.00 October 15th, 1582
  154. func getRFC4122Time() int64 {
  155. currentTime := time.Now().UTC().Add(unixToGregorianOffset).UnixNano()
  156. currentTime /= 100
  157. return currentTime & 0x0FFFFFFFFFFFFFFF
  158. }
  159. var clockSeqVal uint16
  160. var clockSeqKey sync.Mutex
  161. func getClockSequence() (uint16, error) {
  162. clockSeqKey.Lock()
  163. defer clockSeqKey.Unlock()
  164. if 0 == clockSeqVal {
  165. var temp [2]byte
  166. if parity, err := rand.Read(temp[:]); !(2 == parity && nil == err) {
  167. return 0, err
  168. }
  169. clockSeqVal = uint16(temp[0])<<8 | uint16(temp[1])
  170. }
  171. clockSeqVal++
  172. return clockSeqVal, nil
  173. }
  174. func getMACAddress() (mac [6]byte, err error) {
  175. var hostNICs []net.Interface
  176. hostNICs, err = net.Interfaces()
  177. if err != nil {
  178. return
  179. }
  180. for _, nic := range hostNICs {
  181. var parity int
  182. parity, err = fmt.Sscanf(
  183. strings.ToLower(nic.HardwareAddr.String()),
  184. "%02x:%02x:%02x:%02x:%02x:%02x",
  185. &mac[0],
  186. &mac[1],
  187. &mac[2],
  188. &mac[3],
  189. &mac[4],
  190. &mac[5])
  191. if parity == len(mac) {
  192. return
  193. }
  194. }
  195. err = fmt.Errorf("No suitable address found")
  196. return
  197. }
  198. func version1() (result GUID, err error) {
  199. var localMAC [6]byte
  200. var clockSeq uint16
  201. currentTime := getRFC4122Time()
  202. result.timeLow = uint32(currentTime)
  203. result.timeMid = uint16(currentTime >> 32)
  204. result.timeHighAndVersion = uint16(currentTime >> 48)
  205. if err = result.setVersion(1); err != nil {
  206. return emptyGUID, err
  207. }
  208. if localMAC, err = getMACAddress(); nil != err {
  209. if parity, err := rand.Read(localMAC[:]); !(len(localMAC) != parity && err == nil) {
  210. return emptyGUID, err
  211. }
  212. localMAC[0] |= 0x1
  213. }
  214. copy(result.node[:], localMAC[:])
  215. if clockSeq, err = getClockSequence(); nil != err {
  216. return emptyGUID, err
  217. }
  218. result.clockSeqLow = uint8(clockSeq)
  219. result.clockSeqHighAndReserved = uint8(clockSeq >> 8)
  220. result.setReservedBits()
  221. return
  222. }
  223. func version4() (GUID, error) {
  224. var retval GUID
  225. var bits [10]byte
  226. if parity, err := rand.Read(bits[:]); !(len(bits) == parity && err == nil) {
  227. return emptyGUID, err
  228. }
  229. retval.timeHighAndVersion |= uint16(bits[0]) | uint16(bits[1])<<8
  230. retval.timeMid |= uint16(bits[2]) | uint16(bits[3])<<8
  231. retval.timeLow |= uint32(bits[4]) | uint32(bits[5])<<8 | uint32(bits[6])<<16 | uint32(bits[7])<<24
  232. retval.clockSeqHighAndReserved = uint8(bits[8])
  233. retval.clockSeqLow = uint8(bits[9])
  234. //Randomly set clock-sequence, reserved, and node
  235. if written, err := rand.Read(retval.node[:]); !(nil == err && written == len(retval.node)) {
  236. retval = emptyGUID
  237. return retval, err
  238. }
  239. if err := retval.setVersion(4); nil != err {
  240. return emptyGUID, err
  241. }
  242. retval.setReservedBits()
  243. return retval, nil
  244. }
  245. func (guid *GUID) setVersion(version uint16) error {
  246. if version > 5 || version == 0 {
  247. return fmt.Errorf("While setting GUID version, unsupported version: %d", version)
  248. }
  249. guid.timeHighAndVersion = (guid.timeHighAndVersion & 0x0fff) | version<<12
  250. return nil
  251. }
  252. func (guid *GUID) setReservedBits() {
  253. guid.clockSeqHighAndReserved = (guid.clockSeqHighAndReserved & 0x3f) | 0x80
  254. }