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