102 lines
2.1 KiB
Go
102 lines
2.1 KiB
Go
package image
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/golang/freetype/truetype"
|
|
|
|
"douyu_go/internal/logger"
|
|
"douyu_go/internal/types"
|
|
)
|
|
|
|
const (
|
|
defaultSuccessImageWorkers = 1
|
|
defaultSuccessImageQueue = 256
|
|
)
|
|
|
|
type successImageJob struct {
|
|
Account types.Account
|
|
Product types.Product
|
|
RoleName string
|
|
}
|
|
|
|
// SuccessImageSaver 用后台队列生成成功图片,避免图片编码和磁盘写入占用抢购链路。
|
|
type SuccessImageSaver struct {
|
|
font *truetype.Font
|
|
successDir string
|
|
ch chan successImageJob
|
|
wg sync.WaitGroup
|
|
|
|
mu sync.Mutex
|
|
closed bool
|
|
}
|
|
|
|
// NewSuccessImageSaver 创建成功图片后台保存器。
|
|
func NewSuccessImageSaver(font *truetype.Font, successDir string, workers, queueSize int) *SuccessImageSaver {
|
|
if font == nil {
|
|
return nil
|
|
}
|
|
if workers <= 0 {
|
|
workers = defaultSuccessImageWorkers
|
|
}
|
|
if queueSize <= 0 {
|
|
queueSize = defaultSuccessImageQueue
|
|
}
|
|
saver := &SuccessImageSaver{
|
|
font: font,
|
|
successDir: successDir,
|
|
ch: make(chan successImageJob, queueSize),
|
|
}
|
|
for i := 0; i < workers; i++ {
|
|
saver.wg.Add(1)
|
|
go saver.run()
|
|
}
|
|
return saver
|
|
}
|
|
|
|
// Enqueue 投递成功图片任务;队列满时丢弃图片任务,优先保护抢购请求。
|
|
func (s *SuccessImageSaver) Enqueue(account types.Account, product types.Product, roleName string) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
job := successImageJob{
|
|
Account: account,
|
|
Product: product,
|
|
RoleName: roleName,
|
|
}
|
|
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.closed {
|
|
return
|
|
}
|
|
select {
|
|
case s.ch <- job:
|
|
default:
|
|
logger.LogEvent("图片", "warn", "成功图片队列已满,已跳过: 账号=%s 商品=%s", account.Name, product.CommodityID)
|
|
}
|
|
}
|
|
|
|
func (s *SuccessImageSaver) run() {
|
|
defer s.wg.Done()
|
|
for job := range s.ch {
|
|
SaveSuccessImage(job.Account, job.Product, job.RoleName, s.font, s.successDir)
|
|
}
|
|
}
|
|
|
|
// Close 关闭后台队列并等待已投递图片保存完成。
|
|
func (s *SuccessImageSaver) Close() {
|
|
if s == nil {
|
|
return
|
|
}
|
|
s.mu.Lock()
|
|
if s.closed {
|
|
s.mu.Unlock()
|
|
return
|
|
}
|
|
s.closed = true
|
|
close(s.ch)
|
|
s.mu.Unlock()
|
|
s.wg.Wait()
|
|
}
|