diff --git a/main.go b/main.go index 09835d2..bbe995e 100644 --- a/main.go +++ b/main.go @@ -55,4 +55,5 @@ func main() { func afterInit(dg *discordgo.Session) { dg.AddHandler(xp.OnMessage) + dg.AddHandler(xp.OnVoiceUpdate) } diff --git a/xp/events.go b/xp/events.go index c82c489..13b4a84 100644 --- a/xp/events.go +++ b/xp/events.go @@ -1,26 +1,33 @@ package xp import ( + "context" + "errors" + "fmt" + "github.com/anhgelus/gokord" "github.com/anhgelus/gokord/utils" "github.com/bwmarrin/discordgo" + "github.com/redis/go-redis/v9" + "strconv" + "time" +) + +const ( + ConnectedSince = "connected_since" + NotConnected = -1 + MaxTimeInVocal = 60 * 60 * 6 ) func OnMessage(s *discordgo.Session, m *discordgo.MessageCreate) { c := Copaing{DiscordID: m.Author.ID, GuildID: m.GuildID} c.Load() // add xp - pastLevel := Level(c.XP) trimmed := utils.TrimMessage(m.Content) - c.XP += XPMessage(uint(len(trimmed)), calcDiversity(trimmed)) - c.Save() - newLevel := Level(c.XP) - // handle new level - if pastLevel < newLevel { + c.AddXP(s, XPMessage(uint(len(trimmed)), calcDiversity(trimmed)), func(_ uint, _ uint) { if err := s.MessageReactionAdd(m.ChannelID, m.Message.ID, "⬆"); err != nil { utils.SendAlert("xp/events.go - reaction add new level", "cannot add the reaction: "+err.Error()) } - onNewLevel(s, newLevel) - } + }) } func calcDiversity(msg string) uint { @@ -38,3 +45,87 @@ func calcDiversity(msg string) uint { } return uint(len(chars)) } + +func OnVoiceUpdate(s *discordgo.Session, e *discordgo.VoiceStateUpdate) { + if e.Member.User.Bot { + return + } + redis, err := gokord.BaseCfg.Redis.Get() + if err != nil { + utils.SendAlert("events.go - Getting redis client", err.Error()) + } + if e.BeforeUpdate == nil { + onConnection(s, e, redis) + } else { + onDisconnect(s, e, redis) + } + err = redis.Close() + if err != nil { + utils.SendAlert("events.go - Closing redis client", err.Error()) + } +} + +func onConnection(s *discordgo.Session, e *discordgo.VoiceStateUpdate, r *redis.Client) { + u := gokord.UserBase{DiscordID: e.UserID, GuildID: e.GuildID} + err := r.Set( + context.Background(), + fmt.Sprintf("%s:%s", u.GenKey(), ConnectedSince), + strconv.FormatInt(time.Now().Unix(), 10), + 0, + ).Err() + if err != nil { + utils.SendAlert("events.go - Setting connected_since", err.Error()) + } +} + +func onDisconnect(s *discordgo.Session, e *discordgo.VoiceStateUpdate, r *redis.Client) { + u := gokord.UserBase{DiscordID: e.UserID, GuildID: e.GuildID} + key := fmt.Sprintf("%s:%s", u.GenKey(), ConnectedSince) + res := r.Get(context.Background(), key) + now := time.Now().Unix() + if errors.Is(res.Err(), redis.Nil) { + utils.SendWarn(fmt.Sprintf( + "User %s diconnect from a vocal but does not have a connected_since", + e.Member.DisplayName(), + )) + return + } + if res.Err() != nil { + utils.SendAlert("events.go - Getting connected_since", res.Err().Error()) + err := r.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err() + if err != nil { + utils.SendAlert("events.go - Set connected_since to not connected after get err", err.Error()) + } + return + } + con, err := res.Int64() + if err != nil { + utils.SendAlert("events.go - Converting result to int64", err.Error()) + return + } + if con == NotConnected { + utils.SendWarn(fmt.Sprintf( + "User %s diconnect from a vocal but was registered as not connected", + e.Member.DisplayName(), + )) + return + } + err = r.Set(context.Background(), key, strconv.Itoa(NotConnected), 0).Err() + if err != nil { + utils.SendAlert("events.go - Set connected_since to not connected", err.Error()) + } + timeInVocal := now - con + if timeInVocal < 0 { + utils.SendAlert("events.go - Calculating time spent in vocal", "the time is negative") + return + } + if timeInVocal > MaxTimeInVocal { + utils.SendWarn(fmt.Sprintf("User %s spent more than 6 hours in vocal", e.Member.DisplayName())) + timeInVocal = MaxTimeInVocal + } + c := Copaing{DiscordID: u.DiscordID, GuildID: u.GuildID} + c.Load() + c.AddXP(s, XPVocal(uint(timeInVocal)), func(_ uint, _ uint) { + //TODO: handle new level in vocal + }) +} diff --git a/xp/member.go b/xp/member.go index 751bbd7..e3714fa 100644 --- a/xp/member.go +++ b/xp/member.go @@ -2,6 +2,7 @@ package xp import ( "github.com/anhgelus/gokord" + "github.com/bwmarrin/discordgo" "gorm.io/gorm" ) @@ -20,3 +21,14 @@ func (c *Copaing) Load() *Copaing { func (c *Copaing) Save() { gokord.DB.Save(c) } + +func (c *Copaing) AddXP(s *discordgo.Session, xp uint, fn func(uint, uint)) { + pastLevel := Level(c.XP) + c.XP += xp + c.Save() + newLevel := Level(c.XP) + if newLevel > pastLevel { + fn(c.XP, newLevel) + onNewLevel(s, newLevel) + } +}