package accessstat import ( "sync" "time" "gitlink.org.cn/cloudream/common/pkgs/async" "gitlink.org.cn/cloudream/common/pkgs/logger" "gitlink.org.cn/cloudream/jcs-pub/client/internal/db" clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" ) type AccessStatEventChan = async.UnboundChannel[AccessStatEvent] type AccessStatEvent interface { IsAccessStatEvent() bool } type ExitEvent struct { AccessStatEvent Err error } type AccessStat struct { cfg Config done chan any stats []db.AddAccessStatEntry lock sync.Mutex db *db.DB } func NewAccessStat(cfg Config, db *db.DB) *AccessStat { return &AccessStat{ cfg: cfg, done: make(chan any), db: db, } } func (p *AccessStat) AddAccessCounter(objID clitypes.ObjectID, pkgID clitypes.PackageID, spaceID clitypes.UserSpaceID, value float64) { p.lock.Lock() defer p.lock.Unlock() p.stats = append(p.stats, db.AddAccessStatEntry{ ObjectID: objID, PackageID: pkgID, UserSpaceID: spaceID, Counter: value, }) } func (p *AccessStat) Start() *AccessStatEventChan { ch := async.NewUnboundChannel[AccessStatEvent]() go func() { ticker := time.NewTicker(p.cfg.ReportInterval) defer ticker.Stop() for { select { case <-ticker.C: case <-p.done: ch.Send(ExitEvent{}) return } p.lock.Lock() st := p.stats p.stats = nil p.lock.Unlock() if len(st) == 0 { continue } err := db.DoTx10(p.db, p.db.Package().BatchAddPackageAccessStat, st) if err != nil { logger.Errorf("add all package access stat counter: %v", err) p.lock.Lock() p.stats = append(p.stats, st...) p.lock.Unlock() continue } } }() return ch } func (p *AccessStat) Stop() { close(p.done) }