-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
state.go
137 lines (115 loc) · 3.38 KB
/
state.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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)
}