config: add defaults checking where necessary

This commit is contained in:
Chris Sexton 2019-01-21 14:24:03 -05:00
parent 15168f5db0
commit 742c76f562
13 changed files with 180 additions and 17 deletions

View File

@ -79,6 +79,7 @@ func New(config *config.Config, connector Connector) Bot {
addr := config.Get("HttpAddr") addr := config.Get("HttpAddr")
if addr == "" { if addr == "" {
addr = "127.0.0.1:1337" addr = "127.0.0.1:1337"
config.Set("HttpAddr", addr)
} }
go http.ListenAndServe(addr, nil) go http.ListenAndServe(addr, nil)
@ -172,7 +173,14 @@ func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) {
// Checks if message is a command and returns its curtailed version // Checks if message is a command and returns its curtailed version
func IsCmd(c *config.Config, message string) (bool, string) { func IsCmd(c *config.Config, message string) (bool, string) {
cmdcs := c.GetArray("CommandChar") cmdcs := c.GetArray("CommandChar")
if len(cmdcs) == 0 {
cmdcs = []string{"!"}
c.SetArray("CommandChar", cmdcs)
}
botnick := strings.ToLower(c.Get("Nick")) botnick := strings.ToLower(c.Get("Nick"))
if botnick == "" {
log.Fatalf(`You must run catbase -set nick -val <your bot nick>`)
}
iscmd := false iscmd := false
lowerMessage := strings.ToLower(message) lowerMessage := strings.ToLower(message)

View File

@ -54,6 +54,12 @@ func (c *Config) Get(key string) string {
return c.GetString(key) return c.GetString(key)
} }
func envkey(key string) string {
key = strings.ToUpper(key)
key = strings.Replace(key, ".", "", -1)
return key
}
// GetString returns the config value for a string key // GetString returns the config value for a string key
// It will first look in the env vars for the key // It will first look in the env vars for the key
// It will check the DB for the key if an env DNE // It will check the DB for the key if an env DNE
@ -61,13 +67,14 @@ func (c *Config) Get(key string) string {
// It will convert the value to a string if it exists // It will convert the value to a string if it exists
func (c *Config) GetString(key string) string { func (c *Config) GetString(key string) string {
key = strings.ToLower(key) key = strings.ToLower(key)
if v, found := os.LookupEnv(key); found { if v, found := os.LookupEnv(envkey(key)); found {
return v return v
} }
var configValue string var configValue string
q := `select value from config where key=?` q := `select value from config where key=?`
err := c.DB.Get(&configValue, q, key) err := c.DB.Get(&configValue, q, key)
if err != nil { if err != nil {
log.Printf("WARN: Key %s is empty", key)
return "" return ""
} }
return configValue return configValue
@ -81,6 +88,9 @@ func (c *Config) GetString(key string) string {
// This will do no conversion. // This will do no conversion.
func (c *Config) GetArray(key string) []string { func (c *Config) GetArray(key string) []string {
val := c.GetString(key) val := c.GetString(key)
if val == "" {
return []string{}
}
return strings.Split(val, ";;") return strings.Split(val, ";;")
} }
@ -88,14 +98,19 @@ func (c *Config) GetArray(key string) []string {
// Note, this is always a string. Use the SetArray for an array helper // Note, this is always a string. Use the SetArray for an array helper
func (c *Config) Set(key, value string) error { func (c *Config) Set(key, value string) error {
key = strings.ToLower(key) key = strings.ToLower(key)
q := (`insert into config (key,value) values (?, ?);`) q := (`insert into config (key,value) values (?, ?)
_, err := c.Exec(q, key, value) on conflict(key) do update set value=?;`)
if err != nil { tx, err := c.Begin()
q := (`update config set value=? where key=?);`)
_, err = c.Exec(q, value, key)
if err != nil { if err != nil {
return err return err
} }
_, err = tx.Exec(q, key, value, value)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
} }
return nil return nil
} }

57
config/defaults.go Normal file
View File

@ -0,0 +1,57 @@
package config
import (
"bytes"
"html/template"
"log"
"strings"
)
var q = `
INSERT INTO config VALUES('type','slack');
INSERT INTO config VALUES('nick','{{.Nick}}');
INSERT INTO config VALUES('channels','{{.Channel}}');
INSERT INTO config VALUES('factoid.quotetime',30);
INSERT INTO config VALUES('reaction.negativereactions','bullshit;;fake;;tableflip;;vomit');
INSERT INTO config VALUES('reaction.positivereactions','+1;;authorized;;aw_yeah;;yeah_man;;joy');
INSERT INTO config VALUES('reaction.generalchance',0.01);
INSERT INTO config VALUES('reaction.harrasschance',0.05);
INSERT INTO config VALUES('commandchar','!;;¡');
INSERT INTO config VALUES('factoid.startupfact','speed test');
INSERT INTO config VALUES('factoid.quotechance',0.99);
INSERT INTO config VALUES('factoid.minlen',4);
INSERT INTO config VALUES('untappd.channels','{{.Channel}}');
INSERT INTO config VALUES('twitch.channels','{{.Channel}}');
INSERT INTO config VALUES('twitch.{{.ChannelKey}}.users','drseabass;;phlyingpenguin;;stack5;;geoffwithaj;;msherms;;eaburns;;sheltim;;rathaus;;rcuhljr');
INSERT INTO config VALUES('twitch.freq',60);
INSERT INTO config VALUES('leftpad.maxlen',50);
INSERT INTO config VALUES('untappd.freq',60);
INSERT INTO config VALUES('your.replacements.0.freq',1);
INSERT INTO config VALUES('your.replacements.0.this','fuck');
INSERT INTO config VALUES('your.replacements.0.that','duck');
INSERT INTO config VALUES('your.replacements','0;;1;;2');
INSERT INTO config VALUES('httpaddr','127.0.0.1:1337');
INSERT INTO config VALUES('your.maxlength',140);
INSERT INTO config VALUES('init',1);
`
func (c *Config) SetDefaults(mainChannel, nick string) {
if nick == mainChannel && nick == "" {
log.Fatalf("You must provide a nick and a mainChannel")
}
t := template.Must(template.New("query").Parse(q))
vals := struct {
Nick string
Channel string
ChannelKey string
}{
nick,
mainChannel,
strings.ToLower(mainChannel),
}
var buf bytes.Buffer
t.Execute(&buf, vals)
c.MustExec(`delete from config;`)
c.MustExec(buf.String())
log.Println("Configuration initialized.")
}

24
main.go
View File

@ -38,6 +38,12 @@ import (
"github.com/velour/catbase/slack" "github.com/velour/catbase/slack"
) )
var (
key = flag.String("set", "", "Configuration key to set")
val = flag.String("val", "", "Configuration value to set")
initDB = flag.Bool("init", false, "Initialize the configuration DB")
)
func main() { func main() {
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
@ -46,8 +52,26 @@ func main() {
flag.Parse() // parses the logging flags. flag.Parse() // parses the logging flags.
c := config.ReadConfig(*dbpath) c := config.ReadConfig(*dbpath)
if *key != "" && *val != "" {
c.Set(*key, *val)
log.Printf("Set config %s: %s", *key, *val)
return
}
if (*initDB && len(flag.Args()) != 2) || (!*initDB && c.GetInt("init") != 1) {
log.Fatal(`You must run "catbase -init <channel> <nick>"`)
} else if *initDB {
c.SetDefaults(flag.Arg(0), flag.Arg(1))
return
}
var client bot.Connector var client bot.Connector
t := c.Get("type")
if t == "" {
c.Set("type", "slack")
t = "slack"
}
switch c.Get("type") { switch c.Get("type") {
case "irc": case "irc":
client = irc.New(c) client = irc.New(c)

View File

@ -306,7 +306,12 @@ type Beers struct {
} }
func (p *BeersPlugin) pullUntappd() ([]checkin, error) { func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
access_token := "?access_token=" + p.Bot.Config().Get("Untappd.Token") token := p.Bot.Config().Get("Untappd.Token")
if token == "" {
return []checkin{}, fmt.Errorf("No untappd token")
}
access_token := "?access_token=" + token
baseUrl := "https://api.untappd.com/v4/checkin/recent/" baseUrl := "https://api.untappd.com/v4/checkin/recent/"
url := baseUrl + access_token + "&limit=25" url := baseUrl + access_token + "&limit=25"
@ -337,7 +342,8 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
func (p *BeersPlugin) checkUntappd(channel string) { func (p *BeersPlugin) checkUntappd(channel string) {
token := p.Bot.Config().Get("Untappd.Token") token := p.Bot.Config().Get("Untappd.Token")
if token == "" || token == "<Your Token>" { if token == "" {
log.Println(`Set config value "untappd.token" if you wish to enable untappd`)
return return
} }
@ -421,6 +427,9 @@ func (p *BeersPlugin) checkUntappd(channel string) {
func (p *BeersPlugin) untappdLoop(channel string) { func (p *BeersPlugin) untappdLoop(channel string) {
frequency := p.Bot.Config().GetInt("Untappd.Freq") frequency := p.Bot.Config().GetInt("Untappd.Freq")
if frequency == 0 {
return
}
log.Println("Checking every ", frequency, " seconds") log.Println("Checking every ", frequency, " seconds")

View File

@ -691,7 +691,12 @@ func (p *Factoid) randomFact() *factoid {
// factTimer spits out a fact at a given interval and with given probability // factTimer spits out a fact at a given interval and with given probability
func (p *Factoid) factTimer(channel string) { func (p *Factoid) factTimer(channel string) {
duration := time.Duration(p.Bot.Config().GetInt("Factoid.QuoteTime")) * time.Minute quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime")
if quoteTime == 0 {
quoteTime = 30
p.Bot.Config().Set("Factoid.QuoteTime", "30")
}
duration := time.Duration(quoteTime) * time.Minute
myLastMsg := time.Now() myLastMsg := time.Now()
for { for {
time.Sleep(time.Duration(5) * time.Second) // why 5? time.Sleep(time.Duration(5) * time.Second) // why 5?
@ -705,7 +710,12 @@ func (p *Factoid) factTimer(channel string) {
tdelta := time.Since(lastmsg.Time) tdelta := time.Since(lastmsg.Time)
earlier := time.Since(myLastMsg) > tdelta earlier := time.Since(myLastMsg) > tdelta
chance := rand.Float64() chance := rand.Float64()
success := chance < p.Bot.Config().GetFloat64("Factoid.QuoteChance") quoteChance := p.Bot.Config().GetFloat64("Factoid.QuoteChance")
if quoteChance == 0.0 {
quoteChance = 0.99
p.Bot.Config().Set("Factoid.QuoteChance", "0.99")
}
success := chance < quoteChance
if success && tdelta > duration && earlier { if success && tdelta > duration && earlier {
fact := p.randomFact() fact := p.randomFact()

View File

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"log" "log"
"regexp" "regexp"
"strconv"
"strings" "strings"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -201,7 +202,12 @@ func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
return true return true
} }
var removed string var removed string
if p.count() > p.config.GetInt("Inventory.Max") { max := p.config.GetInt("inventory.max")
if max == 0 {
max = 10
p.config.Set("inventory.max", strconv.Itoa(max))
}
if p.count() > max {
removed = p.removeRandom() removed = p.removeRandom()
} }
_, err := p.Exec(`INSERT INTO inventory (item) values (?)`, i) _, err := p.Exec(`INSERT INTO inventory (item) values (?)`, i)

View File

@ -45,7 +45,12 @@ func (p *LeftpadPlugin) Message(message msg.Message) bool {
p.bot.SendMessage(message.Channel, "Invalid padding number") p.bot.SendMessage(message.Channel, "Invalid padding number")
return true return true
} }
if length > p.config.GetInt("LeftPad.MaxLen") && p.config.GetInt("LeftPad.MaxLen") > 0 { maxLen, who := p.config.GetInt("LeftPad.MaxLen"), p.config.Get("LeftPad.Who")
if who == "" {
who = "Putin"
p.config.Set("LeftPad.MaxLen", who)
}
if length > maxLen && maxLen > 0 {
msg := fmt.Sprintf("%s would kill me if I did that.", p.config.Get("LeftPad.Who")) msg := fmt.Sprintf("%s would kill me if I did that.", p.config.Get("LeftPad.Who"))
p.bot.SendMessage(message.Channel, msg) p.bot.SendMessage(message.Channel, msg)
return true return true

View File

@ -31,6 +31,7 @@ func makePlugin(t *testing.T) (*LeftpadPlugin, *bot.MockBot) {
counter.New(mb) counter.New(mb)
p := New(mb) p := New(mb)
assert.NotNil(t, p) assert.NotNil(t, p)
p.config.Set("LeftPad.MaxLen", "0")
return p, mb return p, mb
} }
@ -56,6 +57,7 @@ func TestNotCommand(t *testing.T) {
func TestNoMaxLen(t *testing.T) { func TestNoMaxLen(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.config.Set("LeftPad.MaxLen", "0")
p.Message(makeMessage("!leftpad dicks 100 dicks")) p.Message(makeMessage("!leftpad dicks 100 dicks"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "dicks") assert.Contains(t, mb.Messages[0], "dicks")

View File

@ -122,7 +122,12 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
what := strings.Join(parts[6:], " ") what := strings.Join(parts[6:], " ")
for i := 0; when.Before(endTime); i++ { for i := 0; when.Before(endTime); i++ {
if i >= p.config.GetInt("Reminder.MaxBatchAdd") { max := p.config.GetInt("Reminder.MaxBatchAdd")
if max == 0 {
max = 10
p.config.Set("reminder.maxbatchadd", strconv.Itoa(max))
}
if i >= max {
p.Bot.SendMessage(channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.") p.Bot.SendMessage(channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.")
doConfirm = false doConfirm = false
break break

View File

@ -60,7 +60,13 @@ func (g *game) scheduleDecrement() {
g.timers[0].Stop() g.timers[0].Stop()
} }
minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement") minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement")
maxDec := g.bot.Config().GetInt("Sisyphus.MinDecrement") maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement")
if maxDec == minDec && maxDec == 0 {
maxDec = 30
minDec = 10
g.bot.Config().Set("Sisyphus.MinDecrement", strconv.Itoa(minDec))
g.bot.Config().Set("Sisyphus.MaxDecrement", strconv.Itoa(maxDec))
}
g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute) g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute)
go func() { go func() {
t := time.NewTimer(g.nextDec.Sub(time.Now())) t := time.NewTimer(g.nextDec.Sub(time.Now()))
@ -78,6 +84,12 @@ func (g *game) schedulePush() {
} }
minPush := g.bot.Config().GetInt("Sisyphus.MinPush") minPush := g.bot.Config().GetInt("Sisyphus.MinPush")
maxPush := g.bot.Config().GetInt("Sisyphus.MaxPush") maxPush := g.bot.Config().GetInt("Sisyphus.MaxPush")
if minPush == maxPush && maxPush == 0 {
minPush = 1
maxPush = 10
g.bot.Config().Set("Sisyphus.MinPush", strconv.Itoa(minPush))
g.bot.Config().Set("Sisyphus.MaxPush", strconv.Itoa(maxPush))
}
g.nextPush = time.Now().Add(time.Duration(rand.Intn(maxPush)+minPush) * time.Minute) g.nextPush = time.Now().Add(time.Duration(rand.Intn(maxPush)+minPush) * time.Minute)
go func() { go func() {
t := time.NewTimer(g.nextPush.Sub(time.Now())) t := time.NewTimer(g.nextPush.Sub(time.Now()))

View File

@ -4,6 +4,7 @@ package your
import ( import (
"math/rand" "math/rand"
"strconv"
"strings" "strings"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
@ -28,7 +29,12 @@ func New(bot bot.Bot) *YourPlugin {
// This function returns true if the plugin responds in a meaningful way to the users message. // This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *YourPlugin) Message(message msg.Message) bool { func (p *YourPlugin) Message(message msg.Message) bool {
if len(message.Body) > p.config.GetInt("Your.MaxLength") { maxLen := p.config.GetInt("your.maxlength")
if maxLen == 0 {
maxLen = 140
p.config.Set("your.maxlength", strconv.Itoa(maxLen))
}
if len(message.Body) > maxLen {
return false return false
} }
msg := message.Body msg := message.Body

View File

@ -212,6 +212,10 @@ func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string
nick := s.config.Get("Nick") nick := s.config.Get("Nick")
icon := s.config.Get("IconURL") icon := s.config.Get("IconURL")
if icon == "" {
icon = "https://placekitten.com/400/400"
log.Println("Set config item IconURL to customize appearance!")
}
resp, err := http.PostForm(postUrl, resp, err := http.PostForm(postUrl,
url.Values{"token": {s.config.Get("Slack.Token")}, url.Values{"token": {s.config.Get("Slack.Token")},