diff --git a/GoBot/command_messageutil.go b/GoBot/command_messageutil.go deleted file mode 100644 index 1da8399..0000000 --- a/GoBot/command_messageutil.go +++ /dev/null @@ -1,147 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "strings" - - "github.com/bwmarrin/discordgo" -) - -const guildID = "626424729234046987" -const memberRoleID = "626434632614805526" -const auditChannel = "631789849929711627" - -var errMemberNotFound = errors.New("messageutil: the requested member was not found") - -func enforceDM(s *discordgo.Session, m *discordgo.MessageCreate) bool { - if m.GuildID != "" { - //This command can only be used in DM to protect the invite creator. - s.ChannelMessageDelete(m.ChannelID, m.ID) - s.ChannelMessageSend( - m.ChannelID, - m.Author.Mention()+",这个指令只能在私信中使用。\n"+m.Author.Mention()+", this command can only be used in DM.", - ) - return false - } - return true -} - -func membersOnly(s *discordgo.Session, m *discordgo.MessageCreate) bool { - member, err := s.GuildMember(guildID, m.Author.ID) - if err != nil { - s.ChannelMessageSend( - m.ChannelID, - m.Author.Mention()+",请在成为会员后才使用这个指令。\n"+m.Author.Mention()+", please use this command after you become a member.", - ) - return false - } - for _, v := range member.Roles { - if v == memberRoleID { - return true - } - } - s.ChannelMessageSend( - m.ChannelID, - m.Author.Mention()+",请在成为会员后才使用这个指令。\n"+m.Author.Mention()+", please use this command after you become a member.", - ) - return false -} - -func nonMembersOnly(s *discordgo.Session, m *discordgo.MessageCreate) bool { - member, err := s.GuildMember(guildID, m.Author.ID) - if err != nil { - return false - } - for _, v := range member.Roles { - if v == memberRoleID { - s.ChannelMessageSend( - m.ChannelID, - m.Author.Mention()+",该指令只能被非会员使用。\n"+m.Author.Mention()+", this command can only be used by non-member.", - ) - return false - } - } - return true -} - -func sendPrivateMessage(s *discordgo.Session, recipient, message string) error { - channel, err := s.UserChannelCreate(recipient) - if err != nil { - return err - } - _, err = s.ChannelMessageSend(channel.ID, message) - return err -} - -func auditLog(s *discordgo.Session, message string) { - _, err := s.ChannelMessageSend(auditChannel, message) - if err != nil { - fmt.Println("==Audit Log==") - fmt.Println(message) - fmt.Println(err) - } -} - -func getMemberFromUserFriendlyName(s *discordgo.Session, user string) (*discordgo.Member, error) { - allMembers, err := getAllMembers(s) - if err != nil { - return nil, err - } - if strings.HasPrefix(user, "@") { - user = strings.TrimPrefix(user, "@") - } else if strings.HasSuffix(user, ">") { - if strings.HasPrefix(user, "<@!") { - user = strings.TrimSuffix(strings.TrimPrefix(user, "<@!"), ">") - } else if strings.HasPrefix(user, "<@") { - user = strings.TrimSuffix(strings.TrimPrefix(user, "<@"), ">") - } - } - if strings.ContainsRune(user, '#') { - list := strings.Split(user, "#") - username := strings.Join(list[:len(list)-1], "#") - discriminator := list[len(list)-1] - for _, v := range allMembers { - if v.User.Username == username && v.User.Discriminator == discriminator { - return v, nil - } - } - } - for _, v := range allMembers { - if v.User.ID == user { - return v, nil - } - } - for _, v := range allMembers { - if v.Nick == user { - return v, nil - } - } - for _, v := range allMembers { - if v.User.Username == user { - return v, nil - } - } - return nil, errMemberNotFound -} - -func getAllMembers(s *discordgo.Session) ([]*discordgo.Member, error) { - initial, err := s.GuildMembers(guildID, "", 1000) - if err != nil { - return nil, err - } - next := initial[len(initial)-1].User.ID - for next != "" { - nextArray, err := s.GuildMembers(guildID, next, 1000) - if err != nil { - return nil, err - } - if len(nextArray) == 0 { - next = "" - } else { - next = nextArray[len(nextArray)-1].User.ID - initial = append(initial, nextArray...) - } - } - return initial, nil -} diff --git a/GoBot/discord/backend/members.go b/GoBot/discord/backend/members.go new file mode 100644 index 0000000..38f088d --- /dev/null +++ b/GoBot/discord/backend/members.go @@ -0,0 +1,75 @@ +package backend + +import ( + "errors" + "strings" + + "github.com/bwmarrin/discordgo" + + "TerraOceanBot/discord/config" +) + +var ErrMemberNotFound = errors.New("discord/backend: the requested member was not found") + +func GetAllMembers(s *discordgo.Session) ([]*discordgo.Member, error) { + initial, err := s.GuildMembers(config.GuildID, "", 1000) + if err != nil { + return nil, err + } + next := initial[len(initial)-1].User.ID + for next != "" { + nextArray, err := s.GuildMembers(config.GuildID, next, 1000) + if err != nil { + return nil, err + } + if len(nextArray) == 0 { + next = "" + } else { + next = nextArray[len(nextArray)-1].User.ID + initial = append(initial, nextArray...) + } + } + return initial, nil +} + +func GetMemberFromUserFriendlyName(s *discordgo.Session, user string) (*discordgo.Member, error) { + allMembers, err := GetAllMembers(s) + if err != nil { + return nil, err + } + if strings.HasPrefix(user, "@") { + user = strings.TrimPrefix(user, "@") + } else if strings.HasSuffix(user, ">") { + if strings.HasPrefix(user, "<@!") { + user = strings.TrimSuffix(strings.TrimPrefix(user, "<@!"), ">") + } else if strings.HasPrefix(user, "<@") { + user = strings.TrimSuffix(strings.TrimPrefix(user, "<@"), ">") + } + } + if strings.ContainsRune(user, '#') { + list := strings.Split(user, "#") + username := strings.Join(list[:len(list)-1], "#") + discriminator := list[len(list)-1] + for _, v := range allMembers { + if v.User.Username == username && v.User.Discriminator == discriminator { + return v, nil + } + } + } + for _, v := range allMembers { + if v.User.ID == user { + return v, nil + } + } + for _, v := range allMembers { + if v.Nick == user { + return v, nil + } + } + for _, v := range allMembers { + if v.User.Username == user { + return v, nil + } + } + return nil, ErrMemberNotFound +} diff --git a/GoBot/trust.go b/GoBot/discord/backend/trust.go similarity index 64% rename from GoBot/trust.go rename to GoBot/discord/backend/trust.go index 6c24faa..2f0776a 100644 --- a/GoBot/trust.go +++ b/GoBot/discord/backend/trust.go @@ -1,4 +1,4 @@ -package main +package backend import ( "errors" @@ -6,28 +6,29 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/config" ) var trustCache map[string]float64 -var errNotMember = errors.New("trust: only members have trust value") +var ErrNotMember = errors.New("trust: only members have trust value") -func getTrust(s *discordgo.Session, discordID string) (float64, error) { +func GetTrust(s *discordgo.Session, discordID string) (float64, error) { if v, ok := trustCache[discordID]; ok { return v, nil } - member, err := s.GuildMember(guildID, discordID) + member, err := s.GuildMember(config.GuildID, discordID) if err != nil { return 0.0, err } isMember := false for _, role := range member.Roles { - if role == memberRoleID { + if role == config.MemberRoleID { isMember = true } } if !isMember { - return 0.0, errNotMember + return 0.0, ErrNotMember } votes, err := db.GetTrustVote(discordID) if err != nil { @@ -41,8 +42,8 @@ func getTrust(s *discordgo.Session, discordID string) (float64, error) { return total / float64(len(votes)), nil } -func getTotalTrust(s *discordgo.Session) (float64, error) { - members, err := getAllMembers(s) +func GetTotalTrust(s *discordgo.Session) (float64, error) { + members, err := GetAllMembers(s) if err != nil { return 0.0, err } @@ -50,14 +51,14 @@ func getTotalTrust(s *discordgo.Session) (float64, error) { for _, member := range members { isMember := false for _, role := range member.Roles { - if role == memberRoleID { + if role == config.MemberRoleID { isMember = true } } if !isMember { continue } - trust, err := getTrust(s, member.User.ID) + trust, err := GetTrust(s, member.User.ID) if err != nil { return 0.0, err } @@ -66,7 +67,7 @@ func getTotalTrust(s *discordgo.Session) (float64, error) { return total, nil } -func updateTrust(sourceID, targetID string, voteValue int) error { +func UpdateTrust(sourceID, targetID string, voteValue int) error { err := db.UpdateTrust(sourceID, targetID, voteValue, false) if err != nil { return err diff --git a/GoBot/discord/config/discordID.go b/GoBot/discord/config/discordID.go new file mode 100644 index 0000000..ba50a63 --- /dev/null +++ b/GoBot/discord/config/discordID.go @@ -0,0 +1,8 @@ +package config + +const GuildID = "626424729234046987" +const MemberRoleID = "626434632614805526" +const AuditChannel = "631789849929711627" +const VoteChannel = "627164246056239104" +const AnnounceCustomChannel = "627165467269922864" +const VoteSuggestionChannel = "627164561644191744" diff --git a/GoBot/discord/discord.go b/GoBot/discord/discord.go new file mode 100644 index 0000000..5f07af4 --- /dev/null +++ b/GoBot/discord/discord.go @@ -0,0 +1,41 @@ +package discord + +import ( + "fmt" + "os" + "os/signal" + "strings" + "sync" + "syscall" + + "github.com/bwmarrin/discordgo" + + "TerraOceanBot/discord/modules" +) + +func StartBot(token string, wg *sync.WaitGroup) { + defer wg.Done() + dg, err := discordgo.New("Bot " + strings.TrimSpace(token)) + if err != nil { + panic(err) + } + + dg.AddHandler(ProcessCommand) + dg.AddHandler(ProcessVote) + dg.AddHandler(modules.CheckForVote) + dg.AddHandler(modules.CheckForTrustUpdate) + dg.AddHandler(modules.CheckForInvite) + + if err := dg.Open(); err != nil { + panic(err) + } + + fmt.Println("Bot is now running. Press CTRL-C to exit.") + go modules.ListenToVoteFinishes(dg) + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + <-sc + + dg.Close() + fmt.Println("Discordgo exited successfully.") +} diff --git a/GoBot/discord/listener.go b/GoBot/discord/listener.go new file mode 100644 index 0000000..63fcde1 --- /dev/null +++ b/GoBot/discord/listener.go @@ -0,0 +1,31 @@ +package discord + +import ( + "strings" + + "github.com/bwmarrin/discordgo" + + "TerraOceanBot/discord/config" + "TerraOceanBot/discord/modules" +) + +func ProcessCommand(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID { + return + } + + command := strings.Split(m.Content, " ") + for _, v := range modules.Commands { + if v.Name == command[0] { + v.Handler(s, m, command) + return + } + } +} + +func ProcessVote(s *discordgo.Session, m *discordgo.MessageCreate) { + //TODO Factorize this code into a command + if m.ChannelID == config.VoteSuggestionChannel { + modules.VoteSuggestion(s, m) + } +} diff --git a/GoBot/command_admin.go b/GoBot/discord/modules/admin.go similarity index 86% rename from GoBot/command_admin.go rename to GoBot/discord/modules/admin.go index fd53f8a..0b54fd4 100644 --- a/GoBot/command_admin.go +++ b/GoBot/discord/modules/admin.go @@ -1,10 +1,12 @@ -package main +package modules import ( "fmt" "strings" "github.com/bwmarrin/discordgo" + + "TerraOceanBot/discord/backend" ) //adminID is my Discord user ID (chanbakjsd#7968). @@ -45,12 +47,12 @@ func viewTrustLevel(s *discordgo.Session, m *discordgo.MessageCreate, command [] return } if len(command) > 1 { - value, err := getTrust(s, command[1]) + value, err := backend.GetTrust(s, command[1]) if err != nil { s.ChannelMessageSend(m.ChannelID, err.Error()) return } - total, err := getTotalTrust(s) + total, err := backend.GetTotalTrust(s) if err != nil { s.ChannelMessageSend(m.ChannelID, err.Error()) return @@ -59,20 +61,20 @@ func viewTrustLevel(s *discordgo.Session, m *discordgo.MessageCreate, command [] return } - total, err := getTotalTrust(s) + total, err := backend.GetTotalTrust(s) if err != nil { s.ChannelMessageSend(m.ChannelID, err.Error()) return } message := "" - members, err := getAllMembers(s) + members, err := backend.GetAllMembers(s) if err != nil { s.ChannelMessageSend(m.ChannelID, err.Error()) return } for _, v := range members { - value, err := getTrust(s, v.User.ID) - if err == errNotMember { + value, err := backend.GetTrust(s, v.User.ID) + if err == backend.ErrNotMember { continue } if err != nil { diff --git a/GoBot/discord/modules/commands.go b/GoBot/discord/modules/commands.go new file mode 100644 index 0000000..86d8f31 --- /dev/null +++ b/GoBot/discord/modules/commands.go @@ -0,0 +1,35 @@ +package modules + +import "github.com/bwmarrin/discordgo" + +type Command struct { + Name string + Handler func(s *discordgo.Session, m *discordgo.MessageCreate, commands []string) +} + +var Commands = []Command{ + Command{ + Name: "!sendas", + Handler: sendAs, + }, + Command{ + Name: "!editas", + Handler: editAs, + }, + Command{ + Name: "!peektrust", + Handler: viewTrustLevel, + }, + Command{ + Name: "!invite", + Handler: createInvite, + }, + Command{ + Name: "!validate", + Handler: checkUseInvite, + }, + Command{ + Name: "!trust", + Handler: changeTrust, + }, +} diff --git a/GoBot/embed.go b/GoBot/discord/modules/embed.go similarity index 97% rename from GoBot/embed.go rename to GoBot/discord/modules/embed.go index 04d6258..251c960 100644 --- a/GoBot/embed.go +++ b/GoBot/discord/modules/embed.go @@ -1,4 +1,4 @@ -package main +package modules import "github.com/bwmarrin/discordgo" diff --git a/GoBot/command_invite.go b/GoBot/discord/modules/invite.go similarity index 86% rename from GoBot/command_invite.go rename to GoBot/discord/modules/invite.go index f9cbd45..43e7e19 100644 --- a/GoBot/command_invite.go +++ b/GoBot/discord/modules/invite.go @@ -1,4 +1,4 @@ -package main +package modules import ( "fmt" @@ -7,6 +7,7 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/config" ) var pendingInviteConfirmation = make(map[string]invite) @@ -95,7 +96,7 @@ func checkUseInvite(s *discordgo.Session, m *discordgo.MessageCreate, command [] } db.UseInvite(messageSplit[1]) - member, err := s.GuildMember(guildID, inviter) + member, err := s.GuildMember(config.GuildID, inviter) if err != nil { sendPrivateMessage(s, m.Author.ID, "验证码制造者不是会员。\nValidation code creator is no longer a member.") return @@ -103,7 +104,7 @@ func checkUseInvite(s *discordgo.Session, m *discordgo.MessageCreate, command [] isMember := false for _, v := range member.Roles { - if v == memberRoleID { + if v == config.MemberRoleID { isMember = true } } @@ -131,7 +132,7 @@ func checkUseInvite(s *discordgo.Session, m *discordgo.MessageCreate, command [] sendPrivateMessage(s, m.Author.ID, "已向验证码制造者发送了请求。\nSent a request to use the validation code to its creator.") } -func checkForInvite(s *discordgo.Session, r *discordgo.MessageReactionAdd) { +func CheckForInvite(s *discordgo.Session, r *discordgo.MessageReactionAdd) { if r.UserID == s.State.User.ID { return } @@ -153,7 +154,7 @@ func checkForInvite(s *discordgo.Session, r *discordgo.MessageReactionAdd) { s.ChannelMessageSend(r.ChannelID, "已同意验证码的使用。该验证码已被无效化。\nUse of validation code accepted. This validation code has been invalidated.") - msg, err := s.ChannelMessageSend(voteChannel, "正在准备新的一个投票…… Preparing for the next vote...") + msg, err := s.ChannelMessageSend(config.VoteChannel, "正在准备新的一个投票…… Preparing for the next vote...") if err != nil { sendPrivateMessage(s, r.UserID, "创造投票失败。Failed to create vote.") auditLog(s, @@ -170,13 +171,13 @@ func checkForInvite(s *discordgo.Session, r *discordgo.MessageReactionAdd) { return } auditLog(s, fmt.Sprintf("Vote ID %d has been created by <@%s>.", id, r.UserID)) - s.ChannelMessageEdit(voteChannel, msg.ID, "") - s.ChannelMessageEditEmbed(voteChannel, msg.ID, createInviteEmbed(id, invite.User+":"+invite.Reason)) - s.MessageReactionAdd(voteChannel, msg.ID, emojiX) - s.MessageReactionAdd(voteChannel, msg.ID, emojiOne) - s.MessageReactionAdd(voteChannel, msg.ID, emojiTwo) - s.MessageReactionAdd(voteChannel, msg.ID, emojiThree) - s.MessageReactionAdd(voteChannel, msg.ID, emojiFour) - s.MessageReactionAdd(voteChannel, msg.ID, emojiFive) - s.MessageReactionAdd(voteChannel, msg.ID, emojiCheck) + s.ChannelMessageEdit(config.VoteChannel, msg.ID, "") + s.ChannelMessageEditEmbed(config.VoteChannel, msg.ID, createInviteEmbed(id, invite.User+":"+invite.Reason)) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiX) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiOne) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiTwo) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiThree) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiFour) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiFive) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiCheck) } diff --git a/GoBot/discord/modules/messageutil.go b/GoBot/discord/modules/messageutil.go new file mode 100644 index 0000000..1367279 --- /dev/null +++ b/GoBot/discord/modules/messageutil.go @@ -0,0 +1,78 @@ +package modules + +import ( + "fmt" + + "github.com/bwmarrin/discordgo" + + "TerraOceanBot/discord/config" +) + +func enforceDM(s *discordgo.Session, m *discordgo.MessageCreate) bool { + if m.GuildID != "" { + //This command can only be used in DM to protect the invite creator. + s.ChannelMessageDelete(m.ChannelID, m.ID) + s.ChannelMessageSend( + m.ChannelID, + m.Author.Mention()+",这个指令只能在私信中使用。\n"+m.Author.Mention()+", this command can only be used in DM.", + ) + return false + } + return true +} + +func membersOnly(s *discordgo.Session, m *discordgo.MessageCreate) bool { + member, err := s.GuildMember(config.GuildID, m.Author.ID) + if err != nil { + s.ChannelMessageSend( + m.ChannelID, + m.Author.Mention()+",请在成为会员后才使用这个指令。\n"+m.Author.Mention()+", please use this command after you become a member.", + ) + return false + } + for _, v := range member.Roles { + if v == config.MemberRoleID { + return true + } + } + s.ChannelMessageSend( + m.ChannelID, + m.Author.Mention()+",请在成为会员后才使用这个指令。\n"+m.Author.Mention()+", please use this command after you become a member.", + ) + return false +} + +func nonMembersOnly(s *discordgo.Session, m *discordgo.MessageCreate) bool { + member, err := s.GuildMember(config.GuildID, m.Author.ID) + if err != nil { + return false + } + for _, v := range member.Roles { + if v == config.MemberRoleID { + s.ChannelMessageSend( + m.ChannelID, + m.Author.Mention()+",该指令只能被非会员使用。\n"+m.Author.Mention()+", this command can only be used by non-member.", + ) + return false + } + } + return true +} + +func sendPrivateMessage(s *discordgo.Session, recipient, message string) error { + channel, err := s.UserChannelCreate(recipient) + if err != nil { + return err + } + _, err = s.ChannelMessageSend(channel.ID, message) + return err +} + +func auditLog(s *discordgo.Session, message string) { + _, err := s.ChannelMessageSend(config.AuditChannel, message) + if err != nil { + fmt.Println("==Audit Log==") + fmt.Println(message) + fmt.Println(err) + } +} diff --git a/GoBot/command_trust.go b/GoBot/discord/modules/trust.go similarity index 90% rename from GoBot/command_trust.go rename to GoBot/discord/modules/trust.go index 87ae6d3..40dc997 100644 --- a/GoBot/command_trust.go +++ b/GoBot/discord/modules/trust.go @@ -1,4 +1,4 @@ -package main +package modules import ( "fmt" @@ -7,6 +7,7 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/backend" ) var trustMessage = make(map[string]string) @@ -23,8 +24,8 @@ func changeTrust(s *discordgo.Session, m *discordgo.MessageCreate, command []str return } - member, err := getMemberFromUserFriendlyName(s, strings.SplitN(m.Content, " ", 2)[1]) - if err == errMemberNotFound { + member, err := backend.GetMemberFromUserFriendlyName(s, strings.SplitN(m.Content, " ", 2)[1]) + if err == backend.ErrMemberNotFound { s.ChannelMessageSend(m.ChannelID, "无法找到您所要求的玩家。\nCannot find the requested player.") return } @@ -61,7 +62,7 @@ func createTrustEmbed(username, nick string) *discordgo.MessageEmbed { return embed.Build() } -func checkForTrustUpdate(s *discordgo.Session, r *discordgo.MessageReactionAdd) { +func CheckForTrustUpdate(s *discordgo.Session, r *discordgo.MessageReactionAdd) { if r.UserID == s.State.User.ID { return } @@ -92,7 +93,7 @@ func checkForTrustUpdate(s *discordgo.Session, r *discordgo.MessageReactionAdd) return } - err := updateTrust(r.UserID, target, value) + err := backend.UpdateTrust(r.UserID, target, value) if err == db.ErrRecentlyChanged { s.ChannelMessageSend(r.ChannelID, "你在一个月内有设定过该名玩家的分数。你这次的更动没有被记录。\nYou have changed your score for this player within the last month. Your change was not recorded.") return diff --git a/GoBot/command_vote.go b/GoBot/discord/modules/vote.go similarity index 82% rename from GoBot/command_vote.go rename to GoBot/discord/modules/vote.go index 0d6080c..6668f07 100644 --- a/GoBot/command_vote.go +++ b/GoBot/discord/modules/vote.go @@ -1,4 +1,4 @@ -package main +package modules import ( "fmt" @@ -8,6 +8,7 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/config" ) type voteType struct { @@ -26,9 +27,6 @@ var voteTypes = map[string]voteType{ }, } -const voteChannel = "627164246056239104" -const announceCustomChannel = "627165467269922864" - const ( emojiOne = "1⃣" emojiTwo = "2⃣" @@ -39,7 +37,7 @@ const ( emojiX = "❌" ) -func checkForVote(s *discordgo.Session, r *discordgo.MessageReactionAdd) { +func CheckForVote(s *discordgo.Session, r *discordgo.MessageReactionAdd) { if r.UserID == s.State.User.ID { return } @@ -105,7 +103,7 @@ func checkForVote(s *discordgo.Session, r *discordgo.MessageReactionAdd) { checkForVoteResult(s, voteID) } -func voteSuggestion(s *discordgo.Session, m *discordgo.MessageCreate) { +func VoteSuggestion(s *discordgo.Session, m *discordgo.MessageCreate) { s.ChannelMessageDelete(m.ChannelID, m.ID) args := strings.SplitN(m.Content, " ", 2) @@ -120,7 +118,7 @@ func voteSuggestion(s *discordgo.Session, m *discordgo.MessageCreate) { switch args[0] { case "custom": - msg, err := s.ChannelMessageSend(voteChannel, "正在准备新的一个投票…… Preparing for the next vote...") + msg, err := s.ChannelMessageSend(config.VoteChannel, "正在准备新的一个投票…… Preparing for the next vote...") if err != nil { sendPrivateMessage(s, m.Author.ID, "创造投票失败。Failed to create vote.") auditLog(s, @@ -137,13 +135,13 @@ func voteSuggestion(s *discordgo.Session, m *discordgo.MessageCreate) { return } auditLog(s, fmt.Sprintf("Vote ID %d has been created by <@%s>.", id, m.Author.ID)) - s.ChannelMessageEdit(voteChannel, msg.ID, "") - s.ChannelMessageEditEmbed(voteChannel, msg.ID, createCustomEmbed(id, args[1])) - s.MessageReactionAdd(voteChannel, msg.ID, emojiOne) - s.MessageReactionAdd(voteChannel, msg.ID, emojiTwo) - s.MessageReactionAdd(voteChannel, msg.ID, emojiThree) - s.MessageReactionAdd(voteChannel, msg.ID, emojiFour) - s.MessageReactionAdd(voteChannel, msg.ID, emojiFive) + s.ChannelMessageEdit(config.VoteChannel, msg.ID, "") + s.ChannelMessageEditEmbed(config.VoteChannel, msg.ID, createCustomEmbed(id, args[1])) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiOne) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiTwo) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiThree) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiFour) + s.MessageReactionAdd(config.VoteChannel, msg.ID, emojiFive) default: sendPrivateMessage(s, m.Author.ID, "未知投票种类:"+args[0]+"\nUnknown vote type: "+args[0]) } @@ -154,5 +152,5 @@ func createCustomEmbed(id int, name string) *discordgo.MessageEmbed { } func announceCustomResult(s *discordgo.Session, id int, name string, isPositive bool) { - s.ChannelMessageSendEmbed(announceCustomChannel, showVoteStatus(createCustomEmbed(id, name), isPositive)) + s.ChannelMessageSendEmbed(config.AnnounceCustomChannel, showVoteStatus(createCustomEmbed(id, name), isPositive)) } diff --git a/GoBot/vote_invite.go b/GoBot/discord/modules/vote_invite.go similarity index 83% rename from GoBot/vote_invite.go rename to GoBot/discord/modules/vote_invite.go index 230b03e..b151139 100644 --- a/GoBot/vote_invite.go +++ b/GoBot/discord/modules/vote_invite.go @@ -1,4 +1,4 @@ -package main +package modules import ( "fmt" @@ -8,6 +8,8 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/backend" + "TerraOceanBot/discord/config" ) const announceInviteChannel = "627165467269922864" @@ -21,12 +23,12 @@ func handleInviteResult(s *discordgo.Session, id int, name string, isPositive bo if !isPositive { return } - member, err := getMemberFromUserFriendlyName(s, strings.SplitN(name, ":", 2)[0]) + member, err := backend.GetMemberFromUserFriendlyName(s, strings.SplitN(name, ":", 2)[0]) if err != nil { auditLog(s, "Error while getting member from user friendly name in invite result. "+err.Error()) return } - err = s.GuildMemberRoleAdd(guildID, member.User.ID, memberRoleID) + err = s.GuildMemberRoleAdd(config.GuildID, member.User.ID, config.MemberRoleID) if err != nil { auditLog(s, fmt.Sprintf("Fail to give user <@%s> the member role: %s", member.User.ID, err.Error())) return diff --git a/GoBot/vote_result.go b/GoBot/discord/modules/vote_result.go similarity index 88% rename from GoBot/vote_result.go rename to GoBot/discord/modules/vote_result.go index 65b9471..29a67f3 100644 --- a/GoBot/vote_result.go +++ b/GoBot/discord/modules/vote_result.go @@ -1,4 +1,4 @@ -package main +package modules import ( "fmt" @@ -8,6 +8,8 @@ import ( "github.com/bwmarrin/discordgo" "TerraOceanBot/db" + "TerraOceanBot/discord/backend" + "TerraOceanBot/discord/config" ) type confirmedResult struct { @@ -18,7 +20,7 @@ type confirmedResult struct { var voteMutex sync.Mutex var toAnnounceResultList []confirmedResult -func listenToVoteFinishes(s *discordgo.Session) { +func ListenToVoteFinishes(s *discordgo.Session) { for { voteMutex.Lock() for _, v := range toAnnounceResultList { @@ -29,7 +31,7 @@ func listenToVoteFinishes(s *discordgo.Session) { voteType, _ := db.GetVoteType(v.VoteID) voteName, _ := db.GetVoteName(v.VoteID) messageID, _ := db.GetMessageIDFromVote(v.VoteID) - s.ChannelMessageEditEmbed(voteChannel, messageID, showVoteStatus(voteTypes[voteType].EmbedBuilder(v.VoteID, voteName), v.IsPositive)) + s.ChannelMessageEditEmbed(config.VoteChannel, messageID, showVoteStatus(voteTypes[voteType].EmbedBuilder(v.VoteID, voteName), v.IsPositive)) voteTypes[voteType].ResultHandler(s, v.VoteID, voteName, v.IsPositive) } toAnnounceResultList = toAnnounceResultList[:0] @@ -50,7 +52,7 @@ func checkForVoteResult(s *discordgo.Session, id int) { if vote.Value == db.ForceRejectionVote { absoluteRejectionVote = true } - trust, err := getTrust(s, vote.UserID) + trust, err := backend.GetTrust(s, vote.UserID) if err != nil { auditLog(s, fmt.Sprintf("Error while getting vote trust for user ID %d: %s", vote.UserID, err.Error())) return @@ -59,7 +61,7 @@ func checkForVoteResult(s *discordgo.Session, id int) { totalTrust += float64(trust) } - totalGlobalTrust, err := getTotalTrust(s) + totalGlobalTrust, err := backend.GetTotalTrust(s) if err != nil { auditLog(s, fmt.Sprintf("Error while getting total vote trust: %s", err.Error())) return diff --git a/GoBot/main.go b/GoBot/main.go index 4052f75..7de264c 100644 --- a/GoBot/main.go +++ b/GoBot/main.go @@ -1,66 +1,16 @@ package main import ( - "fmt" "io/ioutil" - "os" - "os/signal" - "strings" - "syscall" + "sync" - "github.com/bwmarrin/discordgo" + "TerraOceanBot/discord" ) -const voteSuggestionChannel = "627164561644191744" - func main() { token, _ := ioutil.ReadFile("token.txt") - dg, err := discordgo.New("Bot " + strings.TrimSpace(string(token))) - if err != nil { - panic(err) - } - - dg.AddHandler(messageCreate) - dg.AddHandler(checkForVote) - dg.AddHandler(checkForTrustUpdate) - dg.AddHandler(checkForInvite) - - if err := dg.Open(); err != nil { - panic(err) - } - - fmt.Println("Bot is now running. Press CTRL-C to exit.") - go listenToVoteFinishes(dg) - sc := make(chan os.Signal, 1) - signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) - <-sc - - dg.Close() -} - -func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Author.ID == s.State.User.ID { - return - } - - if m.ChannelID == voteSuggestionChannel { - voteSuggestion(s, m) - return - } - - command := strings.Split(m.Content, " ") - switch command[0] { - case "!sendas": - sendAs(s, m, command) - case "!editas": - editAs(s, m, command) - case "!peektrust": - viewTrustLevel(s, m, command) - case "!invite": - createInvite(s, m, command) - case "!validate": - checkUseInvite(s, m, command) - case "!trust": - changeTrust(s, m, command) - } + wg := sync.WaitGroup{} + wg.Add(1) + go discord.StartBot(string(token), &wg) + wg.Wait() }