|
|
- 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)
- }
-
|