mirror of
https://github.com/parkan/go-hauk.git
synced 2026-05-08 16:47:46 +02:00
126 lines
2.6 KiB
Go
126 lines
2.6 KiB
Go
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
|
|
}
|
|
}
|
|
}
|