uuid.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. package xorm
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "crypto/rand"
  6. "crypto/sha1"
  7. "encoding/binary"
  8. "encoding/hex"
  9. "fmt"
  10. "hash"
  11. "math"
  12. "math/big"
  13. "net"
  14. "sort"
  15. "strings"
  16. "time"
  17. )
  18. // The UUID represents Universally Unique IDentifier (which is 128 bit long).
  19. type UUID [16]byte
  20. var (
  21. // NIL is defined in RFC 4122 section 4.1.7.
  22. // The nil UUID is special form of UUID that is specified to have all 128 bits set to zero.
  23. NIL = &UUID{
  24. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  25. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  26. }
  27. // NameSpaceDNS assume name to be a fully-qualified domain name.
  28. // Declared in RFC 4122 Appendix C.
  29. NameSpaceDNS = &UUID{
  30. 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
  31. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  32. }
  33. // NameSpaceURL assume name to be a URL.
  34. // Declared in RFC 4122 Appendix C.
  35. NameSpaceURL = &UUID{
  36. 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
  37. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  38. }
  39. // NameSpaceOID assume name to be an ISO OID.
  40. // Declared in RFC 4122 Appendix C.
  41. NameSpaceOID = &UUID{
  42. 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
  43. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  44. }
  45. // NameSpaceX500 assume name to be a X.500 DN (in DER or a text output format).
  46. // Declared in RFC 4122 Appendix C.
  47. NameSpaceX500 = &UUID{
  48. 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
  49. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  50. }
  51. )
  52. // Version of the UUID represents a kind of subtype specifier.
  53. func (u *UUID) Version() int {
  54. return int(binary.BigEndian.Uint16(u[6:8]) >> 12)
  55. }
  56. // String returns the human readable form of the UUID.
  57. func (u *UUID) String() string {
  58. return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
  59. }
  60. func (u *UUID) WithoutDashString() string {
  61. return fmt.Sprintf("%x", u[:])
  62. }
  63. func (u *UUID) variantRFC4122() {
  64. u[8] = (u[8] & 0x3f) | 0x80
  65. }
  66. // NewV3 creates a new UUID with variant 3 as described in RFC 4122.
  67. // Variant 3 based namespace-uuid and name and MD-5 hash calculation.
  68. func NewV3(namespace *UUID, name []byte) *UUID {
  69. uuid := newByHash(md5.New(), namespace, name)
  70. uuid[6] = (uuid[6] & 0x0f) | 0x30
  71. return uuid
  72. }
  73. func newByHash(hash hash.Hash, namespace *UUID, name []byte) *UUID {
  74. hash.Write(namespace[:])
  75. hash.Write(name[:])
  76. var uuid UUID
  77. copy(uuid[:], hash.Sum(nil)[:16])
  78. uuid.variantRFC4122()
  79. return &uuid
  80. }
  81. type stamp [10]byte
  82. var (
  83. mac []byte
  84. requests chan bool
  85. answers chan stamp
  86. )
  87. const gregorianUnix = 122192928000000000 // nanoseconds between gregorion zero and unix zero
  88. func init() {
  89. mac = make([]byte, 6)
  90. rand.Read(mac)
  91. requests = make(chan bool)
  92. answers = make(chan stamp)
  93. go unique()
  94. i, err := net.Interfaces()
  95. if err != nil {
  96. return
  97. }
  98. for _, d := range i {
  99. if len(d.HardwareAddr) == 6 {
  100. mac = d.HardwareAddr[:6]
  101. return
  102. }
  103. }
  104. }
  105. // NewV1 creates a new UUID with variant 1 as described in RFC 4122.
  106. // Variant 1 is based on hosts MAC address and actual timestamp (as count of 100-nanosecond intervals since
  107. // 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the Christian calendar).
  108. func NewV1() *UUID {
  109. var uuid UUID
  110. requests <- true
  111. s := <-answers
  112. copy(uuid[:4], s[4:])
  113. copy(uuid[4:6], s[2:4])
  114. copy(uuid[6:8], s[:2])
  115. uuid[6] = (uuid[6] & 0x0f) | 0x10
  116. copy(uuid[8:10], s[8:])
  117. copy(uuid[10:], mac)
  118. uuid.variantRFC4122()
  119. return &uuid
  120. }
  121. func unique() {
  122. var (
  123. lastNanoTicks uint64
  124. clockSequence [2]byte
  125. )
  126. rand.Read(clockSequence[:])
  127. for range requests {
  128. var s stamp
  129. nanoTicks := uint64((time.Now().UTC().UnixNano() / 100) + gregorianUnix)
  130. if nanoTicks < lastNanoTicks {
  131. lastNanoTicks = nanoTicks
  132. rand.Read(clockSequence[:])
  133. } else if nanoTicks == lastNanoTicks {
  134. lastNanoTicks = nanoTicks + 1
  135. } else {
  136. lastNanoTicks = nanoTicks
  137. }
  138. binary.BigEndian.PutUint64(s[:], lastNanoTicks)
  139. copy(s[8:], clockSequence[:])
  140. answers <- s
  141. }
  142. }
  143. // NewV4 creates a new UUID with variant 4 as described in RFC 4122. Variant 4 based on pure random bytes.
  144. func NewV4() *UUID {
  145. buf := make([]byte, 16)
  146. rand.Read(buf)
  147. buf[6] = (buf[6] & 0x0f) | 0x40
  148. var uuid UUID
  149. copy(uuid[:], buf[:])
  150. uuid.variantRFC4122()
  151. return &uuid
  152. }
  153. // NewV5 creates a new UUID with variant 5 as described in RFC 4122.
  154. // Variant 5 based namespace-uuid and name and SHA-1 hash calculation.
  155. func NewV5(namespaceUUID *UUID, name []byte) *UUID {
  156. uuid := newByHash(sha1.New(), namespaceUUID, name)
  157. uuid[6] = (uuid[6] & 0x0f) | 0x50
  158. return uuid
  159. }
  160. // NewNamespaceUUID creates a namespace UUID by using the namespace name in the NIL name space.
  161. // This is a different approach as the 4 "standard" namespace UUIDs which are timebased UUIDs (V1).
  162. func NewNamespaceUUID(namespace string) *UUID {
  163. return NewV5(NIL, []byte(namespace))
  164. }
  165. // String parse helpers.
  166. var (
  167. urnPrefix = []byte("urn:uuid:")
  168. byteGroups = []int{8, 4, 4, 4, 12}
  169. )
  170. func (u *UUID) UnmarshalText(text []byte) (err error) {
  171. if len(text) < 32 {
  172. err = fmt.Errorf("uuid: UUID string too short: %s", text)
  173. return
  174. }
  175. t := text[:]
  176. braced := false
  177. if bytes.Equal(t[:9], urnPrefix) {
  178. t = t[9:]
  179. } else if t[0] == '{' {
  180. braced = true
  181. t = t[1:]
  182. }
  183. b := u[:]
  184. for i, byteGroup := range byteGroups {
  185. if i > 0 {
  186. if t[0] != '-' {
  187. err = fmt.Errorf("uuid: invalid string format")
  188. return
  189. }
  190. t = t[1:]
  191. }
  192. if len(t) < byteGroup {
  193. err = fmt.Errorf("uuid: UUID string too short: %s", text)
  194. return
  195. }
  196. if i == 4 && len(t) > byteGroup &&
  197. ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
  198. err = fmt.Errorf("uuid: UUID string too long: %s", text)
  199. return
  200. }
  201. _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
  202. if err != nil {
  203. return
  204. }
  205. t = t[byteGroup:]
  206. b = b[byteGroup/2:]
  207. }
  208. return
  209. }
  210. // FromString returns UUID parsed from string input.
  211. // Input is expected in a form accepted by UnmarshalText.
  212. func FromString(input string) (u UUID, err error) {
  213. err = u.UnmarshalText([]byte(input))
  214. return
  215. }
  216. type StringSet struct {
  217. set map[string]bool
  218. list []string
  219. sorted bool
  220. }
  221. func NewStringSet() *StringSet {
  222. return &StringSet{make(map[string]bool), make([]string, 0), false}
  223. }
  224. func (set *StringSet) Add(i string) bool {
  225. _, found := set.set[i]
  226. set.set[i] = true
  227. if !found {
  228. set.sorted = false
  229. }
  230. return !found //False if it existed already
  231. }
  232. func (set *StringSet) Contains(i string) bool {
  233. _, found := set.set[i]
  234. return found //true if it existed already
  235. }
  236. func (set *StringSet) Remove(i string) {
  237. set.sorted = false
  238. delete(set.set, i)
  239. }
  240. func (set *StringSet) Len() int {
  241. return len(set.set)
  242. }
  243. func (set *StringSet) ItemByIndex(idx int) string {
  244. set.Sort()
  245. return set.list[idx]
  246. }
  247. func (set *StringSet) Index(c string) int {
  248. for i, s := range set.list {
  249. if c == s {
  250. return i
  251. }
  252. }
  253. return 0
  254. }
  255. func (set *StringSet) Sort() {
  256. if set.sorted {
  257. return
  258. }
  259. set.list = make([]string, 0)
  260. for s, _ := range set.set {
  261. set.list = append(set.list, s)
  262. }
  263. sort.Strings(set.list)
  264. set.sorted = true
  265. }
  266. func (set *StringSet) String() string {
  267. set.Sort()
  268. return strings.Join(set.list, "")
  269. }
  270. const (
  271. DEFAULT_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  272. )
  273. type ShortUUID struct {
  274. alphabet *StringSet
  275. }
  276. func NewShortUUID() *ShortUUID {
  277. suid := &ShortUUID{}
  278. suid.SetAlphabet(DEFAULT_ALPHABET)
  279. return suid
  280. }
  281. func NewShortUUIDWithAlphabet(alphabet string) *ShortUUID {
  282. suuid := &ShortUUID{}
  283. if alphabet == "" {
  284. alphabet = DEFAULT_ALPHABET
  285. }
  286. suuid.SetAlphabet(alphabet)
  287. return suuid
  288. }
  289. func (s *ShortUUID) SetAlphabet(alphabet string) {
  290. set := NewStringSet()
  291. for _, a := range alphabet {
  292. set.Add(string(a))
  293. }
  294. set.Sort()
  295. s.alphabet = set
  296. }
  297. func (s ShortUUID) String() string {
  298. return s.UUID("")
  299. }
  300. var (
  301. NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
  302. NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
  303. NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
  304. NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
  305. )
  306. func (s *ShortUUID) UUID(name string) string {
  307. var _uuid *UUID
  308. if name == "" {
  309. _uuid = NewV4()
  310. } else if strings.HasPrefix(name, "http") {
  311. _uuid = NewV5(&NamespaceDNS, []byte(name))
  312. } else {
  313. _uuid = NewV5(&NamespaceURL, []byte(name))
  314. }
  315. return s.Encode(_uuid)
  316. }
  317. // Encodes a UUID into a string (LSB first) according to the alphabet
  318. // If leftmost (MSB) bits 0, string might be shorter
  319. func (s *ShortUUID) Encode(uuid *UUID) string {
  320. padLen := s.encodeLen(len(uuid))
  321. number := uuidToInt(uuid)
  322. return s.numToString(number, padLen)
  323. }
  324. func (s *ShortUUID) Decode(input string) (UUID, error) {
  325. _uuid, err := FromString(s.stringToNum(input))
  326. return _uuid, err
  327. }
  328. func (s *ShortUUID) encodeLen(numBytes int) int {
  329. factor := math.Log(float64(25)) / math.Log(float64(s.alphabet.Len()))
  330. length := math.Ceil(factor * float64(numBytes))
  331. return int(length)
  332. }
  333. //Covert a number to a string, using the given alphabet.
  334. func (s *ShortUUID) numToString(number *big.Int, padToLen int) string {
  335. output := ""
  336. var digit *big.Int
  337. for number.Uint64() > 0 {
  338. number, digit = new(big.Int).DivMod(number, big.NewInt(int64(s.alphabet.Len())), new(big.Int))
  339. output += s.alphabet.ItemByIndex(int(digit.Int64()))
  340. }
  341. if padToLen > 0 {
  342. remainer := math.Max(float64(padToLen)-float64(len(output)), 0)
  343. output = output + strings.Repeat(s.alphabet.ItemByIndex(0), int(remainer))
  344. }
  345. return output
  346. }
  347. // Convert a string to a number(based uuid string),using the given alphabet.
  348. func (s *ShortUUID) stringToNum(input string) string {
  349. n := big.NewInt(0)
  350. for i := len(input) - 1; i >= 0; i-- {
  351. n.Mul(n, big.NewInt(int64(s.alphabet.Len())))
  352. n.Add(n, big.NewInt(int64(s.alphabet.Index(string(input[i])))))
  353. }
  354. x := fmt.Sprintf("%x", n)
  355. x = x[0:8] + "-" + x[8:12] + "-" + x[12:16] + "-" + x[16:20] + "-" + x[20:32]
  356. return x
  357. }
  358. func uuidToInt(_uuid *UUID) *big.Int {
  359. var i big.Int
  360. i.SetString(strings.Replace(_uuid.String(), "-", "", 4), 16)
  361. return &i
  362. }