add link id generation

This commit is contained in:
Arkadiy Kukarkin
2025-12-23 12:23:32 +01:00
parent a0290f6a6d
commit c4889d7d16

125
linkgen/linkgen.go Normal file
View File

@@ -0,0 +1,125 @@
package linkgen
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"github.com/parkan/go-hauk/config"
"github.com/parkan/go-hauk/store"
)
const (
alphaLower = "0123456789abcdefghijklmnopqrstuvwxyz"
alphaMixed = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
alphaUpper = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"
prefixLocdata = "locdata-"
)
type Generator struct {
store store.Store
style config.LinkStyle
}
func New(s store.Store, style config.LinkStyle) *Generator {
return &Generator{store: s, style: style}
}
func (g *Generator) Generate(ctx context.Context) (string, error) {
for {
s, err := g.generate()
if err != nil {
return "", err
}
exists, err := g.store.Exists(ctx, prefixLocdata+s)
if err != nil {
return "", err
}
if !exists {
return s, nil
}
}
}
func (g *Generator) generate() (string, error) {
switch g.style {
case config.LinkUUIDv4:
return uuidV4()
case config.Link16Hex:
return hexString(8)
case config.Link16Lower:
return randomString(alphaLower, 16)
case config.Link16Mixed:
return randomString(alphaMixed, 16)
case config.Link16Upper:
return randomString(alphaUpper, 16)
case config.Link32Hex:
return hexString(16)
case config.Link32Lower:
return randomString(alphaLower, 32)
case config.Link32Mixed:
return randomString(alphaMixed, 32)
case config.Link32Upper:
return randomString(alphaUpper, 32)
case config.Link4Plus4Lower:
return fourPlusFour(alphaLower)
case config.Link4Plus4Mixed:
return fourPlusFour(alphaMixed)
case config.Link4Plus4Upper:
fallthrough
default:
return fourPlusFour(alphaUpper)
}
}
func uuidV4() (string, error) {
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
return "", err
}
b[6] = (b[6] & 0x0f) | 0x40
b[8] = (b[8] & 0x3f) | 0x80
h := hex.EncodeToString(b)
return fmt.Sprintf("%s-%s-%s-%s-%s", h[0:8], h[8:12], h[12:16], h[16:20], h[20:32]), nil
}
func hexString(n int) (string, error) {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
func randomString(alpha string, length int) (string, error) {
b := make([]byte, length)
for i := 0; i < length; i++ {
idx, err := randInt(len(alpha))
if err != nil {
return "", err
}
b[i] = alpha[idx]
}
return string(b), nil
}
func fourPlusFour(alpha string) (string, error) {
s, err := randomString(alpha, 8)
if err != nil {
return "", err
}
return s[:4] + "-" + s[4:], nil
}
func randInt(max int) (int, error) {
b := make([]byte, 1)
for {
if _, err := rand.Read(b); err != nil {
return 0, err
}
if int(b[0]) < 256-(256%max) {
return int(b[0]) % max, nil
}
}
}