Compare commits
13 Commits
main
...
command-re
Author | SHA1 | Date |
---|---|---|
DutchEllie | 780fe972cd | |
DutchEllie | b64a4096e9 | |
DutchEllie | 661ce08764 | |
DutchEllie | 062e9276f2 | |
DutchEllie | a8128b120a | |
DutchEllie | eff943a715 | |
DutchEllie | 8555a686a6 | |
DutchEllie | ebbbc3680d | |
DutchEllie | 9f1d13d3aa | |
DutchEllie | e56686ee3c | |
DutchEllie | 0829c2a39d | |
DutchEllie | 6e65f9165b | |
DutchEllie | 91c9230e05 |
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
|
@ -10,12 +8,20 @@ func (app *application) messageCreate(s *discordgo.Session, m *discordgo.Message
|
|||
if m.Author.Bot {
|
||||
return
|
||||
}
|
||||
app.limiter.LogInteraction(m.Author.ID, "messagecreate")
|
||||
|
||||
app.LogInteraction(app.LogToConsole(app.commandMux)).Execute(s, m)
|
||||
|
||||
/* if strings.HasPrefix(m.Content, "!newpepe") {
|
||||
app.LogToConsole(app.commandMux).Execute(s, m)
|
||||
return
|
||||
} */
|
||||
|
||||
//app.limiter.LogInteraction(m.Author.ID, "messagecreate")
|
||||
|
||||
/* Check if the user is even allowed by the rate limiter */
|
||||
err := app.limiter.CheckAllowed(m.Author.ID)
|
||||
/* err := app.limiter.CheckAllowed(m.Author.ID)
|
||||
if err != nil {
|
||||
/* normally don't send, but now do for debug purposes. This is the admin bot channel */
|
||||
/* normally don't send, but now do for debug purposes. This is the admin bot channel *
|
||||
//app.unknownError(err, s, true, "815952128106430514")
|
||||
app.infoLog.Printf("Rate limit exceeded by used %s", m.Author.Username)
|
||||
channel, err := s.UserChannelCreate(m.Author.ID)
|
||||
|
@ -25,24 +31,24 @@ func (app *application) messageCreate(s *discordgo.Session, m *discordgo.Message
|
|||
}
|
||||
s.ChannelMessageSend(channel.ID, "You exceeded the rate limit for the server, please stop spamming")
|
||||
return
|
||||
}
|
||||
} */
|
||||
|
||||
/* Checking if the message starts with the trigger specified in application struct
|
||||
if it does then we start the switch statement to trigger the appropriate function
|
||||
if it does not then we check if it contains a triggerword from the database */
|
||||
if strings.HasPrefix(m.Content, app.trigger) {
|
||||
/* if strings.HasPrefix(m.Content, app.trigger) {
|
||||
splitCommand := strings.Split(strings.TrimSpace(m.Content), " ")
|
||||
|
||||
/* If the whole message on it's own is just "!pepe" aka the triggerword, then send a pepe and stop */
|
||||
/* If the whole message on it's own is just "!pepe" aka the triggerword, then send a pepe and stop *
|
||||
if strings.TrimSpace(m.Content) == app.trigger {
|
||||
app.sendPepe(s, m)
|
||||
return
|
||||
}
|
||||
/* This switches on the first word in the message
|
||||
it could be anything starting with !pepe */
|
||||
it could be anything starting with !pepe *
|
||||
if len(splitCommand) > 1 {
|
||||
switch splitCommand[1] {
|
||||
/* --- Funny commands --- */
|
||||
/* --- Funny commands --- *
|
||||
case "cringe":
|
||||
app.sendCringe(s, m)
|
||||
case "gif":
|
||||
|
@ -53,12 +59,12 @@ func (app *application) messageCreate(s *discordgo.Session, m *discordgo.Message
|
|||
app.sendWednesday(s, m)
|
||||
case "github", "source":
|
||||
app.sendGithub(s, m)
|
||||
/* --- Bot commands for words --- */
|
||||
/* --- Bot commands for words --- *
|
||||
case "spam":
|
||||
app.sendManyPepes(s, m, splitCommand)
|
||||
case "stop":
|
||||
app.stopRequest(s, m)
|
||||
/* --- Bot commands, but only admins --- */
|
||||
/* --- Bot commands, but only admins --- *
|
||||
case "addword":
|
||||
app.addWord(s, m, splitCommand)
|
||||
case "removeword":
|
||||
|
@ -71,8 +77,8 @@ func (app *application) messageCreate(s *discordgo.Session, m *discordgo.Message
|
|||
|
||||
}
|
||||
} else {
|
||||
/* If the trigger wasn't the prefix of the message, we need to check all the words for a trigger */
|
||||
/* If the trigger wasn't the prefix of the message, we need to check all the words for a trigger
|
||||
app.findTrigger(s, m)
|
||||
}
|
||||
} */
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
package main
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "github.com/bwmarrin/discordgo"
|
||||
|
||||
func newCringe(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
s.ChannelMessageSend(m.ChannelID, "this is a test message right from the new command system!")
|
||||
}
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
/* -------- DB Helper functions -------- */
|
||||
|
||||
func openDB(dsn string) (*sql.DB, error){
|
||||
func openDB(dsn string) (*sql.DB, error) {
|
||||
db, err := sql.Open("mysql", dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -25,7 +25,7 @@ func openDB(dsn string) (*sql.DB, error){
|
|||
return db, nil
|
||||
}
|
||||
|
||||
func (app *application) updateAllBadWords() (error) {
|
||||
func (app *application) updateAllBadWords() error {
|
||||
var err error
|
||||
app.allBadWords, err = app.badwords.AllWords()
|
||||
if err != nil {
|
||||
|
@ -39,7 +39,7 @@ func (app *application) updateAllBadWords() (error) {
|
|||
|
||||
func (app *application) unknownError(err error, s *discordgo.Session, notifyDiscord bool, channelID string) {
|
||||
trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
|
||||
app.errorLog.Output(2, trace)
|
||||
app.errorLog.Output(2, trace)
|
||||
|
||||
if notifyDiscord {
|
||||
msg := fmt.Sprintf("An unknown error occured, error message attached below. Stack trace is in the server logs.\n%s", err.Error())
|
||||
|
@ -61,4 +61,4 @@ func (app *application) readAuthToken() (string, error) {
|
|||
}
|
||||
|
||||
return string(token), nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"quenten.nl/pepebot/discord/mux"
|
||||
"quenten.nl/pepebot/limiter"
|
||||
"quenten.nl/pepebot/models/mysql"
|
||||
)
|
||||
|
@ -25,9 +26,10 @@ type application struct {
|
|||
trigger string
|
||||
allBadWords map[string][]string
|
||||
limiter *limiter.Limiter
|
||||
commandMux *mux.CommandMux
|
||||
|
||||
active bool
|
||||
stop bool
|
||||
stop bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -61,6 +63,9 @@ func main() {
|
|||
Logs: make(map[string][]*limiter.Action),
|
||||
}
|
||||
|
||||
server := mux.NewCommandMux()
|
||||
server.Prefix = "!pepe"
|
||||
|
||||
app := &application{
|
||||
infoLog: infoLog,
|
||||
errorLog: errorLog,
|
||||
|
@ -68,6 +73,7 @@ func main() {
|
|||
adminroles: &mysql.AdminRolesModel{DB: db},
|
||||
trigger: "!pepe",
|
||||
limiter: limiter,
|
||||
commandMux: server,
|
||||
}
|
||||
|
||||
app.allBadWords, err = app.badwords.AllWords()
|
||||
|
@ -75,6 +81,23 @@ func main() {
|
|||
app.errorLog.Fatal(err)
|
||||
}
|
||||
|
||||
server.HandleFunc("cringe", app.sendCringe)
|
||||
server.HandleFunc("gif", app.sendNigelGif)
|
||||
server.HandleFunc("tuesday", app.sendTuesday)
|
||||
server.HandleFunc("wednesday", app.sendWednesday)
|
||||
server.HandleFunc("github", app.sendGithub)
|
||||
server.HandleFunc("source", app.sendGithub)
|
||||
/* The admin commands are left out for now.
|
||||
They have specialised functions and don't work yet.
|
||||
Their code is left unworking and nonfunctional to be fixed
|
||||
sometime in the future... sometime
|
||||
|
||||
Another thing left out is the bad words feature.
|
||||
It goes underused and has had it's joke.
|
||||
|
||||
Oh and no one must be sad to see the death of the spam command...*/
|
||||
server.HandleFunc(server.Prefix, app.sendPepe)
|
||||
|
||||
/* token, err := app.readAuthToken()
|
||||
if err != nil {
|
||||
app.errorLog.Fatal(err)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"quenten.nl/pepebot/discord/mux"
|
||||
"quenten.nl/pepebot/limiter"
|
||||
)
|
||||
|
||||
/*
|
||||
Middleware chain
|
||||
|
||||
Logtoconsole -> loginteraction -> mux -> command
|
||||
|
||||
*/
|
||||
|
||||
func (app *application) LogToConsole(next mux.Command) mux.Command {
|
||||
fn := func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
app.infoLog.Printf("%s \tsaid: %s\n", m.Author.Username, m.Content)
|
||||
next.Execute(s, m)
|
||||
}
|
||||
return mux.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func (app *application) LogInteraction(next mux.Command) mux.Command {
|
||||
fn := func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
// Logging interaction
|
||||
a := limiter.NewAction("Any message")
|
||||
app.limiter.Logs[m.Author.ID] = append(app.limiter.Logs[m.Author.ID], a)
|
||||
|
||||
// Checking if rate limit exceeded
|
||||
err := app.limiter.CheckAllowed(m.Author.ID)
|
||||
if err != nil {
|
||||
mux.NotFound(s, m)
|
||||
} else {
|
||||
next.Execute(s, m)
|
||||
}
|
||||
}
|
||||
return mux.HandlerFunc(fn)
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package mux
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
type Command interface {
|
||||
Execute(s *discordgo.Session, m *discordgo.MessageCreate)
|
||||
}
|
||||
|
||||
func NotFound(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
return
|
||||
}
|
||||
|
||||
func NotFoundHandler() Command { return HandlerFunc(NotFound) }
|
||||
|
||||
type HandlerFunc func(s *discordgo.Session, m *discordgo.MessageCreate)
|
||||
|
||||
func (f HandlerFunc) Execute(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
f(s, m)
|
||||
}
|
||||
|
||||
/* The CommandMux struct is a type of mux for Discord commands. It's modelled after the net/http ServeMux */
|
||||
type CommandMux struct {
|
||||
mu sync.RWMutex
|
||||
m map[string]muxEntry
|
||||
Prefix string
|
||||
}
|
||||
|
||||
func NewCommandMux() *CommandMux { return new(CommandMux) }
|
||||
|
||||
func (c *CommandMux) removeFirst(command string) string {
|
||||
split := strings.SplitN(strings.TrimSpace(command), " ", 2)
|
||||
if len(split) > 1 {
|
||||
return split[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *CommandMux) firstCommand(command string) string {
|
||||
split := strings.SplitN(strings.TrimSpace(command), " ", 2)
|
||||
if len(split) > 0 {
|
||||
return split[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *CommandMux) Handler(m *discordgo.MessageCreate) (cmd Command, pattern string) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
if strings.HasPrefix(m.Content, c.Prefix) {
|
||||
/* Special case for this bot alone. It has a command that is only it's prefix
|
||||
So we check if the whole message is only the prefix before proceding.
|
||||
So please don't forget to add the command, since it's totally hardcoded here. */
|
||||
if strings.TrimSpace(m.Content) == c.Prefix {
|
||||
return c.m[c.Prefix].h, c.m[c.Prefix].pattern
|
||||
}
|
||||
|
||||
m := c.removeFirst(m.Content) /* Here the prefix is removed, so we're left with only the first keyword */
|
||||
cmd, ok := c.m[c.firstCommand(m)]
|
||||
if ok {
|
||||
return cmd.h, cmd.pattern
|
||||
}
|
||||
}
|
||||
|
||||
/* Here is where I might add the whole checking for bad words part */
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func (c *CommandMux) Execute(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
h, _ := c.Handler(m)
|
||||
if h == nil {
|
||||
//log.Printf("There exists no handler for %s\n", m.Content)
|
||||
return
|
||||
}
|
||||
h.Execute(s, m)
|
||||
}
|
||||
|
||||
func (c *CommandMux) Handle(pattern string, handler Command) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if pattern == "" {
|
||||
panic("commandmux: invalid pattern")
|
||||
}
|
||||
if handler == nil {
|
||||
panic("commandmux: nil handler")
|
||||
}
|
||||
if _, exist := c.m[pattern]; exist {
|
||||
panic("commandmux: multiple registrations for " + pattern)
|
||||
}
|
||||
|
||||
if c.m == nil {
|
||||
c.m = make(map[string]muxEntry)
|
||||
}
|
||||
e := muxEntry{h: handler, pattern: pattern}
|
||||
c.m[pattern] = e
|
||||
}
|
||||
|
||||
func (c *CommandMux) HandleFunc(pattern string, handler func(s *discordgo.Session, m *discordgo.MessageCreate)) {
|
||||
if handler == nil {
|
||||
panic("commandmux: nil handler")
|
||||
}
|
||||
c.Handle(pattern, HandlerFunc(handler))
|
||||
}
|
||||
|
||||
/* The muxEntry struct contains the actual Command implementation as well as the pattern (discord command)
|
||||
it will be matched against */
|
||||
type muxEntry struct {
|
||||
h Command
|
||||
pattern string
|
||||
}
|
|
@ -3,6 +3,7 @@ version: "3.7"
|
|||
services:
|
||||
app:
|
||||
container_name: pepebot_server
|
||||
image: dutchellie/pepebot
|
||||
build: .
|
||||
restart: always
|
||||
depends_on:
|
||||
|
@ -11,6 +12,8 @@ services:
|
|||
- DB_USER=
|
||||
- DB_PASS=
|
||||
- DISCORD_TOKEN=
|
||||
- RATE_LIMIT=
|
||||
- TIME_LIMIT=
|
||||
db:
|
||||
container_name: pepebot_database
|
||||
image: mysql:8.0
|
||||
|
|
|
@ -6,3 +6,10 @@ type Action struct {
|
|||
Type string
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func NewAction(t string) *Action {
|
||||
a := new(Action)
|
||||
a.Timestamp = time.Now()
|
||||
a.Type = t
|
||||
return a
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue