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