35 lines
1.2 KiB
Go
35 lines
1.2 KiB
Go
// Package idgen generates stable, opaque, URL-safe identifiers for domain
|
|
// entities (users, folders, artists, albums, songs, ...).
|
|
//
|
|
// IDs are random and assigned once, then persisted. They are never derived
|
|
// from filesystem position or recomputed on rescan: the scanner looks up
|
|
// existing rows by natural key (e.g. a song's path within its music
|
|
// folder) and only calls NewID for rows it has never seen before, so IDs
|
|
// stay stable across restarts and normal rescans.
|
|
package idgen
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base32"
|
|
"strings"
|
|
)
|
|
|
|
// enc is unpadded base32 using Crockford's alphabet-like lowercase set,
|
|
// which is URL-safe and avoids ambiguous characters better than base64url
|
|
// for anything a human might need to read back (log lines, debugging).
|
|
var enc = base32.NewEncoding("0123456789abcdefghjkmnpqrstvwxyz").WithPadding(base32.NoPadding)
|
|
|
|
// New returns a new opaque ID with the given short type prefix, e.g.
|
|
// New("us") -> "us_1a2b3c4d5e6f7g8h9j0k1m2n".
|
|
func New(prefix string) string {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
panic(err) // crypto/rand failing means the system is broken
|
|
}
|
|
id := strings.ToLower(enc.EncodeToString(b))
|
|
if prefix == "" {
|
|
return id
|
|
}
|
|
return prefix + "_" + id
|
|
}
|