diff options
Diffstat (limited to 'vendor/github.com/twinj/uuid/state.go')
-rw-r--r-- | vendor/github.com/twinj/uuid/state.go | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/vendor/github.com/twinj/uuid/state.go b/vendor/github.com/twinj/uuid/state.go new file mode 100644 index 0000000000..f3920776cd --- /dev/null +++ b/vendor/github.com/twinj/uuid/state.go @@ -0,0 +1,137 @@ +package uuid + +/**************** + * Date: 14/02/14 + * Time: 7:43 PM + ***************/ + +import ( + "bytes" + "log" + seed "math/rand" + "net" + "sync" +) + + +// **************************************************** State + +func SetupCustomStateSaver(pSaver StateSaver) { + state.Lock() + pSaver.Init(&state) + state.init() + state.Unlock() +} + +// Holds package information about the current +// state of the UUID generator +type State struct { + + // A flag which informs whether to + // randomly create a node id + randomNode bool + + // A flag which informs whether to + // randomly create the sequence + randomSequence bool + + // the last time UUID was saved + past Timestamp + + // the next time the state will be saved + next Timestamp + + // the last node which saved a UUID + node []byte + + // An iterated value to help ensure different + // values across the same domain + sequence uint16 + + sync.Mutex + + // save state interface + saver StateSaver +} + +// Changes the state with current data +// Compares the current found node to the last node stored, +// If they are the same or randomSequence is already set due +// to an earlier read issue then the sequence is randomly generated +// else if there is an issue with the time the sequence is incremented +func (o *State) read(pNow Timestamp, pNode net.HardwareAddr) { + if bytes.Equal([]byte(pNode), o.node) || o.randomSequence { + o.sequence = uint16(seed.Int()) & 0x3FFF + } else if pNow < o.past { + o.sequence++ + } + o.past = pNow + o.node = pNode +} + +func (o *State) persist() { + if o.saver != nil { + o.saver.Save(o) + } +} + +// Initialises the UUID state when the package is first loaded +// it first attempts to decode the file state into State +// if this file does not exist it will create the file and do a flush +// of the random state which gets loaded at package runtime +// second it will attempt to resolve the current hardware address nodeId +// thirdly it will check the state of the clock +func (o *State) init() { + if o.saver != nil { + intfcs, err := net.Interfaces() + if err != nil { + log.Println("uuid.State.init: address error: will generate random node id instead", err) + return + } + a := getHardwareAddress(intfcs) + if a == nil { + log.Println("uuid.State.init: address error: will generate random node id instead", err) + return + } + // Don't use random as we have a real address + o.randomSequence = false + if bytes.Equal([]byte(a), state.node) { + state.sequence++ + } + state.node = a + state.randomNode = false + } +} + +func getHardwareAddress(pInterfaces []net.Interface) net.HardwareAddr { + for _, inter := range pInterfaces { + // Initially I could multicast out the Flags to get + // whether the interface was up but started failing + if (inter.Flags & (1 << net.FlagUp)) != 0 { + //if inter.Flags.String() != "0" { + if addrs, err := inter.Addrs(); err == nil { + for _, addr := range addrs { + if addr.String() != "0.0.0.0" && !bytes.Equal([]byte(inter.HardwareAddr), make([]byte, len(inter.HardwareAddr))) { + return inter.HardwareAddr + } + } + } + } + } + return nil +} + +// *********************************************** StateSaver interface + +// Use this interface to setup a custom state saver if you wish to have +// v1 UUIDs based on your node id and constant time. +type StateSaver interface { + // Init is run if Setup() is false + // Init should setup the system to save the state + Init(*State) + + // Save saves the state and is called only if const V1Save and + // Setup() is true + Save(*State) +} + |