package idgen import ( "crypto/rand" "encoding/hex" "fmt" "io" "inbox/internal/base/slug" "inbox/internal/base/timeutil" ) type Generator struct { Clock timeutil.Clock Random io.Reader SuffixSize int } func NewGenerator(clock timeutil.Clock, random io.Reader) Generator { if clock == nil { clock = timeutil.SystemClock{} } if random == nil { random = rand.Reader } return Generator{ Clock: clock, Random: random, SuffixSize: 6, } } func (g Generator) New(kind string) (string, error) { prefix := slug.NormalizeWithLimit(kind, 24) if prefix == "" { prefix = "id" } size := g.SuffixSize if size <= 0 { size = 6 } buf := make([]byte, size) if _, err := io.ReadFull(g.Random, buf); err != nil { return "", fmt.Errorf("generate id suffix: %w", err) } return fmt.Sprintf("%s-%s-%s", prefix, timeutil.TimestampIDPart(g.Clock.Now()), hex.EncodeToString(buf)), nil } func New(kind string) (string, error) { return NewGenerator(timeutil.SystemClock{}, rand.Reader).New(kind) }