refactor vcbot to packages

This commit is contained in:
Seraphim Strub 2023-03-08 21:39:42 +01:00
parent 8a4c903c08
commit 21c6e7a748
5 changed files with 265 additions and 237 deletions

40
cmd/vcbot/config/apple.go Normal file
View file

@ -0,0 +1,40 @@
package config
import (
"encoding/json"
"github.com/disgoorg/log"
"io"
"net/http"
)
var (
AppleApi = "https://grow.rievo.page/applelist/initial.json"
AppleList []string
)
type appleApiBody struct {
Status string `json:"status"`
Type string `json:"type"`
Version string `json:"version"`
Body []string `json:"body"`
}
func LoadAppleList() error {
res, err := http.Get(AppleApi)
if err != nil {
return err
}
body, err := io.ReadAll(res.Body)
if err != nil {
return err
}
var data appleApiBody
err = json.Unmarshal(body, &data)
if err != nil {
return err
}
AppleList = data.Body
log.Debug("loaded apple list of lenght: ", len(AppleList))
return nil
}

View file

@ -0,0 +1,14 @@
package config
import (
"github.com/disgoorg/snowflake/v2"
"os"
)
var (
Token = os.Getenv("disgo_token")
RegisterGuildID = snowflake.GetEnv("disgo_guild_id")
ChannelVoiceGroupID snowflake.ID
ChannelVoiceLogID snowflake.ID
ChannelVoicePrefix = "🔉 - "
)

63
cmd/vcbot/event/event.go Normal file
View file

@ -0,0 +1,63 @@
package event
import (
"fmt"
"github.com/disgoorg/disgo/events"
"grow.rievo.dev/discordBots/cmd/vcbot/helper"
)
func JoinEvent(event *events.GuildVoiceJoin) {
event.Client().Logger().Debug("JoinEvent")
channelId := *event.VoiceState.ChannelID
channel, _ := event.Client().Rest().GetChannel(channelId)
channelName := channel.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v joined %v", userName, channelName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v joined %v", userMention, channelName)
go helper.SendNoMention(event.Client(), message, messageEdit)
helper.UpdateVoiceChannels(event.Client(), false)
}
func MoveEvent(event *events.GuildVoiceMove) {
if event.OldVoiceState.ChannelID.String() == event.VoiceState.ChannelID.String() {
// no that's not a move event
return
}
event.Client().Logger().Debug("MoveEvent")
channelOldId := *event.OldVoiceState.ChannelID
channelOld, _ := event.Client().Rest().GetChannel(channelOldId)
channelOldName := channelOld.Name()
channelId := *event.VoiceState.ChannelID
channel, _ := event.Client().Rest().GetChannel(channelId)
channelName := channel.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v moved from %v to %v", userName, channelOldName, channelName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v moved from %v to %v", userMention, channelOldName, channelName)
go helper.SendNoMention(event.Client(), message, messageEdit)
helper.UpdateVoiceChannels(event.Client(), false)
}
func LeaveEvent(event *events.GuildVoiceLeave) {
event.Client().Logger().Debug("LeaveEvent")
if event.OldVoiceState.ChannelID == nil {
event.Client().Logger().Error("OldVoiceState.ChannelID missing")
return
}
channelOldId := *event.OldVoiceState.ChannelID
channelOld, _ := event.Client().Rest().GetChannel(channelOldId)
channelOldName := channelOld.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v left %v", userName, channelOldName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v left %v", userMention, channelOldName)
go helper.SendNoMention(event.Client(), message, messageEdit)
helper.UpdateVoiceChannels(event.Client(), true)
}

137
cmd/vcbot/helper/helper.go Normal file
View file

