Merge pull request #1 from QPixel/feature/databases
(feature) Database support
This commit is contained in:
commit
fc702ed425
58
core.go
58
core.go
|
|
@ -1,12 +1,10 @@
|
||||||
package framework
|
package framework
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
tlog "github.com/ubergeek77/tinylog"
|
tlog "github.com/ubergeek77/tinylog"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
@ -15,9 +13,9 @@ import (
|
||||||
// core.go
|
// core.go
|
||||||
// This file contains the main code responsible for driving core bot functionality
|
// This file contains the main code responsible for driving core bot functionality
|
||||||
|
|
||||||
// messageState
|
// MessageState
|
||||||
// Tells discordgo the amount of messages to cache
|
// Tells discordgo the amount of messages to cache
|
||||||
var messageState = 500
|
var MessageState = 500
|
||||||
|
|
||||||
// log
|
// log
|
||||||
// The logger for the core bot
|
// The logger for the core bot
|
||||||
|
|
@ -56,8 +54,20 @@ var ColorSuccess = 0x55F485
|
||||||
var ColorFailure = 0xF45555
|
var ColorFailure = 0xF45555
|
||||||
|
|
||||||
// BotPresence
|
// BotPresence
|
||||||
|
// Presence data to send when the bot is logging in
|
||||||
var botPresence discordgo.GatewayStatusUpdate
|
var botPresence discordgo.GatewayStatusUpdate
|
||||||
|
|
||||||
|
// initProvider
|
||||||
|
// Stores and allows for the calling of the chosen GuildProvider
|
||||||
|
var initProvider func() GuildProvider
|
||||||
|
|
||||||
|
// SetInitProvider
|
||||||
|
// Sets the init provider
|
||||||
|
func SetInitProvider(provider func() GuildProvider) {
|
||||||
|
initProvider = provider
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SetPresence
|
// SetPresence
|
||||||
// Sets the gateway field for bot presence
|
// Sets the gateway field for bot presence
|
||||||
func SetPresence(presence discordgo.GatewayStatusUpdate) {
|
func SetPresence(presence discordgo.GatewayStatusUpdate) {
|
||||||
|
|
@ -99,34 +109,16 @@ func IsCommand(trigger string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// dgoLog
|
|
||||||
// Allows for discordgo to call tinylog
|
|
||||||
func dgoLog(msgL, caller int, format string, a ...interface{}) {
|
|
||||||
pc, file, line, _ := runtime.Caller(caller)
|
|
||||||
files := strings.Split(file, "/")
|
|
||||||
file = files[len(files)-1]
|
|
||||||
|
|
||||||
name := runtime.FuncForPC(pc).Name()
|
|
||||||
fns := strings.Split(name, ".")
|
|
||||||
name = fns[len(fns)-1]
|
|
||||||
msg := fmt.Sprintf(format, a...)
|
|
||||||
switch msgL {
|
|
||||||
case discordgo.LogError:
|
|
||||||
dlog.Errorf("%s:%d:%s() %s", file, line, name, msg)
|
|
||||||
case discordgo.LogWarning:
|
|
||||||
dlog.Warningf("%s:%d:%s() %s", file, line, name, msg)
|
|
||||||
case discordgo.LogInformational:
|
|
||||||
dlog.Infof("%s:%d:%s() %s", file, line, name, msg)
|
|
||||||
case discordgo.LogDebug:
|
|
||||||
dlog.Debugf("%s:%d:%s() %s", file, line, name, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the bot.
|
// Start the bot.
|
||||||
func Start() {
|
func Start() {
|
||||||
discordgo.Logger = dgoLog
|
discordgo.Logger = dgoLog
|
||||||
|
|
||||||
// Load all the guilds
|
// Load all the guilds
|
||||||
loadGuilds()
|
if initProvider == nil {
|
||||||
|
log.Fatalf("You have not chosen a database provider. Please refer to the docs")
|
||||||
|
}
|
||||||
|
currentProvider = initProvider()
|
||||||
|
Guilds = loadGuilds()
|
||||||
|
|
||||||
// We need a token
|
// We need a token
|
||||||
if botToken == "" {
|
if botToken == "" {
|
||||||
|
|
@ -141,12 +133,14 @@ func Start() {
|
||||||
log.Fatalf("Failed to create Discord session: %s", err)
|
log.Fatalf("Failed to create Discord session: %s", err)
|
||||||
}
|
}
|
||||||
// Setup State specific variables
|
// Setup State specific variables
|
||||||
Session.State.MaxMessageCount = messageState
|
Session.State.MaxMessageCount = MessageState
|
||||||
Session.LogLevel = discordgo.LogWarning
|
Session.LogLevel = discordgo.LogWarning
|
||||||
Session.SyncEvents = false
|
Session.SyncEvents = false
|
||||||
Session.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAll)
|
Session.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAll)
|
||||||
|
|
||||||
// Set the bots status
|
// Set the bots status
|
||||||
Session.Identify.Presence = botPresence
|
Session.Identify.Presence = botPresence
|
||||||
|
|
||||||
// Open the session
|
// Open the session
|
||||||
log.Info("Connecting to Discord...")
|
log.Info("Connecting to Discord...")
|
||||||
err = Session.Open()
|
err = Session.Open()
|
||||||
|
|
@ -155,13 +149,13 @@ func Start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the commandHandler to the list of user-defined handlers
|
// Add the commandHandler to the list of user-defined handlers
|
||||||
AddHandler(commandHandler)
|
AddDGOHandler(commandHandler)
|
||||||
|
|
||||||
// Add the slash command handler to the list of user-defined handlers
|
// Add the slash command handler to the list of user-defined handlers
|
||||||
AddHandler(handleInteraction)
|
AddDGOHandler(handleInteraction)
|
||||||
|
|
||||||
// Add the handlers to the session
|
// Add the handlers to the session
|
||||||
addHandlers()
|
addDGoHandlers()
|
||||||
|
|
||||||
// Log that the login succeeded
|
// Log that the login succeeded
|
||||||
log.Infof("Bot logged in as \"" + Session.State.Ready.User.Username + "#" + Session.State.Ready.User.Discriminator + "\"")
|
log.Infof("Bot logged in as \"" + Session.State.Ready.User.Username + "#" + Session.State.Ready.User.Discriminator + "\"")
|
||||||
|
|
|
||||||
5
go.mod
5
go.mod
|
|
@ -9,3 +9,8 @@ require (
|
||||||
github.com/ubergeek77/tinylog v1.0.0
|
github.com/ubergeek77/tinylog v1.0.0
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||||
|
)
|
||||||
|
|
|
||||||
33
guilds.go
33
guilds.go
|
|
@ -28,6 +28,14 @@ type GuildInfo struct {
|
||||||
WhitelistIds []string `json:"whitelist_ids"`
|
WhitelistIds []string `json:"whitelist_ids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GuildProvider
|
||||||
|
// Type that holds functions that can be easily modified to support a wide range
|
||||||
|
// of storage types
|
||||||
|
type GuildProvider struct {
|
||||||
|
Save func(guild *Guild)
|
||||||
|
Load func() map[string]*Guild
|
||||||
|
}
|
||||||
|
|
||||||
// Guild
|
// Guild
|
||||||
// The definition of a guild, which is simply its ID and Info
|
// The definition of a guild, which is simply its ID and Info
|
||||||
type Guild struct {
|
type Guild struct {
|
||||||
|
|
@ -41,6 +49,11 @@ type Guild struct {
|
||||||
// Otherwise, there will be information desync
|
// Otherwise, there will be information desync
|
||||||
var Guilds = make(map[string]*Guild)
|
var Guilds = make(map[string]*Guild)
|
||||||
|
|
||||||
|
// currentProvider
|
||||||
|
// A reference to a struct of functions that provides the guild info system with a database
|
||||||
|
// Or similar system to save guild data.
|
||||||
|
var currentProvider GuildProvider
|
||||||
|
|
||||||
// getGuild
|
// getGuild
|
||||||
// Return a Guild object corresponding to the given guildId
|
// Return a Guild object corresponding to the given guildId
|
||||||
// If the guild doesn't exist, initialize a new guild and save it before returning
|
// If the guild doesn't exist, initialize a new guild and save it before returning
|
||||||
|
|
@ -90,7 +103,7 @@ func getGuild(guildId string) *Guild {
|
||||||
// Add the new guild to the map of guilds
|
// Add the new guild to the map of guilds
|
||||||
Guilds[guildId] = &newGuild
|
Guilds[guildId] = &newGuild
|
||||||
|
|
||||||
// Save the guild to .json
|
// Save the guild to database
|
||||||
// A failed save is fatal, so we can count on this being successful
|
// A failed save is fatal, so we can count on this being successful
|
||||||
newGuild.save()
|
newGuild.save()
|
||||||
|
|
||||||
|
|
@ -101,6 +114,18 @@ func getGuild(guildId string) *Guild {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadGuilds
|
||||||
|
// Load all known guilds from the database
|
||||||
|
func loadGuilds() map[string]*Guild {
|
||||||
|
return currentProvider.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
// save
|
||||||
|
// saves guild data to the database
|
||||||
|
func (g *Guild) save() {
|
||||||
|
currentProvider.Save(g)
|
||||||
|
}
|
||||||
|
|
||||||
// GetMember
|
// GetMember
|
||||||
// Convenience function to get a member in this guild
|
// Convenience function to get a member in this guild
|
||||||
// This function handles cleaning of the string so you don't have to
|
// This function handles cleaning of the string so you don't have to
|
||||||
|
|
@ -674,7 +699,7 @@ func (g *Guild) EnableCommandInChannel(command string, channelId string) error {
|
||||||
|
|
||||||
// DisableCommandInChannel
|
// DisableCommandInChannel
|
||||||
// Given a command and channel ID, add that command to that channel's list of blocked commands
|
// Given a command and channel ID, add that command to that channel's list of blocked commands
|
||||||
func (g *Guild) DisableTriggerInChannel(command string, channelId string) error {
|
func (g *Guild) DisableCommandInChannel(command string, channelId string) error {
|
||||||
cleanedId := CleanId(channelId)
|
cleanedId := CleanId(channelId)
|
||||||
if cleanedId == "" {
|
if cleanedId == "" {
|
||||||
return errors.New("provided channel ID is invalid")
|
return errors.New("provided channel ID is invalid")
|
||||||
|
|
@ -716,7 +741,7 @@ func (g *Guild) SetResponseChannel(channelId string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kick
|
// Kick
|
||||||
// Kick a member
|
// Kicks a member
|
||||||
func (g *Guild) Kick(userId string, reason string) error {
|
func (g *Guild) Kick(userId string, reason string) error {
|
||||||
// Make sure the member exists
|
// Make sure the member exists
|
||||||
member, err := g.GetMember(userId)
|
member, err := g.GetMember(userId)
|
||||||
|
|
@ -733,7 +758,7 @@ func (g *Guild) Kick(userId string, reason string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ban
|
// Ban
|
||||||
// Ban a user, who may not be a member
|
// Bans a user, who may not be a member
|
||||||
func (g *Guild) Ban(userId string, reason string, deleteDays int) error {
|
func (g *Guild) Ban(userId string, reason string, deleteDays int) error {
|
||||||
// Make sure the USER exists, because they may not be a member
|
// Make sure the USER exists, because they may not be a member
|
||||||
user, err := GetUser(userId)
|
user, err := GetUser(userId)
|
||||||
|
|
|
||||||
18
handlers.go
18
handlers.go
|
|
@ -1,29 +1,29 @@
|
||||||
package framework
|
package framework
|
||||||
|
|
||||||
// handlers.go
|
// handlers.go
|
||||||
// Everything required for commands to pass their own handlers to discordgo
|
// Everything required for commands to pass their own handlers to discordgo and the framework itself.
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
// This list stores all the handlers that can be added to the bot
|
// This list stores all the handlers that can be added to the bot
|
||||||
// It's basically a passthroughs for discordgo.AddHandler, but having a list
|
// It's basically a passthroughs for discordgo.AddHandler, but having a list
|
||||||
// allows them to be collected ahead of time and then added all at once
|
// allows them to be collected ahead of time and then added all at once
|
||||||
var handlers []interface{}
|
var dGOHandlers []interface{}
|
||||||
|
|
||||||
// AddHandler
|
// AddDGOHandler
|
||||||
// This provides a way for commands to pass handler functions through to discorgo,
|
// This provides a way for commands to pass handler functions through to discordgo,
|
||||||
// and have them added properly during bot startup
|
// and have them added properly during bot startup
|
||||||
func AddHandler(handler interface{}) {
|
func AddDGOHandler(handler interface{}) {
|
||||||
handlers = append(handlers, handler)
|
dGOHandlers = append(dGOHandlers, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addHandlers
|
// addHandlers
|
||||||
// Given all the handlers that have been pre-added to the handlers list, add them to the discordgo session
|
// Given all the handlers that have been pre-added to the handlers list, add them to the discordgo session
|
||||||
func addHandlers() {
|
func addDGoHandlers() {
|
||||||
if len(handlers) == 0 {
|
if len(dGOHandlers) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, handler := range handlers {
|
for _, handler := range dGOHandlers {
|
||||||
Session.AddHandler(handler)
|
Session.AddHandler(handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package framework
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/qpixel/framework"
|
||||||
|
tlog "github.com/ubergeek77/tinylog"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -16,10 +18,12 @@ import (
|
||||||
// fs.go
|
// fs.go
|
||||||
// This file contains functions that pertain to interacting with the filesystem, including mutex locking of files
|
// This file contains functions that pertain to interacting with the filesystem, including mutex locking of files
|
||||||
|
|
||||||
|
var log = tlog.NewTaggedLogger("BotCore", tlog.NewColor("38;5;111"))
|
||||||
|
|
||||||
// GuildsDir
|
// GuildsDir
|
||||||
// The directory to use for reading and writing guild .json files. Defaults to ./guilds
|
// The directory to use for reading and writing guild .json files. Defaults to ./guilds
|
||||||
// todo abstract this into a database module (being completed in feature/database)
|
// todo abstract this into a database module (being completed in feature/database)
|
||||||
var GuildsDir = ""
|
var GuildsDir = "./guilds"
|
||||||
|
|
||||||
// saveLock
|
// saveLock
|
||||||
// A map that stores mutexes for each guild, which will be locked every time that guild's data is written
|
// A map that stores mutexes for each guild, which will be locked every time that guild's data is written
|
||||||
|
|
@ -66,7 +70,7 @@ func loadGuilds() {
|
||||||
// - Add up to at least 17 characters (it must be a Discord snowflake)
|
// - Add up to at least 17 characters (it must be a Discord snowflake)
|
||||||
// - Are all numbers
|
// - Are all numbers
|
||||||
guildId := strings.Split(fName, ".json")[0]
|
guildId := strings.Split(fName, ".json")[0]
|
||||||
if len(guildId) < 17 || guildId != EnsureNumbers(guildId) {
|
if len(guildId) < 17 || guildId != framework.EnsureNumbers(guildId) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +92,7 @@ func loadGuilds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal the json
|
// Unmarshal the json
|
||||||
var gInfo GuildInfo
|
var gInfo framework.GuildInfo
|
||||||
err = json.Unmarshal(jsonBytes, &gInfo)
|
err = json.Unmarshal(jsonBytes, &gInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to unmarshal \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
|
log.Errorf("Failed to unmarshal \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
|
||||||
|
|
@ -96,29 +100,29 @@ func loadGuilds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the loaded guild to the map
|
// Add the loaded guild to the map
|
||||||
Guilds[guildId] = &Guild{
|
framework.Guilds[guildId] = &framework.Guild{
|
||||||
ID: guildId,
|
ID: guildId,
|
||||||
Info: gInfo,
|
Info: gInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(Guilds) == 0 {
|
if len(framework.Guilds) == 0 {
|
||||||
log.Warningf("There are no guilds to load; data for new guilds will be saved to \"%s\"", GuildsDir)
|
log.Warningf("There are no guilds to load; data for new guilds will be saved to \"%s\"", GuildsDir)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// :)
|
// :)
|
||||||
plural := ""
|
plural := ""
|
||||||
if len(Guilds) != 1 {
|
if len(framework.Guilds) != 1 {
|
||||||
plural = "s"
|
plural = "s"
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Loaded %d guild%s", len(Guilds), plural)
|
log.Infof("Loaded %d guild%s", len(framework.Guilds), plural)
|
||||||
}
|
}
|
||||||
|
|
||||||
// save
|
// save
|
||||||
// Save a given guild object to .json
|
// Save a given guild object to .json
|
||||||
func (g *Guild) save() {
|
func save(g *framework.Guild) {
|
||||||
// See if a mutex exists for this guild, and create if not
|
// See if a mutex exists for this guild, and create if not
|
||||||
if _, ok := saveLock[g.ID]; !ok {
|
if _, ok := saveLock[g.ID]; !ok {
|
||||||
saveLock[g.ID] = &sync.Mutex{}
|
saveLock[g.ID] = &sync.Mutex{}
|
||||||
|
|
@ -153,24 +157,9 @@ func (g *Guild) save() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDefaults
|
func InitProvider() framework.GuildProvider {
|
||||||
// TODO: WRITE DOCUMENTATION FOR THIS LMAO
|
return framework.GuildProvider{
|
||||||
func ReadDefaults(filePath string) (result []string) {
|
Save: save,
|
||||||
fPath := path.Clean(filePath)
|
Load: loadGuilds,
|
||||||
if _, existErr := os.Stat(fPath); os.IsNotExist(existErr) {
|
|
||||||
log.Errorf("Failed to find \"%s\"; File WILL NOT be loaded! (%s)", fPath, existErr)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, err := ioutil.ReadFile(fPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to read \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(jsonBytes, &result)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to unmarshal \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
//go:build darwin || linux
|
//go:build darwin || linux
|
||||||
// +build darwin linux
|
// +build darwin linux
|
||||||
|
|
||||||
package framework
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/qpixel/framework"
|
||||||
|
tlog "github.com/ubergeek77/tinylog"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -16,10 +18,12 @@ import (
|
||||||
// fs.go
|
// fs.go
|
||||||
// This file contains functions that pertain to interacting with the filesystem, including mutex locking of files
|
// This file contains functions that pertain to interacting with the filesystem, including mutex locking of files
|
||||||
|
|
||||||
|
var log = tlog.NewTaggedLogger("BotCore", tlog.NewColor("38;5;111"))
|
||||||
|
|
||||||
// GuildsDir
|
// GuildsDir
|
||||||
// The directory to use for reading and writing guild .json files. Defaults to ./guilds
|
// The directory to use for reading and writing guild .json files. Defaults to ./guilds
|
||||||
// todo remind me to abstract this into a database
|
// todo abstract this into a database module (being completed in feature/database)
|
||||||
var GuildsDir = ""
|
var GuildsDir = "./guilds"
|
||||||
|
|
||||||
// saveLock
|
// saveLock
|
||||||
// A map that stores mutexes for each guild, which will be locked every time that guild's data is written
|
// A map that stores mutexes for each guild, which will be locked every time that guild's data is written
|
||||||
|
|
@ -28,7 +32,7 @@ var saveLock = make(map[string]*sync.Mutex)
|
||||||
|
|
||||||
// loadGuilds
|
// loadGuilds
|
||||||
// Load all known guilds from the filesystem, from inside GuildsDir
|
// Load all known guilds from the filesystem, from inside GuildsDir
|
||||||
func loadGuilds() {
|
func loadGuilds() (guilds map[string]*framework.Guild) {
|
||||||
// Check if the configured guild directory exists, and create it if otherwise
|
// Check if the configured guild directory exists, and create it if otherwise
|
||||||
if _, existErr := os.Stat(GuildsDir); os.IsNotExist(existErr) {
|
if _, existErr := os.Stat(GuildsDir); os.IsNotExist(existErr) {
|
||||||
mkErr := os.MkdirAll(GuildsDir, 0755)
|
mkErr := os.MkdirAll(GuildsDir, 0755)
|
||||||
|
|
@ -38,10 +42,11 @@ func loadGuilds() {
|
||||||
log.Warningf("There are no Guilds to load; data for new Guilds will be saved to: %s", GuildsDir)
|
log.Warningf("There are no Guilds to load; data for new Guilds will be saved to: %s", GuildsDir)
|
||||||
|
|
||||||
// There are no guilds to load, so we can return early
|
// There are no guilds to load, so we can return early
|
||||||
return
|
return guilds
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of files in the directory
|
// Get a list of files in the directory
|
||||||
|
guilds = make(map[string]*framework.Guild)
|
||||||
files, rdErr := ioutil.ReadDir(GuildsDir)
|
files, rdErr := ioutil.ReadDir(GuildsDir)
|
||||||
if rdErr != nil {
|
if rdErr != nil {
|
||||||
log.Fatalf("Failed to read guild directory: %s", rdErr)
|
log.Fatalf("Failed to read guild directory: %s", rdErr)
|
||||||
|
|
@ -66,7 +71,7 @@ func loadGuilds() {
|
||||||
// - Add up to at least 17 characters (it must be a Discord snowflake)
|
// - Add up to at least 17 characters (it must be a Discord snowflake)
|
||||||
// - Are all numbers
|
// - Are all numbers
|
||||||
guildId := strings.Split(fName, ".json")[0]
|
guildId := strings.Split(fName, ".json")[0]
|
||||||
if len(guildId) < 17 || guildId != EnsureNumbers(guildId) {
|
if len(guildId) < 17 || guildId != framework.EnsureNumbers(guildId) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +91,7 @@ func loadGuilds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal the json
|
// Unmarshal the json
|
||||||
var gInfo GuildInfo
|
var gInfo framework.GuildInfo
|
||||||
err = json.Unmarshal(jsonBytes, &gInfo)
|
err = json.Unmarshal(jsonBytes, &gInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to unmarshal \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
|
log.Errorf("Failed to unmarshal \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
|
||||||
|
|
@ -94,29 +99,30 @@ func loadGuilds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the loaded guild to the map
|
// Add the loaded guild to the map
|
||||||
Guilds[guildId] = &Guild{
|
guilds[guildId] = &framework.Guild{
|
||||||
ID: guildId,
|
ID: guildId,
|
||||||
Info: gInfo,
|
Info: gInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(Guilds) == 0 {
|
if len(guilds) == 0 {
|
||||||
log.Warningf("There are no guilds to load; data for new guilds will be saved to \"%s\"", GuildsDir)
|
log.Warningf("There are no guilds to load; data for new guilds will be saved to \"%s\"", GuildsDir)
|
||||||
return
|
return guilds
|
||||||
}
|
}
|
||||||
|
|
||||||
// :)
|
// :)
|
||||||
plural := ""
|
plural := ""
|
||||||
if len(Guilds) != 1 {
|
if len(framework.Guilds) != 1 {
|
||||||
plural = "s"
|
plural = "s"
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Loaded %d guild%s", len(Guilds), plural)
|
log.Infof("Loaded %d guild%s", len(guilds), plural)
|
||||||
|
return guilds
|
||||||
}
|
}
|
||||||
|
|
||||||
// save
|
// save
|
||||||
// Save a given guild object to .json
|
// Save a given guild object to .json
|
||||||
func (g *Guild) save() {
|
func save(g *framework.Guild) {
|
||||||
// See if a mutex exists for this guild, and create if not
|
// See if a mutex exists for this guild, and create if not
|
||||||
if _, ok := saveLock[g.ID]; !ok {
|
if _, ok := saveLock[g.ID]; !ok {
|
||||||
saveLock[g.ID] = &sync.Mutex{}
|
saveLock[g.ID] = &sync.Mutex{}
|
||||||
|
|
@ -151,24 +157,11 @@ func (g *Guild) save() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDefaults
|
// InitProvider
|
||||||
// TODO: WRITE DOCUMENTATION FOR THIS LMAO
|
// Inits the filesystem provider
|
||||||
func ReadDefaults(filePath string) (result []string) {
|
func InitProvider() framework.GuildProvider {
|
||||||
fPath := path.Clean(filePath)
|
return framework.GuildProvider{
|
||||||
if _, existErr := os.Stat(fPath); os.IsNotExist(existErr) {
|
Save: save,
|
||||||
log.Errorf("Failed to find \"%s\"; File WILL NOT be loaded! (%s)", fPath, existErr)
|
Load: loadGuilds,
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, err := ioutil.ReadFile(fPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to read \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(jsonBytes, &result)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to unmarshal \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
24
util.go
24
util.go
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/dlclark/regexp2"
|
"github.com/dlclark/regexp2"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -355,3 +356,26 @@ func FindAllString(re *regexp2.Regexp, s string) []string {
|
||||||
}
|
}
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dgoLog
|
||||||
|
// Allows for discordgo to call tinylog
|
||||||
|
func dgoLog(msgL, caller int, format string, a ...interface{}) {
|
||||||
|
pc, file, line, _ := runtime.Caller(caller)
|
||||||
|
files := strings.Split(file, "/")
|
||||||
|
file = files[len(files)-1]
|
||||||
|
|
||||||
|
name := runtime.FuncForPC(pc).Name()
|
||||||
|
fns := strings.Split(name, ".")
|
||||||
|
name = fns[len(fns)-1]
|
||||||
|
msg := fmt.Sprintf(format, a...)
|
||||||
|
switch msgL {
|
||||||
|
case discordgo.LogError:
|
||||||
|
dlog.Errorf("%s:%d:%s() %s", file, line, name, msg)
|
||||||
|
case discordgo.LogWarning:
|
||||||
|
dlog.Warningf("%s:%d:%s() %s", file, line, name, msg)
|
||||||
|
case discordgo.LogInformational:
|
||||||
|
dlog.Infof("%s:%d:%s() %s", file, line, name, msg)
|
||||||
|
case discordgo.LogDebug:
|
||||||
|
dlog.Debugf("%s:%d:%s() %s", file, line, name, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue