From 9c3f1ea5ffe9ad70caf306faff7a3e3948cef6ab Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Mon, 9 Mar 2026 18:47:40 +0100 Subject: feat(config): preload role react --- config/channel.go | 5 +- config/guild.go | 79 ++++++++---------------------- config/role_react.go | 124 +++++++++++++++++++++++++++++++++++++++++++++++ config/xp_reduce.go | 3 +- config/xp_role.go | 23 +++++++-- config/xp_role_events.go | 23 ++++----- 6 files changed, 179 insertions(+), 78 deletions(-) create mode 100644 config/role_react.go (limited to 'config') diff --git a/config/channel.go b/config/channel.go index a015aef..6a16e71 100644 --- a/config/channel.go +++ b/config/channel.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "git.anhgelus.world/anhgelus/les-copaings-bot/common" "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/interaction" @@ -31,7 +32,7 @@ func HandleModifyFallbackChannel(ctx context.Context, dg bot.Session, i *interac } } cfg.FallbackChannel = channelID - err := cfg.Save(ctx) + err := cfg.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("saving fallback channel", "error", err) return false @@ -42,7 +43,7 @@ func HandleModifyFallbackChannel(ctx context.Context, dg bot.Session, i *interac func HandleModifyDisChannel(ctx context.Context, dg bot.Session, i *interaction.MessageComponent) bool { cfg := GetGuild(ctx, i.GuildID) cfg.DisabledChannels = strings.Join(i.Data.Values, ";") - err := cfg.Save(ctx) + err := cfg.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("unable to save disabled channel", "error", err) return false diff --git a/config/guild.go b/config/guild.go index aec78ed..10e30ff 100644 --- a/config/guild.go +++ b/config/guild.go @@ -15,40 +15,22 @@ import ( type Guild struct { ID uint64 - XpRoles []XpRole + XpRoles []*XpRole DisabledChannels string FallbackChannel uint64 DaysXPRemains uint - RrMessages []RoleReactMessage -} - -type RoleReactMessage struct { - ID uint `gorm:"primarykey"` - MessageID uint64 `gorm:"not null;unique"` - ChannelID uint64 - GuildID uint64 - Note string - Roles []*RoleReact -} - -type RoleReact struct { - ID uint `gorm:"primarykey"` - Reaction string - RoleID uint64 - RoleReactMessageID uint - CounterID uint `gorm:"-"` + RrMessages []*RoleReactMessage } func GetGuild(ctx context.Context, guildID uint64) *Guild { cfg := Guild{ID: guildID} - if err := cfg.Load(ctx); err != nil { + if err := cfg.load(ctx, common.GetDB(ctx)); err != nil { panic(err) } return &cfg } -func (g *Guild) Load(ctx context.Context) error { - db := common.GetDB(ctx) +func (g *Guild) load(ctx context.Context, db *sql.DB) error { row := db.QueryRowContext( ctx, `SELECT disabled_channels, fallback_channel, days_xp_remains FROM guilds WHERE id = ?`, @@ -72,12 +54,15 @@ func (g *Guild) Load(ctx context.Context) error { if err != nil { return err } - g.XpRoles, err = getXpRoles(ctx, g.ID) + g.XpRoles, err = getXpRoles(ctx, db, g.ID) + if err != nil { + return err + } + g.RrMessages, err = getRoleReactMessages(ctx, db, g.ID) return err } -func (g *Guild) Save(ctx context.Context) error { - db := common.GetDB(ctx) +func (g *Guild) Save(ctx context.Context, db *sql.DB) error { _, err := db.ExecContext( ctx, `UPDATE guilds SET disabled_channels = ?, fallback_channel = ?, days_xp_remains = ? WHERE id = ?`, @@ -86,19 +71,19 @@ func (g *Guild) Save(ctx context.Context) error { if err != nil { return err } - savedRoles, err := getXpRoles(ctx, g.ID) + savedRoles, err := getXpRoles(ctx, db, g.ID) if err != nil { return err } - roleEqual := func(base XpRole) func(XpRole) bool { - return func(v XpRole) bool { + roleEqual := func(base *XpRole) func(*XpRole) bool { + return func(v *XpRole) bool { return v.GuildID == base.GuildID && v.RoleID == base.RoleID && v.XP == base.XP } } // super slow code, but I don't want to implement a data structure to optimize this for _, role := range g.XpRoles { if !slices.ContainsFunc(savedRoles, roleEqual(role)) { - err = role.Save(ctx) + err = role.Save(ctx, db) if err != nil { return err } @@ -106,7 +91,7 @@ func (g *Guild) Save(ctx context.Context) error { } for _, role := range savedRoles { if !slices.ContainsFunc(g.XpRoles, roleEqual(role)) { - err = role.Delete(ctx) + err = role.Delete(ctx, db) if err != nil { return err } @@ -133,37 +118,11 @@ func (g *Guild) IsDisabled(ctx context.Context, dg bot.Session, channelID uint64 return !ok } -func (g *Guild) FindXpRole(roleID uint64) (int, *XpRole) { - for i, r := range g.XpRoles { +func (g *Guild) FindXpRole(roleID uint64) *XpRole { + for _, r := range g.XpRoles { if r.RoleID == roleID { - return i, &r - } - } - return 0, nil -} - -func getXpRoles(ctx context.Context, gID uint64) ([]XpRole, error) { - roles := make([]XpRole, 0) - rows, err := common.GetDB(ctx).QueryContext( - ctx, - `SELECT xp, role FROM xp_roles WHERE guild_id = ?`, - gID, - ) - if err == nil { - defer rows.Close() - for rows.Next() { - var role XpRole - err = rows.Scan(&role.XP, &role.RoleID) - if err != nil { - return roles, err - } - role.GuildID = gID - roles = append(roles, role) - } - } else { - if !errors.Is(err, sql.ErrNoRows) { - return roles, err + return r } } - return roles, nil + return nil } diff --git a/config/role_react.go b/config/role_react.go new file mode 100644 index 0000000..70e6cb0 --- /dev/null +++ b/config/role_react.go @@ -0,0 +1,124 @@ +package config + +import ( + "context" + "database/sql" + + "git.anhgelus.world/anhgelus/les-copaings-bot/common" +) + +type RoleReactMessage struct { + MessageID uint64 + ChannelID uint64 + GuildID uint64 + Note string + Roles []*RoleReact +} + +func (rrm *RoleReactMessage) Load(ctx context.Context, db *sql.DB, rows *sql.Rows) error { + err := rows.Scan(&rrm.MessageID, &rrm.ChannelID, &rrm.GuildID, &rrm.Note) + if err != nil { + return err + } + rrm.Roles, err = getRoleReacts(ctx, db, rrm.MessageID) + return err +} + +func (rrm *RoleReactMessage) Save(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( + ctx, + `INSERT INTO role_react_messages (message_id, channel_id, guild_id, note) VALUES (?, ?, ?, ?)`, + rrm.MessageID, rrm.ChannelID, rrm.GuildID, rrm.Note, + ) + return err +} + +func (rrm *RoleReactMessage) Delete(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( + ctx, + `DELETE FROM role_react_messages WHERE message_id = ?`, + rrm.MessageID, + ) + return err +} + +func getRoleReactMessages(ctx context.Context, db *sql.DB, gID uint64) ([]*RoleReactMessage, error) { + return common.GetValues[*RoleReactMessage]( + ctx, + db, + `role_react_messages`, + `message_id, channel_id, guild_id, note`, + `guild_id = ?`, gID, + ) +} + +type RoleReact struct { + ID uint + Reaction string + RoleID uint64 + MessageID uint + CounterID uint +} + +/*func (rr *RoleReact) Load(ctx context.Context, db *sql.DB) error { + row := db.QueryRowContext( + ctx, + `SELECT role, message_id, reaction FROM role_reacts WHERE id = ?`, + rr.ID, + ) + err := row.Err() + + if err == nil { + return row.Scan(&rr.RoleID, &rr.MessageID, &rr.Reaction) + } + + if !errors.Is(err, sql.ErrNoRows) { + return err + } + res, err := db.ExecContext( + ctx, + `INSERT INTO role_reacts (role, message_id, reaction) VALUES (?, ?, ?)`, + rr.RoleID, rr.MessageID, rr.Reaction, + ) + if err != nil { + return err + } + idr, err := res.LastInsertId() + if err != nil { + return err + } + rr.ID = uint(idr) + return nil +}*/ + +func (rr *RoleReact) Save(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( + ctx, + `UPDATE role_reacts SET role = ?, reaction = ? VALUES (?, ?) WHERE id = ?`, + rr.RoleID, rr.Reaction, rr.ID, + ) + return err +} + +func (rr *RoleReact) Delete(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( + ctx, + `DELETE FROM role_reacts WHERE id = ?`, + rr.ID, + ) + return err +} + +func (rr *RoleReact) Load(_ context.Context, _ *sql.DB, rows *sql.Rows) error { + return rows.Scan(&rr.ID, &rr.MessageID, &rr.Reaction, &rr.RoleID) +} + +func getRoleReacts(ctx context.Context, db *sql.DB, mID uint64) ([]*RoleReact, error) { + return common.GetValues[*RoleReact]( + ctx, + db, + `role_reacts`, + `id, message_id, reaction, role_id`, + `message_id = ?`, mID, + ) +} diff --git a/config/xp_reduce.go b/config/xp_reduce.go index baa4586..51607b1 100644 --- a/config/xp_reduce.go +++ b/config/xp_reduce.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" + "git.anhgelus.world/anhgelus/les-copaings-bot/common" "github.com/nyttikord/gokord/bot" "github.com/nyttikord/gokord/component" "github.com/nyttikord/gokord/interaction" @@ -68,7 +69,7 @@ func HandleTimeReduceSet(ctx context.Context, dg bot.Session, i *interaction.Mod } cfg := GetGuild(ctx, i.GuildID) cfg.DaysXPRemains = uint(days) - err = cfg.Save(ctx) + err = cfg.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("saving DaysXPRemains configuration", "error", err) return false diff --git a/config/xp_role.go b/config/xp_role.go index f0d57c8..ab684c5 100644 --- a/config/xp_role.go +++ b/config/xp_role.go @@ -2,6 +2,7 @@ package config import ( "context" + "database/sql" "git.anhgelus.world/anhgelus/les-copaings-bot/common" ) @@ -12,8 +13,12 @@ type XpRole struct { GuildID uint64 } -func (xp XpRole) Save(ctx context.Context) error { - _, err := common.GetDB(ctx).ExecContext( +func (xp *XpRole) Load(_ context.Context, _ *sql.DB, rows *sql.Rows) error { + return rows.Scan(&xp.XP, &xp.RoleID, &xp.GuildID) +} + +func (xp *XpRole) Save(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( ctx, `INSERT INTO xp_roles (xp, role, guild_id) VALUES (?, ?, ?)`, xp.XP, xp.RoleID, xp.GuildID, @@ -21,11 +26,21 @@ func (xp XpRole) Save(ctx context.Context) error { return err } -func (xp XpRole) Delete(ctx context.Context) error { - _, err := common.GetDB(ctx).ExecContext( +func (xp *XpRole) Delete(ctx context.Context, db *sql.DB) error { + _, err := db.ExecContext( ctx, `DELETE FROM xp_roles WHERE xp = ? AND role = ? AND guild_id = ?`, xp.XP, xp.RoleID, xp.GuildID, ) return err } + +func getXpRoles(ctx context.Context, db *sql.DB, gID uint64) ([]*XpRole, error) { + return common.GetValues[*XpRole]( + ctx, + db, + `xp_roles`, + `xp, role, guild_id`, + `guild_id = ?`, gID, + ) +} diff --git a/config/xp_role_events.go b/config/xp_role_events.go index cda90d5..47026b5 100644 --- a/config/xp_role_events.go +++ b/config/xp_role_events.go @@ -6,6 +6,7 @@ import ( "slices" "strconv" + "git.anhgelus.world/anhgelus/les-copaings-bot/common" "git.anhgelus.world/anhgelus/les-copaings-bot/dynamicid" "git.anhgelus.world/anhgelus/les-copaings-bot/exp" "github.com/nyttikord/gokord/bot" @@ -39,7 +40,7 @@ func HandleXpRole(ctx context.Context, dg bot.Session, i *interaction.Interactio &component.Separator{}, }, } - slices.SortFunc(cfg.XpRoles, func(xp1, xp2 XpRole) int { + slices.SortFunc(cfg.XpRoles, func(xp1, xp2 *XpRole) int { return int(xp2.XP) - int(xp1.XP) }) for _, r := range cfg.XpRoles { @@ -122,7 +123,7 @@ func HandleXpRoleNew(ctx context.Context, dg bot.Session, i *interaction.Message func HandleXpRoleEdit(ctx context.Context, dg bot.Session, i *interaction.Interaction, params *XpRoleId) { config := GetGuild(ctx, i.GuildID) id := params.ID - _, role := config.FindXpRole(id) + role := config.FindXpRole(id) if role == nil { HandleXpRole(ctx, dg, i) return @@ -187,7 +188,7 @@ func HandleXpRoleEditRole(ctx context.Context, dg bot.Session, i *interaction.Me panic(err) } cfg := GetGuild(ctx, i.GuildID) - _, xpRole := cfg.FindXpRole(id) + xpRole := cfg.FindXpRole(id) if xpRole == nil { err := interaction.Respond(i.Interaction, &interaction.Response{ Type: types.InteractionResponseChannelMessageWithSource, @@ -202,7 +203,7 @@ func HandleXpRoleEditRole(ctx context.Context, dg bot.Session, i *interaction.Me return } xpRole.RoleID = role - err = xpRole.Save(ctx) + err = xpRole.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("saving config", "error", err, "guild", i.GuildID, "id", id, "type", "add") } @@ -212,7 +213,7 @@ func HandleXpRoleEditRole(ctx context.Context, dg bot.Session, i *interaction.Me func HandleXpRoleEditLevelStart(ctx context.Context, dg bot.Session, i *interaction.MessageComponent, params *XpRoleId) { id := params.ID cfg := GetGuild(ctx, i.GuildID) - _, xpRole := cfg.FindXpRole(id) + xpRole := cfg.FindXpRole(id) if xpRole == nil { err := interaction.Respond(i.Interaction, &interaction.Response{ Type: types.InteractionResponseChannelMessageWithSource, @@ -272,7 +273,7 @@ func HandleXpRoleEditLevel(ctx context.Context, dg bot.Session, i *interaction.M xp := exp.LevelXP(uint(level)) cfg := GetGuild(ctx, i.GuildID) - _, xpRole := cfg.FindXpRole(id) + xpRole := cfg.FindXpRole(id) if xpRole == nil { err = interaction.Respond(i.Interaction, &interaction.Response{ Type: types.InteractionResponseChannelMessageWithSource, @@ -287,7 +288,7 @@ func HandleXpRoleEditLevel(ctx context.Context, dg bot.Session, i *interaction.M return } xpRole.XP = xp - err = xpRole.Save(ctx) + err = xpRole.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("saving config", "guild", i.GuildID, "id", id, "type", "edit") } @@ -297,7 +298,7 @@ func HandleXpRoleEditLevel(ctx context.Context, dg bot.Session, i *interaction.M func HandleXpRoleDel(ctx context.Context, dg bot.Session, i *interaction.MessageComponent, parameters *XpRoleId) { id := parameters.ID cfg := GetGuild(ctx, i.GuildID) - _, role := cfg.FindXpRole(id) + role := cfg.FindXpRole(id) if role == nil { err := interaction.Respond(i.Interaction, &interaction.Response{ Type: types.InteractionResponseChannelMessageWithSource, @@ -311,7 +312,7 @@ func HandleXpRoleDel(ctx context.Context, dg bot.Session, i *interaction.Message } return } - err := role.Delete(ctx) + err := role.Delete(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("deleting entry", "error", err, "guild", i.GuildID, "id", id, "type", "del") } @@ -344,11 +345,11 @@ func HandleXpRoleAdd(ctx context.Context, dg bot.Session, i *interaction.ModalSu } cfg := GetGuild(ctx, i.GuildID) - cfg.XpRoles = append(cfg.XpRoles, XpRole{ + cfg.XpRoles = append(cfg.XpRoles, &XpRole{ XP: xp, RoleID: roleId, }) - err = cfg.Save(ctx) + err = cfg.Save(ctx, common.GetDB(ctx)) if err != nil { bot.Logger(ctx).Error("saving config", "error", err, "role", roleId, "guild", i.GuildID) return -- cgit v1.2.3