@ -0,0 +1,137 @@
package helper
import (
"errors"
"fmt"
"github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/snowflake/v2"
"grow.rievo.dev/discordBots/cmd/vcbot/config"
"math/rand"
)
func SendNoMention(client bot.Client, msg, msgEdit string) {
message, err := client.Rest().CreateMessage(config.ChannelVoiceLogID, discord.NewMessageCreateBuilder().
SetContent(msg).Build())
if err != nil {
client.Logger().Error("unable to send channel message: ", err)
return
}
_, err = client.Rest().UpdateMessage(config.ChannelVoiceLogID,
message.ID,
discord.NewMessageUpdateBuilder().ClearContent().SetContent(msgEdit).Build())
if err != nil {
client.Logger().Error("unable to update channel message: ", err)
return
}
}
func GetVoiceChannels(client bot.Client) (map[snowflake.ID]string, error) {
allChannels, err := client.Rest().GetGuildChannels(config.RegisterGuildID)
if err != nil {
return nil, errors.New(fmt.Sprintf("error getting channels: %v", err.Error()))
}
voiceChannels := make(map[snowflake.ID]string)
channelVoiceGroupIDStr := config.ChannelVoiceGroupID.String()
for _, channel := range allChannels {
if channel.Type() == discord.ChannelTypeGuildCategory {
continue
}
parentIDStr := channel.ParentID().String()
channelType := channel.Type()
if parentIDStr == channelVoiceGroupIDStr && channelType == discord.ChannelTypeGuildVoice {
voiceChannels[channel.ID()] = channel.Name()
}
}
return voiceChannels, nil
}
func GetName(channels map[snowflake.ID]string) (string, error) {
channelsReverse := make(map[string]snowflake.ID)
for id, name := range channels {
channelsReverse[name] = id
}
appleListLen := len(config.AppleList)
for i := 0; i < appleListLen; i++ {
randomIndex := rand.Intn(appleListLen)
pick := config.AppleList[randomIndex]
newName := fmt.Sprintf("%v%v", config.ChannelVoicePrefix, pick)
_, exists := channelsReverse[newName]
if exists == false {
return newName, nil
}
}
return "", errors.New("could not find unused name")
}
func UpdateVoiceChannels(client bot.Client, deleteChannels bool) {
voiceChannels, err := GetVoiceChannels(client)
if err != nil {
client.Logger().Error("error in getVoiceChannels: ", err)
}
voiceChannelsWithState := make(map[snowflake.ID]string)
voiceChannelsEmpty := make(map[snowflake.ID]string)
for key, val := range voiceChannels {
voiceChannelsEmpty[key] = val
}
client.Caches().VoiceStatesForEach(config.RegisterGuildID, func(state discord.VoiceState) {
if state.ChannelID == nil {
return
}
channelId := *state.ChannelID
name, ok := voiceChannels[channelId]
if !ok {
// not channel of group
return
}
voiceChannelsWithState[channelId] = name
delete(voiceChannelsEmpty, channelId)
})
if len(voiceChannels) == 2 && len(voiceChannelsWithState) == 0 {
client.Logger().Debug("all channels are empty")
return
}
if len(voiceChannelsWithState) >= len(voiceChannels) {
// if there are no empty voiceChannels create one
client.Logger().Debug("new channel has to be created")
name, err := GetName(voiceChannels)
if err != nil {
client.Logger().Error("no empty channels")
return
}
_, err = client.Rest().CreateGuildChannel(config.RegisterGuildID, discord.GuildVoiceChannelCreate{
Name: name,
UserLimit: 77,
ParentID: config.ChannelVoiceGroupID,
})
if err != nil {
return
}
return
}
if len(voiceChannels)-len(voiceChannelsWithState) > 1 && deleteChannels {
// if there are more than one empty voiceChannels delete all but 1
client.Logger().Debug("channel has to be deleted")
client.Logger().Debug("empty channels: ", voiceChannelsEmpty)
for id, s := range voiceChannelsEmpty {
// get the oldest channel and delete it
client.Logger().Debug("deleting: ", s)
err := client.Rest().DeleteChannel(id)
if err != nil {
client.Logger().Error("not able to delete: ", err)
return
}
break
}
UpdateVoiceChannels(client, true)
}
}

View file

