Some checks failed
CI / Test (Go 1.24.x, ubuntu-latest) (push) Successful in 1m53s
CI / Code Quality (push) Failing after 26s
CI / Security Scan (push) Failing after 11s
CI / Test Coverage (push) Successful in 1m13s
CI / Benchmarks (push) Failing after 10m22s
CI / Build CLI (push) Failing after 8s
Benchmarks / Run Benchmarks (push) Failing after 10m13s
Release / Test (push) Successful in 55s
Release / Build (amd64, darwin, ) (push) Failing after 12s
Release / Build (amd64, linux, ) (push) Failing after 6s
Release / Build (amd64, windows, .exe) (push) Failing after 12s
Release / Build (arm64, darwin, ) (push) Failing after 12s
Release / Build (arm64, linux, ) (push) Failing after 12s
Release / Release (push) Has been skipped
CI / Test (Go 1.24.x, macos-latest) (push) Has been cancelled
CI / Test (Go 1.24.x, windows-latest) (push) Has been cancelled
Move hosting from GitHub to private Gitea instance.
125 lines
3.6 KiB
Go
125 lines
3.6 KiB
Go
package jdenticon
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitea.dockr.co/kev/go-jdenticon/internal/engine"
|
|
"gitea.dockr.co/kev/go-jdenticon/internal/util"
|
|
)
|
|
|
|
// Generator provides thread-safe identicon generation with caching.
|
|
// It wraps the internal engine.Generator to provide a clean public API.
|
|
type Generator struct {
|
|
engine *engine.Generator
|
|
config Config // Store the configuration for validation during Generate calls
|
|
}
|
|
|
|
// NewGenerator creates a new Generator with default configuration and default caching.
|
|
func NewGenerator() (*Generator, error) {
|
|
engineGen, err := engine.NewDefaultGenerator()
|
|
if err != nil {
|
|
return nil, NewErrGenerationFailed("", 0, err)
|
|
}
|
|
|
|
return &Generator{
|
|
engine: engineGen,
|
|
config: DefaultConfig(),
|
|
}, nil
|
|
}
|
|
|
|
// NewGeneratorWithCacheSize creates a new Generator with the specified cache size.
|
|
func NewGeneratorWithCacheSize(cacheSize int) (*Generator, error) {
|
|
if cacheSize <= 0 {
|
|
return nil, NewErrInvalidInput("cacheSize", fmt.Sprintf("%d", cacheSize), "must be positive")
|
|
}
|
|
|
|
config := engine.DefaultGeneratorConfig()
|
|
config.CacheSize = cacheSize
|
|
|
|
engineGen, err := engine.NewGeneratorWithConfig(config)
|
|
if err != nil {
|
|
return nil, NewErrCacheCreationFailed(cacheSize, err)
|
|
}
|
|
|
|
return &Generator{
|
|
engine: engineGen,
|
|
config: DefaultConfig(),
|
|
}, nil
|
|
}
|
|
|
|
// NewGeneratorWithConfig creates a new Generator with custom configuration and caching.
|
|
func NewGeneratorWithConfig(config Config, cacheSize int) (*Generator, error) {
|
|
if cacheSize <= 0 {
|
|
return nil, NewErrInvalidInput("cacheSize", fmt.Sprintf("%d", cacheSize), "must be positive")
|
|
}
|
|
|
|
// Convert public config to internal config
|
|
colorConfig, err := config.toEngineColorConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
generatorConfig := engine.GeneratorConfig{
|
|
ColorConfig: colorConfig,
|
|
CacheSize: cacheSize,
|
|
MaxComplexity: config.MaxComplexity,
|
|
MaxIconSize: config.MaxIconSize,
|
|
}
|
|
|
|
engineGen, err := engine.NewGeneratorWithConfig(generatorConfig)
|
|
if err != nil {
|
|
return nil, NewErrCacheCreationFailed(cacheSize, err)
|
|
}
|
|
|
|
return &Generator{
|
|
engine: engineGen,
|
|
config: config,
|
|
}, nil
|
|
}
|
|
|
|
// Generate creates an identicon for the given input string and size with context support.
|
|
// The context can be used to set timeouts or cancel generation.
|
|
//
|
|
// The input string is hashed to generate a deterministic identicon.
|
|
// Size must be positive and represents the width/height in pixels.
|
|
//
|
|
// This method applies the security limits that were configured when the Generator was created.
|
|
// For different limits, create a new Generator with NewGeneratorWithConfig.
|
|
//
|
|
// This method is thread-safe and uses caching if configured.
|
|
func (g *Generator) Generate(ctx context.Context, input string, size int) (*Icon, error) {
|
|
// Apply validation using the generator's stored configuration
|
|
if err := validateInputs(input, size, g.config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Check for early cancellation
|
|
if err := ctx.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Convert input to hash
|
|
hash := util.ComputeHash(input)
|
|
|
|
// Validate complexity before generation
|
|
if err := validateComplexity(hash, g.config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Generate using the internal engine with context
|
|
engineIcon, err := g.engine.Generate(ctx, hash, float64(size))
|
|
if err != nil {
|
|
return nil, NewErrGenerationFailed(input, size, err)
|
|
}
|
|
|
|
// Wrap in public Icon directly
|
|
return newIcon(engineIcon), nil
|
|
}
|
|
|
|
// GetCacheMetrics returns the cache hit and miss counts.
|
|
// These metrics are thread-safe to read.
|
|
func (g *Generator) GetCacheMetrics() (hits, misses int64) {
|
|
return g.engine.GetCacheMetrics()
|
|
}
|