You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
3.4 KiB

  1. package uuid
  2. /****************
  3. * Date: 14/02/14
  4. * Time: 7:43 PM
  5. ***************/
  6. import (
  7. "bytes"
  8. "log"
  9. seed "math/rand"
  10. "net"
  11. "sync"
  12. )
  13. // **************************************************** State
  14. func SetupCustomStateSaver(pSaver StateSaver) {
  15. state.Lock()
  16. pSaver.Init(&state)
  17. state.init()
  18. state.Unlock()
  19. }
  20. // Holds package information about the current
  21. // state of the UUID generator
  22. type State struct {
  23. // A flag which informs whether to
  24. // randomly create a node id
  25. randomNode bool
  26. // A flag which informs whether to
  27. // randomly create the sequence
  28. randomSequence bool
  29. // the last time UUID was saved
  30. past Timestamp
  31. // the next time the state will be saved
  32. next Timestamp
  33. // the last node which saved a UUID
  34. node []byte
  35. // An iterated value to help ensure different
  36. // values across the same domain
  37. sequence uint16
  38. sync.Mutex
  39. // save state interface
  40. saver StateSaver
  41. }
  42. // Changes the state with current data
  43. // Compares the current found node to the last node stored,
  44. // If they are the same or randomSequence is already set due
  45. // to an earlier read issue then the sequence is randomly generated
  46. // else if there is an issue with the time the sequence is incremented
  47. func (o *State) read(pNow Timestamp, pNode net.HardwareAddr) {
  48. if bytes.Equal([]byte(pNode), o.node) || o.randomSequence {
  49. o.sequence = uint16(seed.Int()) & 0x3FFF
  50. } else if pNow < o.past {
  51. o.sequence++
  52. }
  53. o.past = pNow
  54. o.node = pNode
  55. }
  56. func (o *State) persist() {
  57. if o.saver != nil {
  58. o.saver.Save(o)
  59. }
  60. }
  61. // Initialises the UUID state when the package is first loaded
  62. // it first attempts to decode the file state into State
  63. // if this file does not exist it will create the file and do a flush
  64. // of the random state which gets loaded at package runtime
  65. // second it will attempt to resolve the current hardware address nodeId
  66. // thirdly it will check the state of the clock
  67. func (o *State) init() {
  68. if o.saver != nil {
  69. intfcs, err := net.Interfaces()
  70. if err != nil {
  71. log.Println("uuid.State.init: address error: will generate random node id instead", err)
  72. return
  73. }
  74. a := getHardwareAddress(intfcs)
  75. if a == nil {
  76. log.Println("uuid.State.init: address error: will generate random node id instead", err)
  77. return
  78. }
  79. // Don't use random as we have a real address
  80. o.randomSequence = false
  81. if bytes.Equal([]byte(a), state.node) {
  82. state.sequence++
  83. }
  84. state.node = a
  85. state.randomNode = false
  86. }
  87. }
  88. func getHardwareAddress(pInterfaces []net.Interface) net.HardwareAddr {
  89. for _, inter := range pInterfaces {
  90. // Initially I could multicast out the Flags to get
  91. // whether the interface was up but started failing
  92. if (inter.Flags & (1 << net.FlagUp)) != 0 {
  93. //if inter.Flags.String() != "0" {
  94. if addrs, err := inter.Addrs(); err == nil {
  95. for _, addr := range addrs {
  96. if addr.String() != "0.0.0.0" && !bytes.Equal([]byte(inter.HardwareAddr), make([]byte, len(inter.HardwareAddr))) {
  97. return inter.HardwareAddr
  98. }
  99. }
  100. }
  101. }
  102. }
  103. return nil
  104. }
  105. // *********************************************** StateSaver interface
  106. // Use this interface to setup a custom state saver if you wish to have
  107. // v1 UUIDs based on your node id and constant time.
  108. type StateSaver interface {
  109. // Init is run if Setup() is false
  110. // Init should setup the system to save the state
  111. Init(*State)
  112. // Save saves the state and is called only if const V1Save and
  113. // Setup() is true
  114. Save(*State)
  115. }