summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/twinj/uuid/state.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/twinj/uuid/state.go')
-rw-r--r--vendor/github.com/twinj/uuid/state.go137
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)
+}
+