@ -2,48 +2,24 @@ package main
import ( import (
"context" "context"
"encoding/json"
"errors"
"fmt"
"github.com/disgoorg/disgo" "github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/cache" "github.com/disgoorg/disgo/cache"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/disgo/events"
"github.com/disgoorg/disgo/gateway" "github.com/disgoorg/disgo/gateway"
"github.com/disgoorg/log" "github.com/disgoorg/log"
"github.com/disgoorg/snowflake/v2" "grow.rievo.dev/discordBots/cmd/vcbot/config"
"io" "grow.rievo.dev/discordBots/cmd/vcbot/event"
"math/rand"
"net/http"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
) )
var (
token = os.Getenv("disgo_token")
registerGuildID = snowflake.GetEnv("disgo_guild_id")
channelVoiceGroupID snowflake.ID
channelVoiceLogID snowflake.ID
channelVoicePrefix = "🔉 - "
appleApi = "https://grow.rievo.page/applelist/initial.json"
appleList []string
)
type appleApiBody struct {
Status string `json:"status"`
Type string `json:"type"`
Version string `json:"version"`
Body []string `json:"body"`
}
func main() { func main() {
log.SetLevel(log.LevelInfo) log.SetLevel(log.LevelInfo)
log.Info("starting vcbot...") log.Info("starting vcbot...")
log.Info("disgo version: ", disgo.Version) log.Info("disgo version: ", disgo.Version)
err := loadAppleList() err := config.LoadAppleList()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
return return
@ -51,7 +27,7 @@ func main() {
// permissions: Manage Channels // permissions: Manage Channels
// intents: // intents:
client, err := disgo.New(token, client, err := disgo.New(config.Token,
bot.WithGatewayConfigOpts( bot.WithGatewayConfigOpts(
gateway.WithIntents(gateway.IntentGuildVoiceStates), gateway.WithIntents(gateway.IntentGuildVoiceStates),
), ),
@ -62,9 +38,9 @@ func main() {
cache.FlagMembers, cache.FlagMembers,
), ),
), ),
bot.WithEventListenerFunc(joinEvent), bot.WithEventListenerFunc(event.JoinEvent),
bot.WithEventListenerFunc(moveEvent), bot.WithEventListenerFunc(event.MoveEvent),
bot.WithEventListenerFunc(leaveEvent), bot.WithEventListenerFunc(event.LeaveEvent),
) )
if err != nil { if err != nil {
log.Fatal("error while building disgo instance: ", err) log.Fatal("error while building disgo instance: ", err)
@ -77,16 +53,16 @@ func main() {
log.Fatal("error while connecting to gateway: ", err) log.Fatal("error while connecting to gateway: ", err)
} }
channels, err := client.Rest().GetGuildChannels(registerGuildID) channels, err := client.Rest().GetGuildChannels(config.RegisterGuildID)
for _, channel := range channels { for _, channel := range channels {
switch channel.Name() { switch channel.Name() {
case "🔊-talk": case "🔊-talk":
channelVoiceGroupID = channel.ID() config.ChannelVoiceGroupID = channel.ID()
case "📋-voice": case "📋-voice":
channelVoiceLogID = channel.ID() config.ChannelVoiceLogID = channel.ID()
} }
} }
if channelVoiceGroupID == 0 { if config.ChannelVoiceGroupID == 0 {
log.Fatal("couldn't find needed channel") log.Fatal("couldn't find needed channel")
} }
@ -95,205 +71,3 @@ func main() {
signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
<-s <-s
} }
func loadAppleList() error {
res, err := http.Get(appleApi)
if err != nil {
return err
}
body, err := io.ReadAll(res.Body)
if err != nil {
return err
}
var data appleApiBody
err = json.Unmarshal(body, &data)
if err != nil {
return err
}
appleList = data.Body
log.Debug("loaded apple list of lenght: ", len(appleList))
return nil
}
func sendNoMention(client bot.Client, msg, msgEdit string) {
message, err := client.Rest().CreateMessage(channelVoiceLogID, discord.NewMessageCreateBuilder().
SetContent(msg).Build())
if err != nil {
client.Logger().Error("unable to send channel message: ", err)
return
}
_, err = client.Rest().UpdateMessage(channelVoiceLogID,
message.ID,
discord.NewMessageUpdateBuilder().ClearContent().SetContent(msgEdit).Build())
if err != nil {
client.Logger().Error("unable to update channel message: ", err)
return
}
}
func joinEvent(event *events.GuildVoiceJoin) {
event.Client().Logger().Debug("joinEvent")
channelId := *event.VoiceState.ChannelID
channel, _ := event.Client().Rest().GetChannel(channelId)
channelName := channel.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v joined %v", userName, channelName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v joined %v", userMention, channelName)
go sendNoMention(event.Client(), message, messageEdit)
updateVoiceChannels(event.Client(), false)
}
func moveEvent(event *events.GuildVoiceMove) {
if event.OldVoiceState.ChannelID.String() == event.VoiceState.ChannelID.String() {
// no that's not a move event
return
}
event.Client().Logger().Debug("moveEvent")
channelOldId := *event.OldVoiceState.ChannelID
channelOld, _ := event.Client().Rest().GetChannel(channelOldId)
channelOldName := channelOld.Name()
channelId := *event.VoiceState.ChannelID
channel, _ := event.Client().Rest().GetChannel(channelId)
channelName := channel.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v moved from %v to %v", userName, channelOldName, channelName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v moved from %v to %v", userMention, channelOldName, channelName)
go sendNoMention(event.Client(), message, messageEdit)
updateVoiceChannels(event.Client(), false)
}
func leaveEvent(event *events.GuildVoiceLeave) {
event.Client().Logger().Debug("leaveEvent")
if event.OldVoiceState.ChannelID == nil {
event.Client().Logger().Error("OldVoiceState.ChannelID missing")
return
}
channelOldId := *event.OldVoiceState.ChannelID
channelOld, _ := event.Client().Rest().GetChannel(channelOldId)
channelOldName := channelOld.Name()
userName := event.Member.EffectiveName()
userMention := event.Member.Mention()
message := fmt.Sprintf("**CHANNEL LOG:** %v left %v", userName, channelOldName)
messageEdit := fmt.Sprintf("**CHANNEL LOG:** %v left %v", userMention, channelOldName)
go sendNoMention(event.Client(), message, messageEdit)
updateVoiceChannels(event.Client(), true)
}
func getVoiceChannels(client bot.Client) (map[snowflake.ID]string, error) {
allChannels, err := client.Rest().GetGuildChannels(registerGuildID)
if err != nil {
return nil, errors.New(fmt.Sprintf("error getting channels: %v", err.Error()))
}
voiceChannels := make(map[snowflake.ID]string)
channelVoiceGroupIDStr := channelVoiceGroupID.String()
for _, channel := range allChannels {
if channel.Type() == discord.ChannelTypeGuildCategory {
continue
}
parentIDStr := channel.ParentID().String()
channelType := channel.Type()
if parentIDStr == channelVoiceGroupIDStr && channelType == discord.ChannelTypeGuildVoice {
voiceChannels[channel.ID()] = channel.Name()
}
}
return voiceChannels, nil
}
func getName(channels map[snowflake.ID]string) (string, error) {
channelsReverse := make(map[string]snowflake.ID)
for id, name := range channels {
channelsReverse[name] = id
}
appleListLen := len(appleList)
for i := 0; i < appleListLen; i++ {
randomIndex := rand.Intn(appleListLen)
pick := appleList[randomIndex]
newName := fmt.Sprintf("%v%v", channelVoicePrefix, pick)
_, exists := channelsReverse[newName]
if exists == false {
return newName, nil
}
}
return "", errors.New("could not find unused name")
}
func updateVoiceChannels(client bot.Client, deleteChannels bool) {
voiceChannels, err := getVoiceChannels(client)
if err != nil {
client.Logger().Error("error in getVoiceChannels: ", err)
}
voiceChannelsWithState := make(map[snowflake.ID]string)
voiceChannelsEmpty := make(map[snowflake.ID]string)
for key, val := range voiceChannels {
voiceChannelsEmpty[key] = val
}
client.Caches().VoiceStatesForEach(registerGuildID, func(state discord.VoiceState) {
if state.ChannelID == nil {
return
}
channelId := *state.ChannelID
name, ok := voiceChannels[channelId]
if !ok {
// not channel of group
return
}
voiceChannelsWithState[channelId] = name
delete(voiceChannelsEmpty, channelId)
})
if len(voiceChannels) == 2 && len(voiceChannelsWithState) == 0 {
client.Logger().Debug("all channels are empty")
return
}
if len(voiceChannelsWithState) >= len(voiceChannels) {
// if there are no empty voiceChannels create one
client.Logger().Debug("new channel has to be created")
name, err := getName(voiceChannels)
if err != nil {
client.Logger().Error("no empty channels")
return
}
_, err = client.Rest().CreateGuildChannel(registerGuildID, discord.GuildVoiceChannelCreate{
Name: name,
UserLimit: 77,
ParentID: channelVoiceGroupID,
})
if err != nil {
return
}
return
}
if len(voiceChannels)-len(voiceChannelsWithState) > 1 && deleteChannels {
// if there are more than one empty voiceChannels delete all but 1
client.Logger().Debug("channel has to be deleted")
client.Logger().Debug("empty channels: ", voiceChannelsEmpty)
for id, s := range voiceChannelsEmpty {
// get the oldest channel and delete it
client.Logger().Debug("deleting: ", s)
err := client.Rest().DeleteChannel(id)
if err != nil {
client.Logger().Error("not able to delete: ", err)
return
}
break
}
updateVoiceChannels(client, true)
}
}