From c408afc8797b0da5e1d73d190a8f5884870b510c Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 13 May 2025 12:50:20 +0200 Subject: style(files): reorganize everything --- user/level.go | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 user/level.go (limited to 'user/level.go') diff --git a/user/level.go b/user/level.go new file mode 100644 index 0000000..0abd642 --- /dev/null +++ b/user/level.go @@ -0,0 +1,207 @@ +package user + +import ( + "github.com/anhgelus/gokord" + "github.com/anhgelus/gokord/utils" + "github.com/anhgelus/les-copaings-bot/config" + "github.com/anhgelus/les-copaings-bot/exp" + "github.com/bwmarrin/discordgo" + "slices" + "sync" + "time" +) + +func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { + cfg := config.GetGuildConfig(m.GuildID) + xpForLevel := exp.LevelXP(level) + for _, role := range cfg.XpRoles { + if role.XP <= xpForLevel && !slices.Contains(m.Roles, role.RoleID) { + utils.SendDebug( + "Add role", + "role_id", role.RoleID, + "user_id", m.User.ID, + "guild_id", m.GuildID, + ) + err := dg.GuildMemberRoleAdd(m.GuildID, m.User.ID, role.RoleID) + if err != nil { + utils.SendAlert("exp/level.go - Adding role", err.Error(), "role_id", role.RoleID) + } + } else if role.XP > xpForLevel && slices.Contains(m.Roles, role.RoleID) { + utils.SendDebug( + "Remove role", + "role_id", role.RoleID, + "user_id", m.User.ID, + "guild_id", m.GuildID, + ) + err := dg.GuildMemberRoleRemove(m.GuildID, m.User.ID, role.RoleID) + if err != nil { + utils.SendAlert("exp/level.go - Removing role", err.Error(), "role_id", role.RoleID) + } + } + } +} + +func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) { + m, err := dg.GuildMember(c.GuildID, c.DiscordID) + if err != nil { + utils.SendAlert( + "exp/level.go - Getting member for new level", err.Error(), + "discord_id", c.DiscordID, + "guild_id", c.GuildID, + ) + return + } + onNewLevel(dg, m, level) +} + +func LastEventUpdate(dg *discordgo.Session, c *Copaing) { + h := c.HourSinceLastEvent() + l := exp.Lose(h, c.XP) + xp := c.XPAlreadyRemoved() + oldXP := c.XP + if l-xp < 0 { + utils.SendWarn("lose - exp already removed is negative", "lose", l, "exp", xp) + c.XP = 0 + } else { + calc := int(c.XP) - int(l) + int(c.XPAlreadyRemoved()) + if calc < 0 { + c.XP = 0 + } else { + c.XP = uint(calc) + } + } + if oldXP != c.XP { + lvl := exp.Level(c.XP) + if exp.Level(oldXP) != lvl { + utils.SendDebug( + "Level changed", + "old", exp.Level(oldXP), + "new", lvl, + "discord_id", c.DiscordID, + "guild_id", c.GuildID, + ) + c.OnNewLevel(dg, lvl) + } + if err := c.Save(); err != nil { + utils.SendAlert( + "exp/level.go - Saving user", err.Error(), + "exp", c.XP, + "discord_id", c.DiscordID, + "guild_id", c.GuildID, + ) + } + } + c.SetLastEvent() +} + +func UpdateXP(dg *discordgo.Session, c *Copaing) { + oldXP := c.XP + if oldXP == 0 { + return + } + h := c.HourSinceLastEvent() + l := exp.Lose(h, c.XP) + xp := c.XPAlreadyRemoved() + if l-xp < 0 { + utils.SendWarn("lose - xp_removed is negative", "lose", l, "exp removed", xp) + c.AddXPAlreadyRemoved(0) + } else { + calc := int(c.XP) - int(l) + int(xp) + if calc < 0 { + c.AddXPAlreadyRemoved(c.XP) + c.XP = 0 + } else { + c.XP = uint(calc) + c.AddXPAlreadyRemoved(l - xp) + } + } + if oldXP != c.XP { + lvl := exp.Level(c.XP) + if exp.Level(oldXP) != lvl { + utils.SendDebug( + "Level updated", + "old", exp.Level(oldXP), + "new", lvl, + "discord_id", c.DiscordID, + "guild_id", c.GuildID, + ) + c.OnNewLevel(dg, lvl) + } + utils.SendDebug("Save XP", "old", oldXP, "new", c.XP, "user", c.DiscordID) + if err := c.Save(); err != nil { + utils.SendAlert( + "exp/level.go - Saving user", err.Error(), + "exp", c.XP, + "discord_id", c.DiscordID, + "guild_id", c.GuildID, + ) + } + } +} + +func PeriodicReducer(dg *discordgo.Session) { + var wg sync.WaitGroup + for _, g := range dg.State.Guilds { + var cs []*Copaing + err := gokord.DB.Where("guild_id = ?", g.ID).Find(&cs).Error + if err != nil { + utils.SendAlert("exp/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID) + continue + } + for i, c := range cs { + if i%50 == 49 { + time.Sleep(15 * time.Second) // sleep prevents from spamming the Discord API and the database + } + var u *discordgo.User + u, err = dg.User(c.DiscordID) + if err != nil { + utils.SendAlert( + "exp/level.go - Fetching user", err.Error(), + "discord_id", c.DiscordID, + "guild_id", g.ID, + ) + utils.SendWarn("Removing user from database", "discord_id", c.DiscordID) + if err = gokord.DB.Delete(c).Error; err != nil { + utils.SendAlert( + "exp/level.go - Removing user from database", err.Error(), + "discord_id", c.DiscordID, + "guild_id", g.ID, + ) + } + continue + } + if u.Bot { + continue + } + if _, err = dg.GuildMember(g.ID, c.DiscordID); err != nil { + utils.SendAlert( + "exp/level.go - Fetching member", err.Error(), + "discord_id", c.DiscordID, + "guild_id", g.ID, + ) + utils.SendWarn( + "Removing user from guild in database", + "discord_id", c.DiscordID, + "guild_id", g.ID, + ) + if err = gokord.DB.Where("guild_id = ?", g.ID).Delete(c).Error; err != nil { + utils.SendAlert( + "exp/level.go - Removing user from guild in database", err.Error(), + "discord_id", c.DiscordID, + "guild_id", g.ID, + ) + } + continue + } + wg.Add(1) + go func() { + UpdateXP(dg, c) + wg.Done() + }() + } + wg.Wait() // finish the entire guild before starting another + utils.SendDebug("Periodic reduce, guild finished", "guild", g.Name) + time.Sleep(15 * time.Second) // sleep prevents from spamming the Discord API and the database + } + utils.SendDebug("Periodic reduce finished", "len(guilds)", len(dg.State.Guilds)) +} -- cgit v1.2.3 From d38c57b83009bf0a8b22bede7ee786d6f54fc66a Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 13 May 2025 13:00:09 +0200 Subject: fix(log): wrong pos in many alerts --- user/level.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'user/level.go') diff --git a/user/level.go b/user/level.go index 0abd642..122b707 100644 --- a/user/level.go +++ b/user/level.go @@ -24,7 +24,7 @@ func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { ) err := dg.GuildMemberRoleAdd(m.GuildID, m.User.ID, role.RoleID) if err != nil { - utils.SendAlert("exp/level.go - Adding role", err.Error(), "role_id", role.RoleID) + utils.SendAlert("user/level.go - Adding role", err.Error(), "role_id", role.RoleID) } } else if role.XP > xpForLevel && slices.Contains(m.Roles, role.RoleID) { utils.SendDebug( @@ -35,7 +35,7 @@ func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { ) err := dg.GuildMemberRoleRemove(m.GuildID, m.User.ID, role.RoleID) if err != nil { - utils.SendAlert("exp/level.go - Removing role", err.Error(), "role_id", role.RoleID) + utils.SendAlert("user/level.go - Removing role", err.Error(), "role_id", role.RoleID) } } } @@ -45,7 +45,7 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) { m, err := dg.GuildMember(c.GuildID, c.DiscordID) if err != nil { utils.SendAlert( - "exp/level.go - Getting member for new level", err.Error(), + "user/level.go - Getting member for new level", err.Error(), "discord_id", c.DiscordID, "guild_id", c.GuildID, ) @@ -60,7 +60,7 @@ func LastEventUpdate(dg *discordgo.Session, c *Copaing) { xp := c.XPAlreadyRemoved() oldXP := c.XP if l-xp < 0 { - utils.SendWarn("lose - exp already removed is negative", "lose", l, "exp", xp) + utils.SendWarn("lose - xp already removed is negative", "lose", l, "xp", xp) c.XP = 0 } else { calc := int(c.XP) - int(l) + int(c.XPAlreadyRemoved()) @@ -84,7 +84,7 @@ func LastEventUpdate(dg *discordgo.Session, c *Copaing) { } if err := c.Save(); err != nil { utils.SendAlert( - "exp/level.go - Saving user", err.Error(), + "user/level.go - Saving user", err.Error(), "exp", c.XP, "discord_id", c.DiscordID, "guild_id", c.GuildID, @@ -103,7 +103,7 @@ func UpdateXP(dg *discordgo.Session, c *Copaing) { l := exp.Lose(h, c.XP) xp := c.XPAlreadyRemoved() if l-xp < 0 { - utils.SendWarn("lose - xp_removed is negative", "lose", l, "exp removed", xp) + utils.SendWarn("lose - xp_removed is negative", "lose", l, "xp removed", xp) c.AddXPAlreadyRemoved(0) } else { calc := int(c.XP) - int(l) + int(xp) @@ -130,8 +130,8 @@ func UpdateXP(dg *discordgo.Session, c *Copaing) { utils.SendDebug("Save XP", "old", oldXP, "new", c.XP, "user", c.DiscordID) if err := c.Save(); err != nil { utils.SendAlert( - "exp/level.go - Saving user", err.Error(), - "exp", c.XP, + "user/level.go - Saving user", err.Error(), + "xp", c.XP, "discord_id", c.DiscordID, "guild_id", c.GuildID, ) @@ -145,7 +145,7 @@ func PeriodicReducer(dg *discordgo.Session) { var cs []*Copaing err := gokord.DB.Where("guild_id = ?", g.ID).Find(&cs).Error if err != nil { - utils.SendAlert("exp/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID) + utils.SendAlert("user/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID) continue } for i, c := range cs { @@ -156,14 +156,14 @@ func PeriodicReducer(dg *discordgo.Session) { u, err = dg.User(c.DiscordID) if err != nil { utils.SendAlert( - "exp/level.go - Fetching user", err.Error(), + "user/level.go - Fetching user", err.Error(), "discord_id", c.DiscordID, "guild_id", g.ID, ) utils.SendWarn("Removing user from database", "discord_id", c.DiscordID) if err = gokord.DB.Delete(c).Error; err != nil { utils.SendAlert( - "exp/level.go - Removing user from database", err.Error(), + "user/level.go - Removing user from database", err.Error(), "discord_id", c.DiscordID, "guild_id", g.ID, ) @@ -175,7 +175,7 @@ func PeriodicReducer(dg *discordgo.Session) { } if _, err = dg.GuildMember(g.ID, c.DiscordID); err != nil { utils.SendAlert( - "exp/level.go - Fetching member", err.Error(), + "user/level.go - Fetching member", err.Error(), "discord_id", c.DiscordID, "guild_id", g.ID, ) @@ -186,7 +186,7 @@ func PeriodicReducer(dg *discordgo.Session) { ) if err = gokord.DB.Where("guild_id = ?", g.ID).Delete(c).Error; err != nil { utils.SendAlert( - "exp/level.go - Removing user from guild in database", err.Error(), + "user/level.go - Removing user from guild in database", err.Error(), "discord_id", c.DiscordID, "guild_id", g.ID, ) -- cgit v1.2.3 From e0a8f6634424f10a22b0a0740e0bbc17534eaa0e Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 13 May 2025 13:26:32 +0200 Subject: refactor(xp): remove reducer --- user/level.go | 87 +---------------------------------------------------------- 1 file changed, 1 insertion(+), 86 deletions(-) (limited to 'user/level.go') diff --git a/user/level.go b/user/level.go index 122b707..1143c59 100644 --- a/user/level.go +++ b/user/level.go @@ -54,91 +54,6 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) { onNewLevel(dg, m, level) } -func LastEventUpdate(dg *discordgo.Session, c *Copaing) { - h := c.HourSinceLastEvent() - l := exp.Lose(h, c.XP) - xp := c.XPAlreadyRemoved() - oldXP := c.XP - if l-xp < 0 { - utils.SendWarn("lose - xp already removed is negative", "lose", l, "xp", xp) - c.XP = 0 - } else { - calc := int(c.XP) - int(l) + int(c.XPAlreadyRemoved()) - if calc < 0 { - c.XP = 0 - } else { - c.XP = uint(calc) - } - } - if oldXP != c.XP { - lvl := exp.Level(c.XP) - if exp.Level(oldXP) != lvl { - utils.SendDebug( - "Level changed", - "old", exp.Level(oldXP), - "new", lvl, - "discord_id", c.DiscordID, - "guild_id", c.GuildID, - ) - c.OnNewLevel(dg, lvl) - } - if err := c.Save(); err != nil { - utils.SendAlert( - "user/level.go - Saving user", err.Error(), - "exp", c.XP, - "discord_id", c.DiscordID, - "guild_id", c.GuildID, - ) - } - } - c.SetLastEvent() -} - -func UpdateXP(dg *discordgo.Session, c *Copaing) { - oldXP := c.XP - if oldXP == 0 { - return - } - h := c.HourSinceLastEvent() - l := exp.Lose(h, c.XP) - xp := c.XPAlreadyRemoved() - if l-xp < 0 { - utils.SendWarn("lose - xp_removed is negative", "lose", l, "xp removed", xp) - c.AddXPAlreadyRemoved(0) - } else { - calc := int(c.XP) - int(l) + int(xp) - if calc < 0 { - c.AddXPAlreadyRemoved(c.XP) - c.XP = 0 - } else { - c.XP = uint(calc) - c.AddXPAlreadyRemoved(l - xp) - } - } - if oldXP != c.XP { - lvl := exp.Level(c.XP) - if exp.Level(oldXP) != lvl { - utils.SendDebug( - "Level updated", - "old", exp.Level(oldXP), - "new", lvl, - "discord_id", c.DiscordID, - "guild_id", c.GuildID, - ) - c.OnNewLevel(dg, lvl) - } - utils.SendDebug("Save XP", "old", oldXP, "new", c.XP, "user", c.DiscordID) - if err := c.Save(); err != nil { - utils.SendAlert( - "user/level.go - Saving user", err.Error(), - "xp", c.XP, - "discord_id", c.DiscordID, - "guild_id", c.GuildID, - ) - } - } -} - func PeriodicReducer(dg *discordgo.Session) { var wg sync.WaitGroup for _, g := range dg.State.Guilds { @@ -195,7 +110,7 @@ func PeriodicReducer(dg *discordgo.Session) { } wg.Add(1) go func() { - UpdateXP(dg, c) + //do things wg.Done() }() } -- cgit v1.2.3 From eaf9fa51cdd9509c5d075633b712ec9b5ea712c7 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 13 May 2025 17:35:03 +0200 Subject: perf(db): remove useless XP data --- user/level.go | 73 +++++++++++------------------------------------------------ 1 file changed, 13 insertions(+), 60 deletions(-) (limited to 'user/level.go') diff --git a/user/level.go b/user/level.go index 1143c59..5f847b6 100644 --- a/user/level.go +++ b/user/level.go @@ -8,7 +8,6 @@ import ( "github.com/bwmarrin/discordgo" "slices" "sync" - "time" ) func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { @@ -55,68 +54,22 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) { } func PeriodicReducer(dg *discordgo.Session) { - var wg sync.WaitGroup + wg := &sync.WaitGroup{} for _, g := range dg.State.Guilds { - var cs []*Copaing - err := gokord.DB.Where("guild_id = ?", g.ID).Find(&cs).Error - if err != nil { - utils.SendAlert("user/level.go - Querying all copaings in Guild", err.Error(), "guild_id", g.ID) - continue - } - for i, c := range cs { - if i%50 == 49 { - time.Sleep(15 * time.Second) // sleep prevents from spamming the Discord API and the database - } - var u *discordgo.User - u, err = dg.User(c.DiscordID) + wg.Add(1) + go func() { + defer wg.Done() + cfg := config.GetGuildConfig(g.ID) + err := gokord.DB. + Model(&CopaingXP{}). + Where("guild_id = ? and created_at < ?", g.ID, exp.TimeStampNDaysBefore(cfg.DaysXPRemains)). + Delete(&CopaingXP{}). + Error if err != nil { - utils.SendAlert( - "user/level.go - Fetching user", err.Error(), - "discord_id", c.DiscordID, - "guild_id", g.ID, - ) - utils.SendWarn("Removing user from database", "discord_id", c.DiscordID) - if err = gokord.DB.Delete(c).Error; err != nil { - utils.SendAlert( - "user/level.go - Removing user from database", err.Error(), - "discord_id", c.DiscordID, - "guild_id", g.ID, - ) - } - continue - } - if u.Bot { - continue + utils.SendAlert("user/level.go - Removing old XP", err.Error(), "guild_id", g.ID) } - if _, err = dg.GuildMember(g.ID, c.DiscordID); err != nil { - utils.SendAlert( - "user/level.go - Fetching member", err.Error(), - "discord_id", c.DiscordID, - "guild_id", g.ID, - ) - utils.SendWarn( - "Removing user from guild in database", - "discord_id", c.DiscordID, - "guild_id", g.ID, - ) - if err = gokord.DB.Where("guild_id = ?", g.ID).Delete(c).Error; err != nil { - utils.SendAlert( - "user/level.go - Removing user from guild in database", err.Error(), - "discord_id", c.DiscordID, - "guild_id", g.ID, - ) - } - continue - } - wg.Add(1) - go func() { - //do things - wg.Done() - }() - } - wg.Wait() // finish the entire guild before starting another - utils.SendDebug("Periodic reduce, guild finished", "guild", g.Name) - time.Sleep(15 * time.Second) // sleep prevents from spamming the Discord API and the database + }() } + wg.Wait() utils.SendDebug("Periodic reduce finished", "len(guilds)", len(dg.State.Guilds)) } -- cgit v1.2.3 From f2fbf1db929e4bd2b3af014fb8d9af4c0f934a1e Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 13 May 2025 18:06:17 +0200 Subject: feat(xp): update role after removing all old xp --- user/level.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'user/level.go') diff --git a/user/level.go b/user/level.go index 5f847b6..6d9b674 100644 --- a/user/level.go +++ b/user/level.go @@ -8,6 +8,7 @@ import ( "github.com/bwmarrin/discordgo" "slices" "sync" + "time" ) func onNewLevel(dg *discordgo.Session, m *discordgo.Member, level uint) { @@ -55,6 +56,31 @@ func (c *Copaing) OnNewLevel(dg *discordgo.Session, level uint) { func PeriodicReducer(dg *discordgo.Session) { wg := &sync.WaitGroup{} + var cs []*Copaing + if err := gokord.DB.Find(&cs).Error; err != nil { + utils.SendAlert("user/level.go - Fetching all copaings", err.Error()) + return + } + cxps := make([]*cXP, len(cs)) + for i, c := range cs { + if i%10 == 9 { + wg.Wait() // prevents spamming the DB + } + wg.Add(1) + go func() { + defer wg.Done() + xp, err := c.GetXP() + if err != nil { + utils.SendAlert("user/level.go - Getting XP", err.Error(), "copaing_id", c.ID, "guild_id", c.GuildID) + xp = 0 + } + cxps[i] = &cXP{ + Cxp: xp, + Copaing: c, + } + }() + } + wg.Wait() for _, g := range dg.State.Guilds { wg.Add(1) go func() { @@ -71,5 +97,20 @@ func PeriodicReducer(dg *discordgo.Session) { }() } wg.Wait() + for i, c := range cxps { + if i%50 == 49 { + utils.SendDebug("Sleeping...") + time.Sleep(15 * time.Second) // prevents spamming the API + } + oldXp := c.GetXP() + xp, err := c.ToCopaing().GetXP() + if err != nil { + utils.SendAlert("user/level.go - Getting XP", err.Error(), "guild_id", c.ID, "discord_id", c.DiscordID) + continue + } + if exp.Level(oldXp) != exp.Level(xp) { + c.OnNewLevel(dg, exp.Level(xp)) + } + } utils.SendDebug("Periodic reduce finished", "len(guilds)", len(dg.State.Guilds)) } -- cgit v1.2.3