2023-10-31 22:58:28 +01:00
|
|
|
// Code generated by csid-generate.go DO NOT EDIT.
|
|
|
|
|
|
|
|
package {{.PkgName}}
|
|
|
|
|
|
|
|
import "crypto/rand"
|
2023-11-01 00:31:51 +01:00
|
|
|
import "crypto/sha256"
|
2023-10-31 22:58:28 +01:00
|
|
|
import "fmt"
|
|
|
|
import "github.com/go-playground/validator/v10"
|
|
|
|
import "github.com/rs/zerolog/log"
|
|
|
|
import "gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
|
|
|
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
|
|
|
|
import "gogs.mikescher.com/BlackForestBytes/goext/rext"
|
|
|
|
import "math/big"
|
|
|
|
import "reflect"
|
|
|
|
import "regexp"
|
|
|
|
import "strings"
|
|
|
|
|
|
|
|
const ChecksumCharsetIDGenerator = "{{.Checksum}}" // GoExtVersion: {{.GoextVersion}}
|
|
|
|
|
|
|
|
const idlen = 24
|
|
|
|
|
|
|
|
const checklen = 1
|
|
|
|
|
|
|
|
const idCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
|
|
const idCharsetLen = len(idCharset)
|
|
|
|
|
|
|
|
var charSetReverseMap = generateCharsetMap()
|
|
|
|
|
|
|
|
const ({{range .IDs}}
|
|
|
|
prefix{{.Name}} = "{{.Prefix}}" {{end}}
|
|
|
|
)
|
|
|
|
|
|
|
|
var ({{range .IDs}}
|
|
|
|
regex{{.Name}} = generateRegex(prefix{{.Name}}) {{end}}
|
|
|
|
)
|
|
|
|
|
|
|
|
func generateRegex(prefix string) rext.Regex {
|
|
|
|
return rext.W(regexp.MustCompile(fmt.Sprintf("^%s[%s]{%d}[%s]{%d}$", prefix, idCharset, idlen-len(prefix)-checklen, idCharset, checklen)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateCharsetMap() []int {
|
|
|
|
result := make([]int, 128)
|
|
|
|
for i := 0; i < len(result); i++ {
|
|
|
|
result[i] = -1
|
|
|
|
}
|
|
|
|
for idx, chr := range idCharset {
|
|
|
|
result[int(chr)] = idx
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateID(prefix string) string {
|
|
|
|
k := ""
|
|
|
|
csMax := big.NewInt(int64(idCharsetLen))
|
|
|
|
checksum := 0
|
|
|
|
for i := 0; i < idlen-len(prefix)-checklen; i++ {
|
|
|
|
v, err := rand.Int(rand.Reader, csMax)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
v64 := v.Int64()
|
|
|
|
k += string(idCharset[v64])
|
|
|
|
checksum = (checksum + int(v64)) % (idCharsetLen)
|
|
|
|
}
|
|
|
|
checkstr := string(idCharset[checksum%idCharsetLen])
|
|
|
|
return prefix + k + checkstr
|
|
|
|
}
|
|
|
|
|
2023-11-01 00:29:58 +01:00
|
|
|
func generateIDFromSeed(prefix string, seed string) string {
|
|
|
|
h := sha256.New()
|
|
|
|
|
|
|
|
iddata := ""
|
|
|
|
for len(iddata) < idlen-len(prefix)-checklen {
|
|
|
|
h.Write([]byte(seed))
|
|
|
|
bs := h.Sum(nil)
|
|
|
|
iddata += langext.NewAnyBaseConverter(idCharset).Encode(bs)
|
|
|
|
}
|
|
|
|
|
|
|
|
checksum := 0
|
|
|
|
for i := 0; i < idlen-len(prefix)-checklen; i++ {
|
|
|
|
ichr := int(iddata[i])
|
|
|
|
checksum = (checksum + charSetReverseMap[ichr]) % (idCharsetLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkstr := string(idCharset[checksum%idCharsetLen])
|
|
|
|
|
|
|
|
return prefix + iddata[:(idlen-len(prefix)-checklen)] + checkstr
|
|
|
|
}
|
|
|
|
|
2023-10-31 22:58:28 +01:00
|
|
|
func validateID(prefix string, value string) error {
|
|
|
|
if len(value) != idlen {
|
|
|
|
return exerr.New(exerr.TypeInvalidCSID, "id has the wrong length").Str("value", value).Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.HasPrefix(value, prefix) {
|
|
|
|
return exerr.New(exerr.TypeInvalidCSID, "id is missing the correct prefix").Str("value", value).Str("prefix", prefix).Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
checksum := 0
|
|
|
|
for i := len(prefix); i < len(value)-checklen; i++ {
|
|
|
|
ichr := int(value[i])
|
|
|
|
if ichr < 0 || ichr >= len(charSetReverseMap) || charSetReverseMap[ichr] == -1 {
|
|
|
|
return exerr.New(exerr.TypeInvalidCSID, "id contains invalid characters").Str("value", value).Build()
|
|
|
|
}
|
|
|
|
checksum = (checksum + charSetReverseMap[ichr]) % (idCharsetLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkstr := string(idCharset[checksum%idCharsetLen])
|
|
|
|
|
|
|
|
if !strings.HasSuffix(value, checkstr) {
|
|
|
|
return exerr.New(exerr.TypeInvalidCSID, "id checkstring is invalid").Str("value", value).Str("checkstr", checkstr).Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getRawData(prefix string, value string) string {
|
|
|
|
if len(value) != idlen {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return value[len(prefix) : idlen-checklen]
|
|
|
|
}
|
|
|
|
|
|
|
|
func getCheckString(prefix string, value string) string {
|
|
|
|
if len(value) != idlen {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return value[idlen-checklen:]
|
|
|
|
}
|
|
|
|
|
|
|
|
func ValidateEntityID(vfl validator.FieldLevel) bool {
|
|
|
|
if !vfl.Field().CanInterface() {
|
|
|
|
log.Error().Msgf("Failed to validate EntityID (cannot interface ?!?)")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
ifvalue := vfl.Field().Interface()
|
|
|
|
|
|
|
|
if value1, ok := ifvalue.(EntityID); ok {
|
|
|
|
|
|
|
|
if vfl.Field().Type().Kind() == reflect.Pointer && langext.IsNil(value1) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := value1.Valid(); err != nil {
|
|
|
|
log.Debug().Msgf("Failed to validate EntityID '%s' (%s)", value1.String(), err.Error())
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
log.Error().Msgf("Failed to validate EntityID (wrong type: %T)", ifvalue)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{{range .IDs}}
|
|
|
|
|
|
|
|
// ================================ {{.Name}} ({{.FileRelative}}) ================================
|
|
|
|
|
|
|
|
func New{{.Name}}() {{.Name}} {
|
|
|
|
return {{.Name}}(generateID(prefix{{.Name}}))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id {{.Name}}) Valid() error {
|
|
|
|
return validateID(prefix{{.Name}}, string(id))
|
|
|
|
}
|
|
|
|
|
2024-10-22 09:36:40 +02:00
|
|
|
func (i *{{.Name}}) String() string {
|
|
|
|
if i == nil {
|
|
|
|
return "<nil>"
|
|
|
|
}
|
2023-10-31 22:58:28 +01:00
|
|
|
return string(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i {{.Name}}) Prefix() string {
|
|
|
|
return prefix{{.Name}}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id {{.Name}}) Raw() string {
|
|
|
|
return getRawData(prefix{{.Name}}, string(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id {{.Name}}) CheckString() string {
|
|
|
|
return getCheckString(prefix{{.Name}}, string(id))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id {{.Name}}) Regex() rext.Regex {
|
|
|
|
return regex{{.Name}}
|
|
|
|
}
|
|
|
|
|
|
|
|
{{end}}
|