diff --git a/app/app.go b/app/app.go index 8c3af1e..611fd0f 100644 --- a/app/app.go +++ b/app/app.go @@ -2,14 +2,18 @@ package app import ( "fmt" + "log" "os" "os/signal" "strings" "syscall" + "github.com/Fluffy-Bean/lynxie/utils" "github.com/bwmarrin/discordgo" ) +type Callback func(h *Handler, args []string) Error + type Config struct { Prefix string Token string @@ -18,17 +22,17 @@ type Config struct { type App struct { Config Config - Commands map[string]func(h *Handler, args []string) + Commands map[string]Callback } func NewApp(config Config) *App { return &App{ Config: config, - Commands: make(map[string]func(h *Handler, args []string)), + Commands: make(map[string]Callback), } } -func (a *App) RegisterCommand(cmd string, f func(h *Handler, args []string)) { +func (a *App) RegisterCommand(cmd string, f Callback) { a.Commands[cmd] = f } @@ -59,36 +63,78 @@ func (a *App) Run() { } type Handler struct { - Session *discordgo.Session - Message *discordgo.MessageCreate + Session *discordgo.Session + Message *discordgo.MessageCreate + Reference *discordgo.MessageReference } func (a *App) handler(session *discordgo.Session, message *discordgo.MessageCreate) { h := &Handler{ Session: session, Message: message, + Reference: &discordgo.MessageReference{ + ChannelID: message.ChannelID, + MessageID: message.ID, + }, } if h.Message.Author.ID == h.Session.State.User.ID { return } - if h.Message.Author.Bot { return } - var command string + var cmd string var args string - command = h.Message.Content - command = strings.TrimSpace(command) - command = strings.TrimPrefix(command, a.Config.Prefix) - command, args, _ = strings.Cut(command, " ") + cmd = h.Message.Content + cmd = strings.TrimPrefix(cmd, a.Config.Prefix) + cmd, args, _ = strings.Cut(cmd, " ") - callback, ok := a.Commands[command] + callback, ok := a.Commands[cmd] if !ok { + // Falling back to default help command + if cmd == "help" { + printHelp(a, h) + } + return } - callback(h, strings.Split(args, " ")) + h.Session.ChannelTyping(h.Message.ChannelID) + + err := callback(h, strings.Split(args, " ")) + if !err.Ok() { + printError(a, h, err) + } +} + +func printHelp(a *App, h *Handler) { + var commands []string + for cmd := range a.Commands { + commands = append(commands, cmd) + } + + h.Session.ChannelMessageSendComplex(h.Message.ChannelID, &discordgo.MessageSend{ + Embed: &discordgo.MessageEmbed{ + Title: "Help", + Description: strings.Join(commands, "\n"), + Color: utils.ColorFromRGB(255, 255, 255), + }, + Reference: h.Reference, + }) +} + +func printError(a *App, h *Handler, e Error) { + log.Println(e.Err) + + h.Session.ChannelMessageSendComplex(h.Message.ChannelID, &discordgo.MessageSend{ + Embed: &discordgo.MessageEmbed{ + Title: "Error", + Description: e.Msg, + Color: utils.ColorFromRGB(255, 0, 0), + }, + Reference: h.Reference, + }) } diff --git a/app/errors.go b/app/errors.go new file mode 100644 index 0000000..b95580f --- /dev/null +++ b/app/errors.go @@ -0,0 +1,10 @@ +package app + +type Error struct { + Msg string + Err error +} + +func (e *Error) Ok() bool { + return e.Err == nil +} diff --git a/commands/meta.go b/commands/meta.go index 8ca0df6..9211cdd 100644 --- a/commands/meta.go +++ b/commands/meta.go @@ -9,6 +9,8 @@ import ( "time" "github.com/Fluffy-Bean/lynxie/app" + "github.com/Fluffy-Bean/lynxie/utils" + "github.com/bwmarrin/discordgo" ) func RegisterMetaCommands(a *app.App) { @@ -16,8 +18,8 @@ func RegisterMetaCommands(a *app.App) { a.RegisterCommand("debug", registerDebug(a)) } -func registerPong(a *app.App) func(h *app.Handler, args []string) { - return func(h *app.Handler, args []string) { +func registerPong(a *app.App) app.Callback { + return func(h *app.Handler, args []string) app.Error { var options struct { latency bool } @@ -26,22 +28,27 @@ func registerPong(a *app.App) func(h *app.Handler, args []string) { cmd.BoolVar(&options.latency, "latency", false, "Display the latency of ping") cmd.Parse(args) + var content string if options.latency { - h.Session.ChannelMessageSend( - h.Message.ChannelID, - fmt.Sprintf("Pong! %dms", h.Session.HeartbeatLatency().Milliseconds()), - ) + content = fmt.Sprintf("Pong! %dms", h.Session.HeartbeatLatency().Milliseconds()) } else { - h.Session.ChannelMessageSend( - h.Message.ChannelID, - "Pong!", - ) + content = "Pong!" } + + h.Session.ChannelMessageSendComplex(h.Message.ChannelID, &discordgo.MessageSend{ + Embed: &discordgo.MessageEmbed{ + Description: content, + Color: utils.ColorFromRGB(255, 255, 255), + }, + Reference: h.Reference, + }) + + return app.Error{} } } -func registerDebug(a *app.App) func(h *app.Handler, args []string) { - return func(h *app.Handler, args []string) { +func registerDebug(a *app.App) app.Callback { + return func(h *app.Handler, args []string) app.Error { modified := false revision := "-" tags := "-" @@ -65,17 +72,26 @@ func registerDebug(a *app.App) func(h *app.Handler, args []string) { revision += " (uncommitted changes)" } - h.Session.ChannelMessageSend( - h.Message.ChannelID, - fmt.Sprintf( - "``` Revision :: %s\nBuild Tags :: %s\nGo version :: %s\n OS/Arch :: %s\n GC Count :: %d\nLocal Time :: %s```", - revision, - tags, - _go, - runtime.GOOS+"/"+runtime.GOARCH, - gcCount, - localTime, - ), - ) + h.Session.ChannelMessageSendComplex(h.Message.ChannelID, &discordgo.MessageSend{ + Embed: &discordgo.MessageEmbed{ + Description: strings.Join( + []string{ + "```", + "Revision: " + revision, + "Build Tags: " + tags, + "Go version: " + _go, + "OS/Arch: " + runtime.GOOS + "/" + runtime.GOARCH, + "GC Count: " + fmt.Sprint(gcCount), + "Local Time: " + localTime, + "```", + }, + "\n", + ), + Color: utils.ColorFromRGB(255, 255, 255), + }, + Reference: h.Reference, + }) + + return app.Error{} } } diff --git a/commands/tinyfox.go b/commands/tinyfox.go index df0c027..7ad6431 100644 --- a/commands/tinyfox.go +++ b/commands/tinyfox.go @@ -1,46 +1,90 @@ package commands import ( + "errors" "flag" + "fmt" "net/http" + "slices" "time" "github.com/Fluffy-Bean/lynxie/app" + "github.com/Fluffy-Bean/lynxie/utils" + "github.com/bwmarrin/discordgo" ) func RegisterTinyfoxCommands(a *app.App) { a.RegisterCommand("animal", registerAnimal(a)) } -func registerAnimal(a *app.App) func(h *app.Handler, args []string) { +func registerAnimal(a *app.App) app.Callback { + animals := []string{ + "fox", "yeen", "dog", "guara", "serval", "ott", "jackal", "bleat", "woof", "chi", "puma", "skunk", "tig", "wah", + "manul", "snep", "jaguar", "badger", "chee", "racc", "bear", "capy", "bun", "marten", "caracal", "snek", + "shiba", "dook", "leo", "yote", "poss", "chee", "lynx", + } + client := http.Client{ Timeout: 10 * time.Second, } - return func(h *app.Handler, args []string) { + return func(h *app.Handler, args []string) app.Error { var options struct { animal string } cmd := flag.NewFlagSet("pong", flag.ContinueOnError) - cmd.StringVar(&options.animal, "animal", "wah", "Get an image of an animal!") + cmd.StringVar(&options.animal, "animal", "", "Get an image of an animal!") cmd.Parse(args) + if options.animal == "" { + return app.Error{ + Msg: "Animal name is required!", + Err: errors.New("animal name is required"), + } + } + if !slices.Contains(animals, options.animal) { + return app.Error{ + Msg: fmt.Sprintf("Animal %s is invalid", options.animal), + Err: errors.New("entered invalid animal name"), + } + } + req, err := http.NewRequest(http.MethodGet, "https://api.tinyfox.dev/img?animal="+options.animal, nil) if err != nil { - return + return app.Error{ + Msg: "Failed to make request", + Err: err, + } } res, err := client.Do(req) if err != nil { - return + return app.Error{ + Msg: "Failed to do request", + Err: err, + } } defer res.Body.Close() - h.Session.ChannelFileSend( - h.Message.ChannelID, - "animal__"+options.animal+".png", - res.Body, - ) + h.Session.ChannelMessageSendComplex(h.Message.ChannelID, &discordgo.MessageSend{ + Embed: &discordgo.MessageEmbed{ + Title: "Animal", + Image: &discordgo.MessageEmbedImage{ + URL: "attachment://image.png", + }, + Color: utils.ColorFromRGB(255, 255, 255), + }, + Files: []*discordgo.File{ + { + Name: "image.png", + ContentType: "", + Reader: res.Body, + }, + }, + Reference: h.Reference, + }) + + return app.Error{} } } diff --git a/main.go b/main.go index 0c7f46d..533c9ac 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ import ( func main() { a := app.NewApp(app.Config{ - Prefix: "?", + Prefix: ">", Token: os.Getenv("TOKEN"), Intents: discordgo.IntentsGuildMessages, }) diff --git a/utils/color.go b/utils/color.go new file mode 100644 index 0000000..38ccb34 --- /dev/null +++ b/utils/color.go @@ -0,0 +1,5 @@ +package utils + +func ColorFromRGB(r, g, b int) int { + return (r << 16) + (g << 8) + b +}