86 lines
1.7 KiB
Go
86 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
crypto "crypto/rand"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.wisellama.rocks/Wisellama/ulid"
|
|
)
|
|
|
|
func main() {
|
|
t := time.Now()
|
|
|
|
entropy, err := interestingEntropy()
|
|
if err != nil {
|
|
fmt.Printf("error creating entropy source: %v\n", err)
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
for i := 0; i < 30; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
u, err := ulid.NewULIDString(t, entropy)
|
|
if err != nil {
|
|
fmt.Printf("error: %v\n", err)
|
|
}
|
|
|
|
fmt.Printf("ULID: %s\n", u)
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
fmt.Printf("Done\n")
|
|
}
|
|
|
|
// interestingEntropy returns a psuedo random source. This is an
|
|
// alternative to always using crypto/rand and potentially running out
|
|
// of entropy. Don't rely on this for security-sensitive applications.
|
|
//
|
|
// It uses crypto/rand to get the seed for a math/rand psuedorandom
|
|
// number generator. This way we don't collide with other instances
|
|
// that might start at the same time.
|
|
//
|
|
// It also uses a simple locked source for concurrency. If you want a
|
|
// more official implementation, look at exp/rand LockedSource:
|
|
//
|
|
// https://pkg.go.dev/golang.org/x/exp/rand#LockedSource
|
|
func interestingEntropy() (*rand.Rand, error) {
|
|
seedBytes := make([]byte, 8)
|
|
_, err := crypto.Read(seedBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
seedInt, _ := binary.Varint(seedBytes)
|
|
|
|
source := &LockedSource{
|
|
Source: rand.NewSource(seedInt),
|
|
}
|
|
|
|
// nolint
|
|
return rand.New(source), nil
|
|
|
|
}
|
|
|
|
type LockedSource struct {
|
|
mx sync.Mutex
|
|
Source rand.Source
|
|
}
|
|
|
|
func (s *LockedSource) Int63() int64 {
|
|
s.mx.Lock()
|
|
defer s.mx.Unlock()
|
|
return s.Source.Int63()
|
|
}
|
|
|
|
func (s *LockedSource) Seed(seed int64) {
|
|
s.mx.Lock()
|
|
defer s.mx.Unlock()
|
|
s.Source.Seed(seed)
|
|
}
|