Created
June 21, 2022 05:48
-
-
Save CarsonSlovoka/395ec4218aa406d1ef59066a8ac0e909 to your computer and use it in GitHub Desktop.
discord bot test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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