From c661541e45dddd6a082af66fcf7df7ba7dfdc6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Herg=C3=A8s?= Date: Sat, 17 Jan 2026 21:50:54 +0100 Subject: perf(command): store data used by top in state --- user/xp.go | 96 +++++++++++--------------------------------------------------- 1 file changed, 16 insertions(+), 80 deletions(-) (limited to 'user/xp.go') diff --git a/user/xp.go b/user/xp.go index 9c6c6ab..c87c450 100644 --- a/user/xp.go +++ b/user/xp.go @@ -2,13 +2,10 @@ package user import ( "context" - "log/slog" "slices" - "sync" + "time" - "git.anhgelus.world/anhgelus/les-copaings-bot/config" "git.anhgelus.world/anhgelus/les-copaings-bot/exp" - "github.com/anhgelus/gokord" "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/user" ) @@ -27,10 +24,10 @@ func (c *cXP) GetXP() uint { } func (cc *CopaingCached) AddXP(ctx context.Context, s bot.Session, m *user.Member, xp uint, fn func(uint, uint)) { - old := cc.XPs + old := cc.XP pastLevel := exp.Level(old) s.Logger().Debug("adding xp", "user", m.DisplayName(), "old", old, "to add", xp) - cc.XPs += xp + cc.XP += xp cc.XPToAdd += xp if err := cc.Save(ctx); err != nil { s.Logger().Error("saving user in state", "error", err, "user", m.DisplayName(), "xp", xp, "guild", cc.GuildID) @@ -43,88 +40,27 @@ func (cc *CopaingCached) AddXP(ctx context.Context, s bot.Session, m *user.Membe } } -func (c *Copaing) GetXP(logger *slog.Logger) (uint, error) { - cfg := config.GetGuildConfig(c.GuildID) - return c.GetXPForDays(logger, cfg.DaysXPRemains) -} - -func (c *Copaing) GetXPForDays(logger *slog.Logger, n uint) (uint, error) { +func (cc *CopaingCached) GetXPForDays(n uint) uint { xp := uint(0) - rows, err := gokord.DB. - Model(&CopaingXP{}). - Where( - "created_at >= ? and guild_id = ? and copaing_id = ?", - exp.TimeStampNDaysBefore(n), - c.GuildID, - c.ID, - ). - Rows() - if err != nil { - return 0, err - } - defer rows.Close() - for rows.Next() { - var cxp CopaingXP - err = gokord.DB.ScanRows(rows, &cxp) - if err != nil { - logger.Error("scanning rows", "error", err, "copaing", c.ID, "guild", c.GuildID) - continue + for _, v := range cc.XPs { + if v.Time <= time.Duration(n*24)*time.Hour { + xp += v.XP } - xp += cxp.XP } - return xp, nil + return xp + cc.XPToAdd } // GetBestXP returns n Copaing with the best XP within d days (d <= cfg.DaysXPRemain; d < 0 <=> d = cfg.DaysXPRemain) -// -// This function is slow -func GetBestXP(ctx context.Context, logger *slog.Logger, guildId string, n uint, d int) ([]CopaingCached, error) { - if d < 0 { - cfg := config.GetGuildConfig(guildId) - d = int(cfg.DaysXPRemains) - return getBestXPFull(ctx, guildId, n), nil - } - rows, err := gokord.DB.Model(&Copaing{}).Where("guild_id = ?", guildId).Rows() - if err != nil { - return nil, err - } - defer rows.Close() - var l []*cXP - var wg sync.WaitGroup - for rows.Next() { - var c Copaing - err = gokord.DB.ScanRows(rows, &c) - if err != nil { - logger.Error("scanning rows", "error", err, "copaing", c.ID, "guild", c.GuildID) - continue +func GetBestXP(ctx context.Context, guildId string, n uint, d int) ([]CopaingCached, error) { + ccs := GetState(ctx).Copaings(guildId) + if d > 0 { + for _, v := range ccs { + v.XP = v.GetXPForDays(n) } - wg.Go(func() { - xp, err := c.GetXPForDays(logger, uint(d)) - if err != nil { - logger.Error("fetching xp", "error", err, "copaing", c.ID, "guild", c.GuildID) - return - } - l = append(l, &cXP{Cxp: xp, copaing: &c}) - }) } - wg.Wait() - slices.SortFunc(l, func(a, b *cXP) int { - // desc order - return int(b.Cxp) - int(a.Cxp) - }) - m := min(len(l), int(n)) - cs := make([]CopaingCached, m) - for i, c := range l[:m] { - cs[i] = CopaingCached{DiscordID: c.copaing.DiscordID, XPs: c.Cxp} - } - return cs, nil -} - -func getBestXPFull(ctx context.Context, guildId string, n uint) []CopaingCached { - ccs := GetState(ctx).Copaings(guildId) slices.SortFunc(ccs, func(a, b CopaingCached) int { - return int(b.XPs) - int(a.XPs) + // desc order + return int(b.XP) - int(a.XP) }) - m := min(len(ccs), int(n)) - return ccs[:m] + return ccs[:min(len(ccs), int(n))], nil } -- cgit v1.2.3