Compare commits

...

13 Commits

Author SHA1 Message Date
DutchEllie 780fe972cd fix apparent mistake 2021-06-04 16:21:36 +02:00
DutchEllie b64a4096e9 implement? 2021-06-04 16:08:44 +02:00
DutchEllie 661ce08764 log 2021-06-04 16:07:19 +02:00
DutchEllie 062e9276f2 packaged up server, added mutex 2021-06-04 09:54:28 +02:00
DutchEllie a8128b120a changed 2021-06-03 17:07:33 +02:00
DutchEllie eff943a715 fixed error message 2021-06-03 14:07:11 +02:00
DutchEllie 8555a686a6 this might break it all 2021-06-03 13:52:53 +02:00
DutchEllie ebbbc3680d added middleware 2021-06-03 13:45:07 +02:00
DutchEllie 9f1d13d3aa added build 2021-06-03 13:28:47 +02:00
DutchEllie e56686ee3c added newsendpepe 2021-06-03 12:54:03 +02:00
DutchEllie 0829c2a39d ready for testing?? 2021-06-03 12:50:42 +02:00
DutchEllie 6e65f9165b renamed general 2021-06-03 11:29:43 +02:00
DutchEllie 91c9230e05 basic idea 2021-06-03 11:29:34 +02:00
9 changed files with 218 additions and 20 deletions

View File

@ -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)
}
} */
}

View File

@ -1 +0,0 @@
package main

7
discord/handlers.go Normal file
View File

@ -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!")
}

View File

@ -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
}
}

View File

@ -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)

39
discord/middleware.go Normal file
View File

@ -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)
}

114
discord/mux/server.go Normal file
View File

@ -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
}

View File

@ -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

View File

@ -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
}