Files
idgen/idgen.go
2026-06-14 16:55:03 +02:00

67 lines
1.2 KiB
Go

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
}