GraphQL API and utilities for the rpdata project
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.

59 lines
1.0 KiB

  1. package generate
  2. import (
  3. "crypto/rand"
  4. "encoding/binary"
  5. mrand "math/rand"
  6. "strconv"
  7. "strings"
  8. )
  9. // ID generates an ID using crypto-random, falling back to math random when that fails
  10. // to avoid disrupting operation because of a faulty RNG.
  11. func ID(prefix string, length int) string {
  12. var data [32]byte
  13. result := strings.Builder{}
  14. result.Grow(length + 32)
  15. result.WriteString(prefix)
  16. pos := 0
  17. for result.Len() < length {
  18. if pos == 0 {
  19. randRead(data[:])
  20. }
  21. result.WriteString(strconv.FormatUint(binary.BigEndian.Uint64(data[pos:pos+8]), 36))
  22. pos = (pos + 8) % 32
  23. }
  24. return result.String()[:length]
  25. }
  26. func randRead(data []byte) {
  27. n, err := rand.Read(data)
  28. if err != nil {
  29. mrand.Read(data[n:])
  30. }
  31. }
  32. // PostID generates a post ID.
  33. func PostID() string {
  34. return ID("P", 16)
  35. }
  36. // StoryID generates a post ID.
  37. func StoryID() string {
  38. return ID("S", 16)
  39. }
  40. // ChapterID generates a post ID.
  41. func ChapterID() string {
  42. return ID("SC", 24)
  43. }
  44. // FileID generates a file ID.
  45. func FileID() string {
  46. return ID("F", 16)
  47. }