94 lines
2.1 KiB
Go

package services
import (
"bytes"
"context"
"fmt"
"image/png"
"log"
"slices"
"time"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/code128"
"github.com/boombuler/barcode/ean"
"github.com/boombuler/barcode/qr"
"github.com/redis/go-redis/v9"
)
type BarcodeService interface {
GenerateBarcode(format string, content string, width int, height int) (bytes.Buffer, error)
IsTypeSupported(format string) bool
}
type DefaultBarcodeService struct {
RedisClient *redis.Client
}
func (b *DefaultBarcodeService) GenerateBarcode(format string, content string, width int, height int) (bytes.Buffer, error) {
ctx := context.Background()
if !b.IsTypeSupported(format) {
return bytes.Buffer{}, fmt.Errorf("unsupported barcode type: %s", format)
}
if b.RedisClient != nil {
cachedBarcode, err := b.RedisClient.Get(ctx, fmt.Sprintf("barcode:%s:%s:%d:%d", format, content, width, height)).Result()
if err == nil {
log.Printf("Cache hit for barcode:%s:%s:%d:%d", format, content, width, height)
buf := bytes.Buffer{}
buf.Write([]byte(cachedBarcode))
return buf, nil
}
}
var generatedCode barcode.Barcode
var err error
switch format {
case "ean13":
generatedCode, err = ean.Encode(content)
if err != nil {
return bytes.Buffer{}, err
}
break
case "code128":
generatedCode, err = code128.Encode(content)
if err != nil {
return bytes.Buffer{}, err
}
break
case "qr":
generatedCode, err = qr.Encode(content, qr.M, qr.AlphaNumeric)
if err != nil {
return bytes.Buffer{}, err
}
break
}
scaledCode, err := barcode.Scale(generatedCode, width, height)
if err != nil {
return bytes.Buffer{}, err
}
var buf bytes.Buffer
err = png.Encode(&buf, scaledCode)
if err != nil {
return bytes.Buffer{}, err
}
if b.RedisClient != nil {
err = b.RedisClient.Set(ctx, fmt.Sprintf("barcode:%s:%s:%d:%d", format, content, width, height), buf.String(), 10*time.Minute).Err()
if err != nil {
return bytes.Buffer{}, err
}
}
return buf, nil
}
func (b *DefaultBarcodeService) IsTypeSupported(format string) bool {
supportedTypes := []string{"ean13", "code128", "qr"}
return slices.Contains(supportedTypes, format)
}