package idgen import ( "crypto/rand" "encoding/base32" "sync" "time" ) var encoding = base32.StdEncoding.WithPadding(base32.NoPadding) // Creates a new, random token from 20 random bytes, encoded as base32. func NewToken() string { buf := make([]byte, 20) rand.Read(buf) // Guaranteed not to return an error. return encoding.EncodeToString(buf) } var ( lock sync.Mutex ts int64 = time.Now().Unix() seq int64 = 0 seqMax int64 = 1 << 20 ) // NextID can generate ~1M int64s per second. // // nodeID must be in [0, 63]. The counter is shared across all nodeIDs within a // process, so IDs are not guaranteed to be sequential. func NextID(nodeID int64) int64 { if nodeID < 0 || nodeID >= 64 { panic("nodeID out of range [0, 63]") } for { if id := nextID(nodeID); id != 0 { return id } time.Sleep(100 * time.Millisecond) } } func nextID(nodeID int64) int64 { lock.Lock() defer lock.Unlock() tt := time.Now().Unix() if tt > ts { ts = tt seq = 1 } else { seq++ if seq >= seqMax { return 0 } } return (ts << 26) + (nodeID << 20) + seq } func SplitID(id int64) (unixTime, nodeID, counter int64) { counter = id & (0x00000000000FFFFF) nodeID = (id >> 20) & (0x000000000000003F) unixTime = id >> 26 return }