package generate import ( "crypto/rand" "encoding/binary" mrand "math/rand" "strconv" "strings" ) // ID generates an ID using crypto-random, falling back to math random when that fails // to avoid disrupting operation because of a faulty RNG. func ID(prefix string, length int) string { var data [32]byte result := strings.Builder{} result.Grow(length + 32) result.WriteString(prefix) pos := 0 for result.Len() < length { if pos == 0 { randRead(data[:]) } result.WriteString(strconv.FormatUint(binary.BigEndian.Uint64(data[pos:pos+8]), 36)) pos = (pos + 8) % 32 } return result.String()[:length] } func randRead(data []byte) { n, err := rand.Read(data) if err != nil { mrand.Read(data[n:]) } } // PostID generates a post ID. func PostID() string { return ID("P", 16) } // StoryID generates a post ID. func StoryID() string { return ID("S", 16) } // ChapterID generates a post ID. func ChapterID() string { return ID("SC", 24) } // CommentID generates a post ID. func CommentID() string { return ID("SCC", 32) } // FileID generates a file ID. func FileID() string { return ID("F", 16) }