From 50c10d6c443bb92e2317fc06eed8c1fa264e9805 Mon Sep 17 00:00:00 2001 From: Levatax <levatax@randomchars.net> Date: Sat, 20 Nov 2021 11:53:31 +0300 Subject: [PATCH] Bot template with database --- .gitignore | 1 + cleanup.go | 14 ++++++ command.go | 38 +++++++++++++++ config.go | 46 ++++++++++++++++++ database.go | 40 ++++++++++++++++ go.mod | 18 +++++++ go.sum | 41 ++++++++++++++++ handler.go | 14 ++++++ main.go | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 344 insertions(+) create mode 100644 .gitignore create mode 100644 cleanup.go create mode 100644 command.go create mode 100644 config.go create mode 100644 database.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 handler.go create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de0c700 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +server.conf diff --git a/cleanup.go b/cleanup.go new file mode 100644 index 0000000..6e7957e --- /dev/null +++ b/cleanup.go @@ -0,0 +1,14 @@ +package main + +import ( + "git.randomchars.net/freenitori/log" + "os" +) + +func cleanup() { + // Close session + if err := session.Close(); err != nil { + log.Fatalf("Error closing session, %s", err) + os.Exit(1) + } +} diff --git a/command.go b/command.go new file mode 100644 index 0000000..1b5f242 --- /dev/null +++ b/command.go @@ -0,0 +1,38 @@ +package main + +import ( + "git.randomchars.net/freenitori/log" + "git.randomchars.net/freenitori/multiplexer" +) + +func init() { + m.Route(&multiplexer.Route{ + Pattern: "ping", + AliasPatterns: []string{"pong"}, + Description: "ping pong.", + Category: system, + Handler: func(context *multiplexer.Context) { + err := Database.Set("key", "hello world") + if err != nil { + log.Info(err) + } + context.Session.ChannelMessageSend(context.Channel.ID, "Pong") + log.Infof("Pong! " + context.User.Username) + }, + }) + + m.Route(&multiplexer.Route{ + Pattern: "get", + AliasPatterns: []string{"value"}, + Description: "database test.", + Category: system, + Handler: func(context *multiplexer.Context) { + data, err := Database.Get("key2") + if err != nil { + log.Info(err) + } + context.Session.ChannelMessageSend(context.Channel.ID, "getting value " + data) + log.Infof("Nice! " + context.User.Username ) + }, + }) +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..d996c55 --- /dev/null +++ b/config.go @@ -0,0 +1,46 @@ +package main + +import ( + "flag" + "git.randomchars.net/freenitori/log" + "github.com/BurntSushi/toml" + "os" +) + +var config configPayload +var configPath string +var defaultConfig = configPayload{ + Prefix: "!", + Token: "TOKEN", +} + +type configPayload struct { + Prefix string + Token string +} + +func init() { + flag.StringVar(&configPath, "c", "server.conf", "Specify configuration file location.") +} + +func parse() { + if _, err := toml.DecodeFile(configPath, &config); err != nil { + if os.IsNotExist(err) { + var file *os.File + if file, err = os.Create(configPath); err != nil { + log.Fatalf("Error while creating configuration file, %s", err) + os.Exit(1) + } + if err = toml.NewEncoder(file).Encode(defaultConfig); err != nil { + log.Fatalf("Error while encoding default configuration, %s", err) + os.Exit(1) + } + log.Warnf("Default configuration generated at %s, edit before next startup.", configPath) + os.Exit(1) + } + log.Fatalf("Error while decoding configuration file, %s", err) + os.Exit(1) + } else { + log.Infof("Loaded config at %s.", configPath) + } +} \ No newline at end of file diff --git a/database.go b/database.go new file mode 100644 index 0000000..7c26c77 --- /dev/null +++ b/database.go @@ -0,0 +1,40 @@ +package main + +import ( + ldb "github.com/syndtr/goleveldb/leveldb" +) + +var Database LevelDB + +type LevelDB struct { + database *ldb.DB +} + +func (db *LevelDB) Open(path string) error { + if instance, err := ldb.OpenFile(path, nil); err != nil { + return err + } else { + db.database = instance + } + return nil +} + +func (db *LevelDB) Get(key string) (string, error) { + + data , err := db.database.Get([]byte(key), nil) + + if err != nil { + return string(data), err + } + + return string(data), err +} + +func (db *LevelDB) Set(key, value string) error { + err := db.database.Put([]byte(key), []byte(value), nil) + if err != nil { + return err + } else { + return nil + } +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a3e0a32 --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module main + +go 1.17 + +require ( + git.randomchars.net/freenitori/embedutil v1.0.2 // indirect + git.randomchars.net/freenitori/log v1.0.0 // indirect + git.randomchars.net/freenitori/multiplexer v1.0.14 // indirect + github.com/BurntSushi/toml v0.4.1 // indirect + github.com/bwmarrin/discordgo v0.23.2 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/gorilla/websocket v1.4.0 // indirect + github.com/magefile/mage v1.10.0 // indirect + github.com/sirupsen/logrus v1.8.0 // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 // indirect + golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..13ee06d --- /dev/null +++ b/go.sum @@ -0,0 +1,41 @@ +git.randomchars.net/freenitori/embedutil v1.0.2 h1:8A3zSLkRRpslR0VG3vwtgxcEka4A163+K7UsKVhkHhs= +git.randomchars.net/freenitori/embedutil v1.0.2/go.mod h1:ELkCpzF7OBB7Mn//AdkRNkmj+M61DPWllArBgX3A8x4= +git.randomchars.net/freenitori/log v1.0.0 h1:hU99jGk940I1O5OcaTfnXOpN8ozXiarxhu6xpL0xe7c= +git.randomchars.net/freenitori/log v1.0.0/go.mod h1:YZFRZgVWDIrbyDGHyDeRlIRWeq0DXamXONxIt12eq2Q= +git.randomchars.net/freenitori/multiplexer v1.0.14 h1:j6r0dhI+VBDDog7Uc8a492vSSdu/BfiivweTF1sAFK8= +git.randomchars.net/freenitori/multiplexer v1.0.14/go.mod h1:Bx9vu2RXDtBrsKBslrhrc8v3IJl5Dna7I/rsHF586w0= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4= +github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= +github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= +github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..8855829 --- /dev/null +++ b/handler.go @@ -0,0 +1,14 @@ +package main + +import ( + "git.randomchars.net/freenitori/log" + "git.randomchars.net/freenitori/multiplexer" +) + +func init() { + m.MessageCreate = append(m.MessageCreate, messageHandler) +} + +func messageHandler(context *multiplexer.Context) { + log.Infof(context.User.Username + "#" + context.User.Discriminator + " sent the following message: " + context.Message.Content) +} \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..e9f6f32 --- /dev/null +++ b/main.go @@ -0,0 +1,132 @@ +package main + +import ( + "flag" + "fmt" + "git.randomchars.net/freenitori/log" + "git.randomchars.net/freenitori/multiplexer" + "github.com/bwmarrin/discordgo" + "github.com/sirupsen/logrus" + "os" + "os/signal" + "syscall" +) + +var ( + session *discordgo.Session + m = multiplexer.New() + system = multiplexer.NewCategory("System", "System-related utilities.") + verbose bool +) + +func init() { + flag.BoolVar(&verbose, "v", false, "Start up with debug logging.") +} + +func main() { + flag.Parse() + parse() + + if verbose { + log.SetLevel(logrus.DebugLevel) + } else { + log.SetLevel(logrus.InfoLevel) + } + + // Set discordgo log handler + discordgo.Logger = func(msgL, _ int, format string, a ...interface{}) { + var level logrus.Level + switch msgL { + case discordgo.LogDebug: + level = logrus.DebugLevel + case discordgo.LogInformational: + level = logrus.InfoLevel + case discordgo.LogWarning: + level = logrus.WarnLevel + case discordgo.LogError: + level = logrus.ErrorLevel + } + log.Instance.Log(level, fmt.Sprintf(format, a...)) + } + + // Set command not found handler + multiplexer.NoCommandMatched = func(context *multiplexer.Context) { + } + + // Configure session + if s, err := discordgo.New(); err != nil { + log.Fatalf("Error while creating session, %s", err) + os.Exit(1) + } else { + session = s + } + session.UserAgent = "DiscordBot (voice-bot)" + session.Token = "Bot " + config.Token + session.ShouldReconnectOnError = true + session.Identify.Intents = discordgo.IntentsAll + session.State.TrackVoice = true + + // Open session + func() { + open: + if err := session.Open(); err != nil { + if session.Identify.Intents == discordgo.IntentsAll { + log.Warnf("Wasn't able to start with full intents, some stuff might not work (%s)", err) + session.Identify.Intents = discordgo.IntentsAllWithoutPrivileged + goto open + } + + log.Fatalf("Error while opening session, %s", err) + os.Exit(1) + } + }() + + + // Setup multiplexer + m.SessionRegisterHandlers(session) + m.Prefix = config.Prefix + m.Categories = append(m.Categories, system) + err := Database.Open("/tmp/test.db") + if err != nil { + log.Info(err) + } + // Output message + log.Infof("Logged in as %s#%s (%s).", + session.State.User.Username, + session.State.User.Discriminator, + session.State.User.ID) + if application, err := session.Application("@me"); err != nil { + log.Fatalf("Unable to get application, %s", err) + os.Exit(1) + } else { + log.Infof("Invite URL: https://discord.com/oauth2/authorize?client_id=%s&scope=bot&permissions=8", application.ID) + } + + // Signal handling + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, os.Interrupt, syscall.SIGTERM) + var exit int + func() { + for { + currentSignal := <-signalChannel + switch currentSignal { + case os.Interrupt: + exit = 0 + println() + log.Info("Gracefully exiting.") + return + default: + exit = 0 + log.Info("Gracefully exiting.") + return + } + } + }() + + switch exit { + case 0: + cleanup() + default: + os.Exit(exit) + } +} -- GitLab