diff options
| author | Bobby <[email protected]> | 2024-11-16 16:21:51 -0500 |
|---|---|---|
| committer | Bobby <[email protected]> | 2024-11-16 16:21:51 -0500 |
| commit | 2e79b5aa8cfe8433bcd9d1d415826056fea8fcb2 (patch) | |
| tree | e9a8e4fe1f8dfc598f68f3a2c1909fa381f46961 | |
| parent | c7e9ca772b03c2edc3a1893e9c9ac2eeba90acfa (diff) | |
| download | yuzaki-2e79b5aa8cfe8433bcd9d1d415826056fea8fcb2.tar.xz yuzaki-2e79b5aa8cfe8433bcd9d1d415826056fea8fcb2.zip | |
bot setup with basic message handler
| -rw-r--r-- | .air.toml | 74 | ||||
| -rw-r--r-- | config/config.go | 92 | ||||
| -rw-r--r-- | go.mod | 11 | ||||
| -rw-r--r-- | go.sum | 14 | ||||
| -rw-r--r-- | handlers/messageGatewayHandler.go | 18 | ||||
| -rw-r--r-- | yuzaki/main.go | 67 |
6 files changed, 237 insertions, 39 deletions
@@ -3,50 +3,50 @@ testdata_dir = "testdata" tmp_dir = "tmp" [build] - args_bin = [] - bin = "./tmp/main" - cmd = "go build -o ./tmp/main ." - delay = 1000 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] - exclude_file = [] - exclude_regex = ["_test.go"] - exclude_unchanged = false - follow_symlink = false - full_bin = "" - include_dir = [] - include_ext = ["go", "tpl", "tmpl", "html"] - include_file = [] - kill_delay = "0s" - log = "build-errors.log" - poll = false - poll_interval = 0 - post_cmd = [] - pre_cmd = [] - rerun = false - rerun_delay = 500 - send_interrupt = false - stop_on_error = false +args_bin = [] +bin = "./tmp/main" +cmd = "go build -o ./tmp/main yuzaki/main.go" +delay = 1000 +exclude_dir = ["assets", "tmp", "vendor", "testdata"] +exclude_file = [] +exclude_regex = ["_test.go"] +exclude_unchanged = false +follow_symlink = false +full_bin = "" +include_dir = [] +include_ext = ["go", "tpl", "tmpl", "html"] +include_file = [] +kill_delay = "0s" +log = "build-errors.log" +poll = false +poll_interval = 0 +post_cmd = [] +pre_cmd = [] +rerun = false +rerun_delay = 500 +send_interrupt = false +stop_on_error = false [color] - app = "" - build = "yellow" - main = "magenta" - runner = "green" - watcher = "cyan" +app = "" +build = "yellow" +main = "magenta" +runner = "green" +watcher = "cyan" [log] - main_only = false - silent = false - time = false +main_only = false +silent = false +time = false [misc] - clean_on_exit = false +clean_on_exit = false [proxy] - app_port = 0 - enabled = false - proxy_port = 0 +app_port = 0 +enabled = false +proxy_port = 0 [screen] - clear_on_rebuild = false - keep_scroll = true +clear_on_rebuild = false +keep_scroll = true diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..4f7a666 --- /dev/null +++ b/config/config.go @@ -0,0 +1,92 @@ +package config + +import ( + "fmt" + "os" + "strings" + + "github.com/joho/godotenv" +) + +type Config struct { + DiscordToken string + DataSourceName string + DatabaseDriver string +} + +var validDBDrivers = map[string]bool{ + "sqlite": true, + "postgres": true, + "mysql": true, + "mssql": true, +} + +func Load() (*Config, error) { + if err := godotenv.Load(); err != nil { + return nil, fmt.Errorf("loading env file: %w", err) + } + + config := &Config{} + requiredVars := map[string]*string{ + "DISCORD_BOT_TOKEN": &config.DiscordToken, + "DSN": &config.DataSourceName, + "DATABASE_DRIVER": &config.DatabaseDriver, + } + + for envKey, configVar := range requiredVars { + value, err := getEnv(envKey) + if err != nil { + return nil, fmt.Errorf("getting %s: %w", envKey, err) + } + *configVar = value + } + + if err := validateConfig(config); err != nil { + return nil, fmt.Errorf("validating config: %w", err) + } + + return config, nil +} + +func validateConfig(config *Config) error { + if config.DiscordToken == "" { + return fmt.Errorf("discord token not found") + } + if config.DataSourceName == "" { + return fmt.Errorf("data source name not found") + } + if config.DatabaseDriver == "" { + return fmt.Errorf("database driver not found") + } + + if !validDBDrivers[strings.ToLower(config.DatabaseDriver)] { + return fmt.Errorf("invalid database driver: %s", config.DatabaseDriver) + } + + return nil +} + +func getEnv(key string) (string, error) { + value, exists := os.LookupEnv(key) + if !exists { + return "", fmt.Errorf("environment variable %s not found", key) + } + return strings.TrimSpace(value), nil +} + +// Future implementation for getting other types of environment variables +// func getEnvInt(key string) (int, error) { +// value, err := getEnv(key) +// if err != nil { +// return 0, err +// } +// return strconv.Atoi(value) +// } + +// func getEnvBool(key string) (bool, error) { +// value, err := getEnv(key) +// if err != nil { +// return false, err +// } +// return strconv.ParseBool(value) +// } @@ -1,3 +1,14 @@ module yuzaki go 1.23.1 + +require ( + github.com/bwmarrin/discordgo v0.28.1 + github.com/joho/godotenv v1.5.1 +) + +require ( + github.com/gorilla/websocket v1.4.2 // indirect + golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect +) @@ -0,0 +1,14 @@ +github.com/bwmarrin/discordgo v0.28.1 h1:gXsuo2GBO7NbR6uqmrrBDplPUx2T3nzu775q/Rd1aG4= +github.com/bwmarrin/discordgo v0.28.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/handlers/messageGatewayHandler.go b/handlers/messageGatewayHandler.go new file mode 100644 index 0000000..a6ec4d7 --- /dev/null +++ b/handlers/messageGatewayHandler.go @@ -0,0 +1,18 @@ +package handlers + +import ( + "strings" + + "github.com/bwmarrin/discordgo" +) + +func MessageGatewayHandler(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID || m.Author.Bot { + return + } + + // if says "hello @bot" <- case insensitive <- bot responds with "Hello @user!" + if strings.EqualFold(strings.TrimSpace(m.Content), "hello "+s.State.User.Mention()) { + s.ChannelMessageSendReply(m.ChannelID, "Hello "+m.Author.Mention()+"!", m.Reference()) + } +} diff --git a/yuzaki/main.go b/yuzaki/main.go index a3dd973..c54962d 100644 --- a/yuzaki/main.go +++ b/yuzaki/main.go @@ -1,7 +1,70 @@ package main -import "fmt" +import ( + "context" + "log" + "os" + "os/signal" + "syscall" + "yuzaki/config" + "yuzaki/handlers" + + "github.com/bwmarrin/discordgo" +) + +var ( + configuration *config.Config + session *discordgo.Session +) + +func init() { + var err error + configuration, err = config.Load() + if err != nil { + log.Fatalf("loading config: %v", err) + } + + session, err = discordgo.New("Bot " + configuration.DiscordToken) + if err != nil { + log.Fatalf("creating discord session: %v", err) + } + + session.Identify.Intents = discordgo.IntentsAll + session.AddHandler(ready) + session.AddHandler(handlers.MessageGatewayHandler) +} func main() { - fmt.Println("Hello, World!") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + if err := setupAndRun(ctx); err != nil { + log.Fatalf("error running bot: %v", err) + } +} + +func setupAndRun(ctx context.Context) error { + if err := session.Open(); err != nil { + return err + } + defer session.Close() + + shutdown := make(chan os.Signal, 1) + signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) + + select { + case <-ctx.Done(): + return ctx.Err() + case <-shutdown: + log.Println("Shutting down gracefully...") + return nil + } +} + +func ready(s *discordgo.Session, event *discordgo.Ready) { + log.Printf("Logged in as %s on %d guilds", event.User.String(), len(event.Guilds)) + if err := s.UpdateWatchStatus(0, "all users in Yuzaki's Canyon!"); err != nil { + log.Printf("error setting status: %v", err) + } + log.Println("Bot is now running. Press CTRL-C to exit.") } |
