Skip to content

Instantly share code, notes, and snippets.

@CarsonSlovoka
Created June 21, 2022 05:48
Show Gist options
  • Select an option

  • Save CarsonSlovoka/395ec4218aa406d1ef59066a8ac0e909 to your computer and use it in GitHub Desktop.

Select an option

Save CarsonSlovoka/395ec4218aa406d1ef59066a8ac0e909 to your computer and use it in GitHub Desktop.
discord bot test
package main
import (
"container/list"
"flag"
"fmt"
"github.com/bwmarrin/discordgo"
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"
)
var (
Token string = ""
ChannelID string = ""
)
func init() {
if Token == "" {
flag.StringVar(&Token, "token", "", "token")
flag.StringVar(&ChannelID, "chID", "", "channel ID")
flag.Parse()
}
if Token == "" || ChannelID == "" {
Token = os.Getenv("Token")
ChannelID = os.Getenv("ChannelID")
if Token == "" || ChannelID == "" {
panic("You need to input the token.")
}
}
}
type MsgHistory struct {
store map[string]*list.Element
list *list.List // used for GC
notifier map[string]chan *discordgo.Message
sync.RWMutex
}
func NewMsgHistory() *MsgHistory {
mh := &MsgHistory{}
mh.list = list.New()
mh.store = make(map[string]*list.Element, 0)
mh.notifier = make(map[string]chan *discordgo.Message, 0)
return mh
}
func (mh *MsgHistory) AddMsg(msg *discordgo.Message) {
mh.Lock()
defer mh.Unlock()
if elem, exists := mh.store[msg.ID]; exists {
mh.list.MoveToFront(elem)
return
} else {
mh.list.PushFront(msg)
mh.NotifyAll(msg)
}
}
func (mh *MsgHistory) GC(maxLifeTime time.Duration) {
time.AfterFunc(
maxLifeTime,
func() {
mh.Lock()
defer mh.Unlock()
elem := mh.list.Back()
if elem == nil {
mh.GC(maxLifeTime)
return
}
msg := elem.Value.(*discordgo.Message)
var lstModTime *time.Time
if editTime := msg.EditedTimestamp; editTime != nil {
lstModTime = editTime
} else {
lstModTime = &msg.Timestamp
}
if time.Now().After(lstModTime.Add(maxLifeTime)) {
mh.list.Remove(elem)
delete(mh.store, msg.ID)
fmt.Printf("A data has been cleared from the 'MsgHistory' cache, id:%s, content:%s\n", msg.ID, msg.Content)
}
mh.GC(maxLifeTime)
},
)
}
func (mh *MsgHistory) NotifyAll(m *discordgo.Message) {
go func() {
mh.RLock()
defer mh.RUnlock()
for _, ch := range mh.notifier {
ch <- m
}
}()
}
func (mh *MsgHistory) NewFilter(
name string,
criteriaFunc func(m *discordgo.Message) bool,
max int, // When this amount of data is collected, it will stop. Use -1 to ignore this setting.
timeout time.Duration, // Set -1 if you don't want to use the timeout.
loop bool,
callbackFunc func([]*discordgo.Message),
) {
for {
ch := make(chan *discordgo.Message)
mh.Lock()
if _, exists := mh.notifier[name]; exists {
panic("has existed")
}
mh.notifier[name] = ch
mh.Unlock()
fmt.Printf("Filter: %q Start\n", name)
collect := make([]*discordgo.Message, 0)
if timeout != -1 {
time.AfterFunc(timeout, func() {
fmt.Printf("timeout: %q\n", name)
close(ch) // Do not receive messages anymore after the timeout.
})
}
for {
msg, isOpen := <-ch
isDone := false
if !isOpen {
isDone = true
} else {
if criteriaFunc(msg) {
collect = append(collect, msg)
}
if max != -1 && len(collect) >= max {
isDone = true
}
}
if isDone {
mh.Lock()
delete(mh.notifier, name)
mh.Unlock()
callbackFunc(collect)
if loop {
break
} else {
return
}
}
}
}
}
func main() {
session, err := discordgo.New("Bot " + Token)
if err != nil {
fmt.Println("error creating Discord session,", err)
return
}
session.Identify.Intents = discordgo.IntentsGuildMessages // we only care about receiving message
msgHistory := NewMsgHistory()
go msgHistory.GC(16 * time.Second)
session.AddHandler(func(s *discordgo.Session, curMsg *discordgo.MessageCreate) {
appID := s.State.User.ID
if curMsg.Author.ID == appID { // if msg is sending from bot then skip.
return
}
msgHistory.AddMsg(curMsg.Message)
})
go msgHistory.NewFilter("need help", func(receiveMsg *discordgo.Message) bool {
if strings.Contains(strings.ToLower(receiveMsg.Content), "help") {
return true
}
return false
}, 3, 30*time.Second, true,
func(collectMsg []*discordgo.Message) {
if len(collectMsg) == 0 {
return
}
type User struct {
name string
msg []string
}
userMap := make(map[string]*User, 0)
for _, msg := range collectMsg {
if user, exists := userMap[msg.Author.ID]; !exists {
u := User{msg.Author.Username, []string{msg.Content}}
userMap[msg.Author.ID] = &u
} else {
user.msg = append(user.msg, msg.Content)
}
}
s := fmt.Sprintf("There are %d users who may need help.\nUser List:\n", len(userMap))
for userID, user := range userMap {
s += fmt.Sprintf("- [%s (%s)]\n%s\n", user.name, userID, strings.Join(user.msg, "\n"))
}
_, _ = session.ChannelMessageSend(ChannelID, s)
})
go msgHistory.NewFilter("test", func(receiveMsg *discordgo.Message) bool {
if strings.Contains(strings.ToLower(receiveMsg.Content), "+1") {
return true
}
return false
}, 3, 15*time.Second, true,
func(collectMsg []*discordgo.Message) {
if len(collectMsg) == 0 {
return
}
_, _ = session.ChannelMessageSend(ChannelID, "hello world test!")
})
err = session.Open()
if err != nil {
fmt.Println("error opening connection,", err)
return
}
fmt.Println("Bot is now running. Press CTRL-C to exit.")
chanSignal := make(chan os.Signal, 1)
signal.Notify(chanSignal, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-chanSignal
_ = session.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment