You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
1.6 KiB
65 lines
1.6 KiB
package generator
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
var EPOCH_TIME time.Time = time.Unix(0, 1609459200000*int64(time.Millisecond))
|
|
var TIME_MASK uint64 = 0x1FFFFFFFFFF
|
|
|
|
var tooManyRequests = errors.New("Too many requests in the current ms")
|
|
var incorrectSystemTime = errors.New("The current time is less than the last generated time! Check the system time.")
|
|
|
|
type Generator struct {
|
|
LastGeneratedTime time.Duration
|
|
Counter uint64
|
|
LastCounterRollover time.Duration
|
|
WorkerID uint64
|
|
}
|
|
|
|
func (g *Generator) GenerateSnowflake() (uint64, error) {
|
|
time := time.Since(EPOCH_TIME)
|
|
if time < g.LastGeneratedTime {
|
|
return 0, incorrectSystemTime
|
|
}
|
|
if g.Counter == 4095 {
|
|
if g.LastCounterRollover >= time {
|
|
return 0, tooManyRequests
|
|
}
|
|
g.LastCounterRollover = time
|
|
g.Counter = 0
|
|
} else {
|
|
g.Counter += 1
|
|
}
|
|
g.LastGeneratedTime = time
|
|
return (((uint64(time.Milliseconds()) & TIME_MASK) << 22) + g.WorkerID + g.Counter), nil
|
|
}
|
|
|
|
func CreateGenerator(workerID uint64) (*Generator, error) {
|
|
if workerID <= 0 {
|
|
return nil, errors.New("Worker ID must be greater than 0")
|
|
}
|
|
return &Generator{
|
|
LastGeneratedTime: time.Since(EPOCH_TIME),
|
|
Counter: 0,
|
|
LastCounterRollover: time.Since(EPOCH_TIME),
|
|
WorkerID: workerID,
|
|
}, nil
|
|
}
|
|
|
|
func (g *Generator) Run(request chan chan uint64) {
|
|
for output := range request {
|
|
id, err := g.GenerateSnowflake()
|
|
if err != nil {
|
|
if err == tooManyRequests {
|
|
time.Sleep(time.Millisecond)
|
|
continue
|
|
} else if err == incorrectSystemTime {
|
|
panic("System time is incorrect")
|
|
}
|
|
}
|
|
output <- id
|
|
}
|
|
}
|