mirror of https://github.com/velour/catbase.git
Compare commits
2 Commits
1d3748ed06
...
1f954f301c
Author | SHA1 | Date |
---|---|---|
Chris Sexton | 1f954f301c | |
Chris Sexton | 4a0ba76b89 |
|
@ -94,7 +94,7 @@ type Bot interface {
|
||||||
// Usually, the first vararg should be a channel ID, but refer to the Connector for info
|
// Usually, the first vararg should be a channel ID, but refer to the Connector for info
|
||||||
Send(Connector, Kind, ...interface{}) (string, error)
|
Send(Connector, Kind, ...interface{}) (string, error)
|
||||||
|
|
||||||
// Bot receives from a Connector.
|
// bot receives from a Connector.
|
||||||
// The Kind arg should be one of bot.Message/Reply/Action/etc
|
// The Kind arg should be one of bot.Message/Reply/Action/etc
|
||||||
Receive(Connector, Kind, msg.Message, ...interface{}) bool
|
Receive(Connector, Kind, msg.Message, ...interface{}) bool
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Discord struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *config.Config) *Discord {
|
func New(config *config.Config) *Discord {
|
||||||
client, err := discordgo.New("Bot " + config.Get("DISCORDBOTTOKEN", ""))
|
client, err := discordgo.New("bot " + config.Get("DISCORDBOTTOKEN", ""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("Could not connect to Discord")
|
log.Fatal().Err(err).Msg("Could not connect to Discord")
|
||||||
}
|
}
|
||||||
|
|
2
main.go
2
main.go
|
@ -39,7 +39,6 @@ import (
|
||||||
"github.com/velour/catbase/plugins/emojifyme"
|
"github.com/velour/catbase/plugins/emojifyme"
|
||||||
"github.com/velour/catbase/plugins/fact"
|
"github.com/velour/catbase/plugins/fact"
|
||||||
"github.com/velour/catbase/plugins/first"
|
"github.com/velour/catbase/plugins/first"
|
||||||
"github.com/velour/catbase/plugins/fuck"
|
|
||||||
"github.com/velour/catbase/plugins/git"
|
"github.com/velour/catbase/plugins/git"
|
||||||
"github.com/velour/catbase/plugins/impossible"
|
"github.com/velour/catbase/plugins/impossible"
|
||||||
"github.com/velour/catbase/plugins/inventory"
|
"github.com/velour/catbase/plugins/inventory"
|
||||||
|
@ -121,7 +120,6 @@ func main() {
|
||||||
b.AddPlugin(emojifyme.New(b))
|
b.AddPlugin(emojifyme.New(b))
|
||||||
b.AddPlugin(first.New(b))
|
b.AddPlugin(first.New(b))
|
||||||
b.AddPlugin(leftpad.New(b))
|
b.AddPlugin(leftpad.New(b))
|
||||||
b.AddPlugin(fuck.New(b))
|
|
||||||
b.AddPlugin(talker.New(b))
|
b.AddPlugin(talker.New(b))
|
||||||
b.AddPlugin(dice.New(b))
|
b.AddPlugin(dice.New(b))
|
||||||
b.AddPlugin(picker.New(b))
|
b.AddPlugin(picker.New(b))
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/velour/catbase/bot"
|
"github.com/velour/catbase/bot"
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
)
|
)
|
||||||
|
@ -18,8 +19,10 @@ import (
|
||||||
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
|
// This is a first plugin to serve as an example and quick copy/paste for new plugins.
|
||||||
|
|
||||||
type FirstPlugin struct {
|
type FirstPlugin struct {
|
||||||
Bot bot.Bot
|
bot bot.Bot
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
|
handlers bot.HandlerTable
|
||||||
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type FirstEntry struct {
|
type FirstEntry struct {
|
||||||
|
@ -47,6 +50,22 @@ func (fe *FirstEntry) save(db *sqlx.DB) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fe *FirstEntry) delete(db *sqlx.DB) error {
|
||||||
|
tx, err := db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tx.Exec(`delete from first where id=?`, fe.id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewFirstPlugin creates a new FirstPlugin with the Plugin interface
|
// NewFirstPlugin creates a new FirstPlugin with the Plugin interface
|
||||||
func New(b bot.Bot) *FirstPlugin {
|
func New(b bot.Bot) *FirstPlugin {
|
||||||
_, err := b.DB().Exec(`create table if not exists first (
|
_, err := b.DB().Exec(`create table if not exists first (
|
||||||
|
@ -67,10 +86,11 @@ func New(b bot.Bot) *FirstPlugin {
|
||||||
midnight(time.Now()))
|
midnight(time.Now()))
|
||||||
|
|
||||||
fp := &FirstPlugin{
|
fp := &FirstPlugin{
|
||||||
Bot: b,
|
bot: b,
|
||||||
db: b.DB(),
|
db: b.DB(),
|
||||||
|
enabled: true,
|
||||||
}
|
}
|
||||||
b.Register(fp, bot.Message, fp.message)
|
fp.register()
|
||||||
b.Register(fp, bot.Help, fp.help)
|
b.Register(fp, bot.Help, fp.help)
|
||||||
return fp
|
return fp
|
||||||
}
|
}
|
||||||
|
@ -129,56 +149,98 @@ func isNotToday(f *FirstEntry) bool {
|
||||||
return t0.Before(midnight(time.Now()))
|
return t0.Before(midnight(time.Now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message responds to the bot hook on recieving messages.
|
func (p *FirstPlugin) register() {
|
||||||
// This function returns true if the plugin responds in a meaningful way to the users message.
|
p.handlers = []bot.HandlerSpec{
|
||||||
// Otherwise, the function returns false and the bot continues execution of other plugins.
|
{Kind: bot.Message, IsCmd: false,
|
||||||
func (p *FirstPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
Regex: regexp.MustCompile(`(?i)^who'?s on first the most.?$`),
|
||||||
if message.IsIM {
|
Handler: func(r bot.Request) bool {
|
||||||
log.Debug().Msg("Skipping IM")
|
first, err := getLastFirst(p.db, r.Msg.Channel)
|
||||||
return false
|
if first != nil && err == nil {
|
||||||
}
|
p.leaderboard(r.Conn, r.Msg.Channel)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}},
|
||||||
|
{Kind: bot.Message, IsCmd: false,
|
||||||
|
Regex: regexp.MustCompile(`(?i)^who'?s on first.?$`),
|
||||||
|
Handler: func(r bot.Request) bool {
|
||||||
|
first, err := getLastFirst(p.db, r.Msg.Channel)
|
||||||
|
if first != nil && err == nil {
|
||||||
|
p.announceFirst(r.Conn, first)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}},
|
||||||
|
{Kind: bot.Message, IsCmd: true,
|
||||||
|
Regex: regexp.MustCompile(`(?i)^clear first$`),
|
||||||
|
Handler: func(r bot.Request) bool {
|
||||||
|
if !p.bot.CheckAdmin(r.Msg.User.Name) {
|
||||||
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, "You are not authorized to do that.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
fe, err := getLastFirst(p.db, r.Msg.Channel)
|
||||||
|
if err != nil {
|
||||||
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, "Could not find a first entry.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.enabled = false
|
||||||
|
err = fe.delete(p.db)
|
||||||
|
if err != nil {
|
||||||
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel,
|
||||||
|
fmt.Sprintf("Could not delete first entry: %s", err))
|
||||||
|
p.enabled = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
d := p.bot.Config().GetInt("first.maxregen", 300)
|
||||||
|
log.Debug().Msgf("Setting first timer for %d seconds", d)
|
||||||
|
timer := time.NewTimer(time.Duration(d) * time.Second)
|
||||||
|
go func() {
|
||||||
|
<-timer.C
|
||||||
|
p.enabled = true
|
||||||
|
log.Debug().Msgf("Re-enabled first")
|
||||||
|
}()
|
||||||
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel,
|
||||||
|
fmt.Sprintf("Deleted first entry: '%s' and set a random timer for when first will happen next.", fe.body))
|
||||||
|
return true
|
||||||
|
}},
|
||||||
|
{Kind: bot.Message, IsCmd: false,
|
||||||
|
Regex: regexp.MustCompile(`.*`),
|
||||||
|
Handler: func(r bot.Request) bool {
|
||||||
|
if r.Msg.IsIM || !p.enabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
first, err := getLastFirst(p.db, message.Channel)
|
first, err := getLastFirst(p.db, r.Msg.Channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("Error getting last first")
|
Msg("Error getting last first")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Bool("first == nil", first == nil).Msg("Is first nil?")
|
log.Debug().Bool("first == nil", first == nil).Msg("Is first nil?")
|
||||||
log.Debug().Bool("first == nil || isNotToday()", isNotToday(first)).Msg("Is it today?")
|
log.Debug().Bool("first == nil || isNotToday()", isNotToday(first)).Msg("Is it today?")
|
||||||
log.Debug().Bool("p.allowed", p.allowed(message)).Msg("Allowed?")
|
log.Debug().Bool("p.allowed", p.allowed(r.Msg)).Msg("Allowed?")
|
||||||
|
|
||||||
if (first == nil || isNotToday(first)) && p.allowed(message) {
|
if (first == nil || isNotToday(first)) && p.allowed(r.Msg) {
|
||||||
log.Debug().
|
log.Debug().
|
||||||
Str("body", message.Body).
|
Str("body", r.Msg.Body).
|
||||||
Interface("t0", first).
|
Interface("t0", first).
|
||||||
Time("t1", time.Now()).
|
Time("t1", time.Now()).
|
||||||
Msg("Recording first")
|
Msg("Recording first")
|
||||||
p.recordFirst(c, message)
|
p.recordFirst(r.Conn, r.Msg)
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
p.bot.RegisterTable(p, p.handlers)
|
||||||
r := strings.NewReplacer("’", "", "'", "", "\"", "", ",", "", ".", "", ":", "",
|
|
||||||
"?", "", "!", "")
|
|
||||||
m := strings.ToLower(message.Body)
|
|
||||||
if r.Replace(m) == "whos on first the most" && first != nil {
|
|
||||||
p.leaderboard(c, message.Channel)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if r.Replace(m) == "whos on first" && first != nil {
|
|
||||||
p.announceFirst(c, first)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FirstPlugin) allowed(message msg.Message) bool {
|
func (p *FirstPlugin) allowed(message msg.Message) bool {
|
||||||
if message.Body == "" {
|
if message.Body == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, m := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) {
|
for _, m := range p.bot.Config().GetArray("Bad.Msgs", []string{}) {
|
||||||
match, err := regexp.MatchString(m, strings.ToLower(message.Body))
|
match, err := regexp.MatchString(m, strings.ToLower(message.Body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Bad regexp")
|
log.Error().Err(err).Msg("Bad regexp")
|
||||||
|
@ -191,7 +253,7 @@ func (p *FirstPlugin) allowed(message msg.Message) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, host := range p.Bot.Config().GetArray("Bad.Hosts", []string{}) {
|
for _, host := range p.bot.Config().GetArray("Bad.Hosts", []string{}) {
|
||||||
if host == message.Host {
|
if host == message.Host {
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("user", message.User.Name).
|
Str("user", message.User.Name).
|
||||||
|
@ -200,7 +262,7 @@ func (p *FirstPlugin) allowed(message msg.Message) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, nick := range p.Bot.Config().GetArray("Bad.Nicks", []string{}) {
|
for _, nick := range p.bot.Config().GetArray("Bad.Nicks", []string{}) {
|
||||||
if nick == message.User.Name {
|
if nick == message.User.Name {
|
||||||
log.Info().
|
log.Info().
|
||||||
Str("user", message.User.Name).
|
Str("user", message.User.Name).
|
||||||
|
@ -255,18 +317,18 @@ func (p *FirstPlugin) leaderboard(c bot.Connector, ch string) error {
|
||||||
for i, e := range res {
|
for i, e := range res {
|
||||||
msg += fmt.Sprintf("%s %d %s\n", talismans[i], e.Count, e.Nick)
|
msg += fmt.Sprintf("%s %d %s\n", talismans[i], e.Count, e.Nick)
|
||||||
}
|
}
|
||||||
p.Bot.Send(c, bot.Message, ch, msg)
|
p.bot.Send(c, bot.Message, ch, msg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *FirstPlugin) announceFirst(c bot.Connector, first *FirstEntry) {
|
func (p *FirstPlugin) announceFirst(c bot.Connector, first *FirstEntry) {
|
||||||
ch := first.channel
|
ch := first.channel
|
||||||
p.Bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
|
p.bot.Send(c, bot.Message, ch, fmt.Sprintf("%s had first at %s with the message: \"%s\"",
|
||||||
first.nick, first.time.Format("15:04"), first.body))
|
first.nick, first.time.Format("15:04"), first.body))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help responds to help requests. Every plugin must implement a help function.
|
// Help responds to help requests. Every plugin must implement a help function.
|
||||||
func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *FirstPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
p.Bot.Send(c, bot.Message, message.Channel, "You can ask 'who's on first?' to find out.")
|
p.bot.Send(c, bot.Message, message.Channel, "You can ask 'who's on first?' to find out.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package fuck
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/chrissexton/gofuck"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"github.com/velour/catbase/bot"
|
|
||||||
"github.com/velour/catbase/bot/msg"
|
|
||||||
"github.com/velour/catbase/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Fuck struct {
|
|
||||||
b bot.Bot
|
|
||||||
c *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(b bot.Bot) *Fuck {
|
|
||||||
f := &Fuck{
|
|
||||||
b: b,
|
|
||||||
c: b.Config(),
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Register(f, bot.Help, f.help)
|
|
||||||
b.Register(f, bot.Message, f.message)
|
|
||||||
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Fuck) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
||||||
helpMsg := "Run brainfuck with: `!fuck ```<program>``` <stdin>`\n\nFor example:\n> !fuck ```,[.,]``` hello"
|
|
||||||
p.b.Send(c, bot.Message, message.Channel, helpMsg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Fuck) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
||||||
lowerBody := strings.ToLower(message.Body)
|
|
||||||
if message.Command && strings.HasPrefix(lowerBody, "fuck") {
|
|
||||||
fields := strings.Split(message.Body, "```")
|
|
||||||
if len(fields) < 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pgm := fields[1]
|
|
||||||
in := strings.Join(fields[2:], "```")
|
|
||||||
|
|
||||||
log.Debug().
|
|
||||||
Str("pgm", pgm).
|
|
||||||
Str("in", in).
|
|
||||||
Msg("Asked to fuck hard")
|
|
||||||
|
|
||||||
stdin := bytes.NewBufferString(in)
|
|
||||||
stdout := &bytes.Buffer{}
|
|
||||||
|
|
||||||
m := gofuck.New(stdin, stdout)
|
|
||||||
|
|
||||||
m.InstructionLimit = p.c.GetInt("fuck.limit.instr", 100000)
|
|
||||||
if m.InstructionLimit < 1 {
|
|
||||||
m.InstructionLimit = 1
|
|
||||||
}
|
|
||||||
maxOut := p.c.GetInt("fuck.limit.output", 1000)
|
|
||||||
|
|
||||||
err := m.Run([]byte(pgm))
|
|
||||||
if stdout.Len() > maxOut {
|
|
||||||
stdout.Truncate(maxOut)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
p.b.Send(c, bot.Message, message.Channel, fmt.Sprintf("Error running program: %s", err))
|
|
||||||
if stdout.Len() > 0 {
|
|
||||||
p.b.Send(c, bot.Message, message.Channel,
|
|
||||||
fmt.Sprintf("Here's the output so far:\n%s", stdout.String()))
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
p.b.Send(c, bot.Message, message.Channel, stdout.String())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
Loading…
Reference in New Issue