mirror of https://github.com/velour/catbase.git
Compare commits
4 Commits
ff4b541c01
...
9b5d39fdc7
Author | SHA1 | Date |
---|---|---|
Chris Sexton | 9b5d39fdc7 | |
Chris Sexton | 75a12ca9a5 | |
Chris Sexton | 0e5f7eb2d5 | |
Chris Sexton | aad4ecf143 |
|
@ -54,6 +54,4 @@ ENV TZ America/New_York
|
||||||
RUN git clone https://github.com/chrissexton/rank-amateur-cowsay.git cowsay && cd cowsay && ./install.sh
|
RUN git clone https://github.com/chrissexton/rank-amateur-cowsay.git cowsay && cd cowsay && ./install.sh
|
||||||
RUN cd $SRC_DIR; go get ./...; go build -o /app/catbase
|
RUN cd $SRC_DIR; go get ./...; go build -o /app/catbase
|
||||||
|
|
||||||
RUN git clone https://gitlab.com/DavidGriffith/frotz.git frotz && cd frotz && make dfrotz && cp dfrotz /app
|
|
||||||
|
|
||||||
ENTRYPOINT ["/app/catbase", "-db=/app/var/catbase.db", "-debug"]
|
ENTRYPOINT ["/app/catbase", "-db=/app/var/catbase.db", "-debug"]
|
||||||
|
|
34
bot/bot.go
34
bot/bot.go
|
@ -230,16 +230,40 @@ func (b *bot) RegisterFilter(name string, f func(string) string) {
|
||||||
b.filters[name] = f
|
b.filters[name] = f
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register a callback
|
// RegisterRegex does what register does, but with a matcher
|
||||||
func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
|
func (b *bot) RegisterRegex(p Plugin, kind Kind, r *regexp.Regexp, resp ResponseHandler) {
|
||||||
t := reflect.TypeOf(p).String()
|
t := reflect.TypeOf(p).String()
|
||||||
if _, ok := b.callbacks[t]; !ok {
|
if _, ok := b.callbacks[t]; !ok {
|
||||||
b.callbacks[t] = make(map[Kind][]Callback)
|
b.callbacks[t] = make(map[Kind]map[*regexp.Regexp][]ResponseHandler)
|
||||||
}
|
}
|
||||||
if _, ok := b.callbacks[t][kind]; !ok {
|
if _, ok := b.callbacks[t][kind]; !ok {
|
||||||
b.callbacks[t][kind] = []Callback{}
|
b.callbacks[t][kind] = map[*regexp.Regexp][]ResponseHandler{}
|
||||||
}
|
}
|
||||||
b.callbacks[t][kind] = append(b.callbacks[t][kind], cb)
|
if _, ok := b.callbacks[t][kind][r]; !ok {
|
||||||
|
b.callbacks[t][kind][r] = []ResponseHandler{}
|
||||||
|
}
|
||||||
|
b.callbacks[t][kind][r] = append(b.callbacks[t][kind][r], resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterRegexCmd is a shortcut to filter non-command messages from a registration
|
||||||
|
func (b *bot) RegisterRegexCmd(p Plugin, kind Kind, r *regexp.Regexp, resp ResponseHandler) {
|
||||||
|
newResp := func(req Request) bool {
|
||||||
|
if !req.Msg.Command {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return resp(req)
|
||||||
|
}
|
||||||
|
b.RegisterRegex(p, kind, r, newResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a callback
|
||||||
|
// This function should be considered deprecated.
|
||||||
|
func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
|
||||||
|
r := regexp.MustCompile(`.*`)
|
||||||
|
resp := func(r Request) bool {
|
||||||
|
return cb(r.Conn, r.Kind, r.Msg, r.Args...)
|
||||||
|
}
|
||||||
|
b.RegisterRegex(p, kind, r, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bot) RegisterWeb(root, name string) {
|
func (b *bot) RegisterWeb(root, name string) {
|
||||||
|
|
|
@ -41,13 +41,36 @@ RET:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseValues(r *regexp.Regexp, body string) RegexValues {
|
||||||
|
out := RegexValues{}
|
||||||
|
subs := r.FindStringSubmatch(body)
|
||||||
|
if len(subs) == 0 {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
for i, n := range r.SubexpNames() {
|
||||||
|
out[n] = subs[i]
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
|
func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool {
|
||||||
t := reflect.TypeOf(plugin).String()
|
t := reflect.TypeOf(plugin).String()
|
||||||
for _, cb := range b.callbacks[t][evt] {
|
for r, cbs := range b.callbacks[t][evt] {
|
||||||
if cb(conn, evt, message, args...) {
|
if r.MatchString(message.Body) {
|
||||||
|
for _, cb := range cbs {
|
||||||
|
resp := Request{
|
||||||
|
Conn: conn,
|
||||||
|
Kind: evt,
|
||||||
|
Msg: message,
|
||||||
|
Values: parseValues(r, message.Body),
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
if cb(resp) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
|
@ -46,9 +48,20 @@ type ImageAttachment struct {
|
||||||
Height int
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Conn Connector
|
||||||
|
Kind Kind
|
||||||
|
Msg msg.Message
|
||||||
|
Values RegexValues
|
||||||
|
Args []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
type Kind int
|
type Kind int
|
||||||
type Callback func(Connector, Kind, msg.Message, ...interface{}) bool
|
type Callback func(Connector, Kind, msg.Message, ...interface{}) bool
|
||||||
type CallbackMap map[string]map[Kind][]Callback
|
type ResponseHandler func(Request) bool
|
||||||
|
type CallbackMap map[string]map[Kind]map[*regexp.Regexp][]ResponseHandler
|
||||||
|
|
||||||
|
type RegexValues map[string]string
|
||||||
|
|
||||||
// b interface serves to allow mocking of the actual bot
|
// b interface serves to allow mocking of the actual bot
|
||||||
type Bot interface {
|
type Bot interface {
|
||||||
|
@ -77,6 +90,14 @@ type Bot interface {
|
||||||
// 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
|
||||||
|
|
||||||
|
// Register a plugin callback
|
||||||
|
// Kind will be matched to the event for the callback
|
||||||
|
RegisterRegex(Plugin, Kind, *regexp.Regexp, ResponseHandler)
|
||||||
|
|
||||||
|
// Register a plugin callback filtering non-commands out
|
||||||
|
// Kind will be matched to the event for the callback
|
||||||
|
RegisterRegexCmd(Plugin, Kind, *regexp.Regexp, ResponseHandler)
|
||||||
|
|
||||||
// Register a plugin callback
|
// Register a plugin callback
|
||||||
// Kind will be matched to the event for the callback
|
// Kind will be matched to the event for the callback
|
||||||
Register(Plugin, Kind, Callback)
|
Register(Plugin, Kind, Callback)
|
||||||
|
|
|
@ -5,6 +5,7 @@ package bot
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, er
|
||||||
}
|
}
|
||||||
func (mb *MockBot) AddPlugin(f Plugin) {}
|
func (mb *MockBot) AddPlugin(f Plugin) {}
|
||||||
func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {}
|
func (mb *MockBot) Register(p Plugin, kind Kind, cb Callback) {}
|
||||||
|
func (mb *MockBot) RegisterRegex(p Plugin, kind Kind, r *regexp.Regexp, h ResponseHandler) {}
|
||||||
|
func (mb *MockBot) RegisterRegexCmd(p Plugin, kind Kind, r *regexp.Regexp, h ResponseHandler) {}
|
||||||
func (mb *MockBot) RegisterWeb(_, _ string) {}
|
func (mb *MockBot) RegisterWeb(_, _ string) {}
|
||||||
func (mb *MockBot) GetWebNavigation() []EndPoint { return nil }
|
func (mb *MockBot) GetWebNavigation() []EndPoint { return nil }
|
||||||
func (mb *MockBot) Receive(c Connector, kind Kind, msg msg.Message, args ...interface{}) bool {
|
func (mb *MockBot) Receive(c Connector, kind Kind, msg msg.Message, args ...interface{}) bool {
|
||||||
|
|
2
main.go
2
main.go
|
@ -59,7 +59,6 @@ import (
|
||||||
"github.com/velour/catbase/plugins/tldr"
|
"github.com/velour/catbase/plugins/tldr"
|
||||||
"github.com/velour/catbase/plugins/twitch"
|
"github.com/velour/catbase/plugins/twitch"
|
||||||
"github.com/velour/catbase/plugins/your"
|
"github.com/velour/catbase/plugins/your"
|
||||||
"github.com/velour/catbase/plugins/zork"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -133,7 +132,6 @@ func main() {
|
||||||
b.AddPlugin(goals.New(b))
|
b.AddPlugin(goals.New(b))
|
||||||
b.AddPlugin(reminder.New(b))
|
b.AddPlugin(reminder.New(b))
|
||||||
b.AddPlugin(babbler.New(b))
|
b.AddPlugin(babbler.New(b))
|
||||||
b.AddPlugin(zork.New(b))
|
|
||||||
b.AddPlugin(rss.New(b))
|
b.AddPlugin(rss.New(b))
|
||||||
b.AddPlugin(reaction.New(b))
|
b.AddPlugin(reaction.New(b))
|
||||||
b.AddPlugin(twitch.New(b))
|
b.AddPlugin(twitch.New(b))
|
||||||
|
|
|
@ -2,13 +2,14 @@ package newsbid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
"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/plugins/newsbid/webshit"
|
"github.com/velour/catbase/plugins/newsbid/webshit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -30,27 +31,42 @@ func New(b bot.Bot) *NewsBid {
|
||||||
db: b.DB(),
|
db: b.DB(),
|
||||||
ws: ws,
|
ws: ws,
|
||||||
}
|
}
|
||||||
p.bot.Register(p, bot.Message, p.message)
|
|
||||||
|
p.bot.RegisterRegexCmd(p, bot.Message, balanceRegex, p.balanceCmd)
|
||||||
|
p.bot.RegisterRegexCmd(p, bot.Message, bidsRegex, p.bidsCmd)
|
||||||
|
p.bot.RegisterRegexCmd(p, bot.Message, scoresRegex, p.scoresCmd)
|
||||||
|
p.bot.RegisterRegexCmd(p, bot.Message, bidRegex, p.bidCmd)
|
||||||
|
p.bot.RegisterRegexCmd(p, bot.Message, checkRegex, p.checkCmd)
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NewsBid) message(conn bot.Connector, k bot.Kind, message msg.Message, args ...interface{}) bool {
|
var balanceRegex = regexp.MustCompile(`(?i)^balance$`)
|
||||||
body := strings.ToLower(message.Body)
|
var bidsRegex = regexp.MustCompile(`(?i)^bids$`)
|
||||||
ch := message.Channel
|
var scoresRegex = regexp.MustCompile(`(?i)^scores$`)
|
||||||
if message.Command && body == "balance" {
|
var bidRegex = regexp.MustCompile(`(?i)^bid (?P<amount>\S+) (?P<url>)\S+$`)
|
||||||
bal := p.ws.GetBalance(message.User.Name)
|
var checkRegex = regexp.MustCompile(`(?i)^check ngate$`)
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("%s, your current balance is %d.",
|
|
||||||
message.User.Name, bal))
|
func (p *NewsBid) balanceCmd(r bot.Request) bool {
|
||||||
return true
|
if !r.Msg.Command {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if message.Command && body == "bids" {
|
|
||||||
|
bal := p.ws.GetBalance(r.Msg.User.Name)
|
||||||
|
p.bot.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("%s, your current balance is %d.",
|
||||||
|
r.Msg.User.Name, bal))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *NewsBid) bidsCmd(r bot.Request) bool {
|
||||||
|
ch := r.Msg.Channel
|
||||||
bids, err := p.ws.GetAllBids()
|
bids, err := p.ws.GetAllBids()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err))
|
p.bot.Send(r.Conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(bids) == 0 {
|
if len(bids) == 0 {
|
||||||
p.bot.Send(conn, bot.Message, ch, "No bids to report.")
|
p.bot.Send(r.Conn, bot.Message, ch, "No bids to report.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
sort.Slice(bids, func(i, j int) bool {
|
sort.Slice(bids, func(i, j int) bool {
|
||||||
|
@ -64,17 +80,20 @@ func (p *NewsBid) message(conn bot.Connector, k bot.Kind, message msg.Message, a
|
||||||
hnURL := fmt.Sprintf("https://news.ycombinator.com/item?id=%d", b.HNID)
|
hnURL := fmt.Sprintf("https://news.ycombinator.com/item?id=%d", b.HNID)
|
||||||
out += fmt.Sprintf("• %s bid %s <%s|%s> (<%s|Comments>)\n", b.User, b.BidStr, b.URL, b.Title, hnURL)
|
out += fmt.Sprintf("• %s bid %s <%s|%s> (<%s|Comments>)\n", b.User, b.BidStr, b.URL, b.Title, hnURL)
|
||||||
}
|
}
|
||||||
p.bot.Send(conn, bot.Message, ch, out)
|
p.bot.Send(r.Conn, bot.Message, ch, out)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if message.Command && body == "scores" {
|
|
||||||
|
func (p *NewsBid) scoresCmd(r bot.Request) bool {
|
||||||
|
|
||||||
|
ch := r.Msg.Channel
|
||||||
bals, err := p.ws.GetAllBalances()
|
bals, err := p.ws.GetAllBalances()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err))
|
p.bot.Send(r.Conn, bot.Message, ch, fmt.Sprintf("Error getting bids: %s", err))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(bals) == 0 {
|
if len(bals) == 0 {
|
||||||
p.bot.Send(conn, bot.Message, ch, "No balances to report.")
|
p.bot.Send(r.Conn, bot.Message, ch, "No balances to report.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
out := "NGate balances:\n"
|
out := "NGate balances:\n"
|
||||||
|
@ -82,38 +101,41 @@ func (p *NewsBid) message(conn bot.Connector, k bot.Kind, message msg.Message, a
|
||||||
for _, b := range bals {
|
for _, b := range bals {
|
||||||
out += fmt.Sprintf("%s has a total score of %d with %d left to bid this session\n", b.User, b.Score, b.Balance)
|
out += fmt.Sprintf("%s has a total score of %d with %d left to bid this session\n", b.User, b.Score, b.Balance)
|
||||||
}
|
}
|
||||||
p.bot.Send(conn, bot.Message, ch, out)
|
p.bot.Send(r.Conn, bot.Message, ch, out)
|
||||||
return true
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *NewsBid) bidCmd(r bot.Request) bool {
|
||||||
|
body := strings.ToLower(r.Msg.Body)
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
conn := r.Conn
|
||||||
|
|
||||||
|
log.Debug().Interface("request", r).Msg("bid request")
|
||||||
|
|
||||||
}
|
|
||||||
if message.Command && strings.HasPrefix(body, "bid") {
|
|
||||||
parts := strings.Fields(body)
|
parts := strings.Fields(body)
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
p.bot.Send(conn, bot.Message, ch, "You must bid with an amount and a URL.")
|
p.bot.Send(conn, bot.Message, ch, "You must bid with an amount and a URL.")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
amount, _ := strconv.Atoi(parts[1])
|
amount, _ := strconv.Atoi(parts[1])
|
||||||
url := parts[2]
|
url := parts[2]
|
||||||
if bid, err := p.ws.Bid(message.User.Name, amount, parts[1], url); err != nil {
|
if bid, err := p.ws.Bid(r.Msg.User.Name, amount, parts[1], url); err != nil {
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error placing bid: %s", err))
|
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error placing bid: %s", err))
|
||||||
} else {
|
} else {
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Your bid has been placed on %s", bid.Title))
|
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Your bid has been placed on %s", bid.Title))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
if message.Command && body == "check ngate" {
|
|
||||||
p.check(conn, ch)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NewsBid) check(conn bot.Connector, ch string) {
|
func (p *NewsBid) checkCmd(r bot.Request) bool {
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
conn := r.Conn
|
||||||
last := p.bot.Config().GetInt64("newsbid.lastprocessed", 0)
|
last := p.bot.Config().GetInt64("newsbid.lastprocessed", 0)
|
||||||
wr, pubTime, err := p.ws.Check(last)
|
wr, pubTime, err := p.ws.Check(last)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error checking ngate: %s", err))
|
p.bot.Send(conn, bot.Message, ch, fmt.Sprintf("Error checking ngate: %s", err))
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
p.bot.Config().Set("newsbid.lastprocessed", strconv.FormatInt(pubTime, 10))
|
p.bot.Config().Set("newsbid.lastprocessed", strconv.FormatInt(pubTime, 10))
|
||||||
|
|
||||||
|
@ -147,4 +169,5 @@ func (p *NewsBid) check(conn bot.Connector, ch string) {
|
||||||
}
|
}
|
||||||
p.bot.Send(conn, bot.Message, ch, msg)
|
p.bot.Send(conn, bot.Message, ch, msg)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,12 @@ func New(b bot.Bot) *SMSPlugin {
|
||||||
}
|
}
|
||||||
plugin.setup()
|
plugin.setup()
|
||||||
plugin.registerWeb()
|
plugin.registerWeb()
|
||||||
b.Register(plugin, bot.Message, plugin.message)
|
|
||||||
|
b.RegisterRegex(plugin, bot.Message, deleteRegex, plugin.deleteCmd)
|
||||||
|
b.RegisterRegex(plugin, bot.Message, sendRegex, plugin.sendCmd)
|
||||||
|
b.RegisterRegex(plugin, bot.Message, regSomeoneRegex, plugin.registerOtherCmd)
|
||||||
|
b.RegisterRegex(plugin, bot.Message, regSelfRegex, plugin.registerSelfCmd)
|
||||||
|
|
||||||
b.Register(plugin, bot.Help, plugin.help)
|
b.Register(plugin, bot.Help, plugin.help)
|
||||||
return plugin
|
return plugin
|
||||||
}
|
}
|
||||||
|
@ -46,9 +51,10 @@ func (p *SMSPlugin) checkNumber(num string) (string, error) {
|
||||||
return num, nil
|
return num, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var regRegex = regexp.MustCompile(`(?i)my sms number is (\d+)`)
|
var regSelfRegex = regexp.MustCompile(`(?i)my sms number is (?P<number>\d+)`)
|
||||||
var reg2Regex = regexp.MustCompile(`(?i)register sms for (?P<name>\S+) (\d+)`)
|
var regSomeoneRegex = regexp.MustCompile(`(?i)register sms for (?P<name>\S+) (?P<number>\d+)`)
|
||||||
var sendRegex = regexp.MustCompile(`(?i)send sms to (?P<name>\S+) (?P<body>.+)`)
|
var sendRegex = regexp.MustCompile(`(?i)send sms to (?P<name>\S+) (?P<body>.+)`)
|
||||||
|
var deleteRegex = regexp.MustCompile(`(?i)delete my sms$`)
|
||||||
|
|
||||||
// Send will send a text to a registered user, who
|
// Send will send a text to a registered user, who
|
||||||
func (p *SMSPlugin) Send(who, message string) error {
|
func (p *SMSPlugin) Send(who, message string) error {
|
||||||
|
@ -59,69 +65,17 @@ func (p *SMSPlugin) Send(who, message string) error {
|
||||||
sid := p.c.Get("TWILIOSID", "")
|
sid := p.c.Get("TWILIOSID", "")
|
||||||
token := p.c.Get("TWILIOTOKEN", "")
|
token := p.c.Get("TWILIOTOKEN", "")
|
||||||
myNum := p.c.Get("TWILIONUMBER", "")
|
myNum := p.c.Get("TWILIONUMBER", "")
|
||||||
|
|
||||||
|
if sid == "" || token == "" || myNum == "" {
|
||||||
|
return fmt.Errorf("this bot is not configured for Twilio")
|
||||||
|
}
|
||||||
|
|
||||||
client := twilio.NewClient(sid, token, nil)
|
client := twilio.NewClient(sid, token, nil)
|
||||||
|
|
||||||
_, err = client.Messages.SendMessage(myNum, num, message, nil)
|
_, err = client.Messages.SendMessage(myNum, num, message, nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SMSPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
||||||
ch, chName := message.Channel, message.ChannelName
|
|
||||||
body := strings.TrimSpace(message.Body)
|
|
||||||
who := message.User.Name
|
|
||||||
|
|
||||||
log.Debug().Bytes("body", []byte(body)).Msgf("body: '%s', match: %v, %#v", body, sendRegex.MatchString(body), sendRegex.FindStringSubmatch(body))
|
|
||||||
|
|
||||||
if strings.ToLower(body) == "delete my sms" {
|
|
||||||
if err := p.delete(who); err != nil {
|
|
||||||
p.b.Send(c, bot.Message, ch, "Something went wrong.")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
p.b.Send(c, bot.Message, ch, "Okay.")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if sendRegex.MatchString(body) {
|
|
||||||
subs := sendRegex.FindStringSubmatch(body)
|
|
||||||
if len(subs) != 3 {
|
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message. Your request makes no sense."))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
user, body := subs[1], fmt.Sprintf("#%s: %s", chName, subs[2])
|
|
||||||
err := p.Send(user, body)
|
|
||||||
if err != nil {
|
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
p.b.Send(c, bot.Message, ch, "I sent a message to them.")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if reg2Regex.MatchString(body) {
|
|
||||||
subs := reg2Regex.FindStringSubmatch(body)
|
|
||||||
if subs == nil || len(subs) != 3 {
|
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("if you're trying to register somebody, give me a "+
|
|
||||||
"message of the format: `%s`", reg2Regex))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.reg(c, ch, subs[1], subs[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
if regRegex.MatchString(body) {
|
|
||||||
subs := regRegex.FindStringSubmatch(body)
|
|
||||||
if subs == nil || len(subs) != 2 {
|
|
||||||
p.b.Send(c, bot.Message, ch, fmt.Sprintf("if you're trying to register a number, give me a "+
|
|
||||||
"message of the format: `%s`", regRegex))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.reg(c, ch, who, subs[1])
|
|
||||||
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SMSPlugin) reg(c bot.Connector, ch, who, num string) bool {
|
func (p *SMSPlugin) reg(c bot.Connector, ch, who, num string) bool {
|
||||||
num, err := p.checkNumber(num)
|
num, err := p.checkNumber(num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -152,8 +106,8 @@ func (p *SMSPlugin) reg(c bot.Connector, ch, who, num string) bool {
|
||||||
|
|
||||||
func (p *SMSPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
func (p *SMSPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
||||||
ch := message.Channel
|
ch := message.Channel
|
||||||
m := fmt.Sprintf("You can register your number with: `%s`", regRegex)
|
m := fmt.Sprintf("You can register your number with: `%s`", regSelfRegex)
|
||||||
m += fmt.Sprintf("\nYou can register somebody else with: `%s`", reg2Regex)
|
m += fmt.Sprintf("\nYou can register somebody else with: `%s`", regSomeoneRegex)
|
||||||
m += fmt.Sprintf("\nYou can send a message to a user with: `%s`", sendRegex)
|
m += fmt.Sprintf("\nYou can send a message to a user with: `%s`", sendRegex)
|
||||||
m += "\nYou can deregister with: `delete my sms`"
|
m += "\nYou can deregister with: `delete my sms`"
|
||||||
m += fmt.Sprintf("\nAll messages sent to %s will come to the channel.",
|
m += fmt.Sprintf("\nAll messages sent to %s will come to the channel.",
|
||||||
|
@ -244,3 +198,55 @@ func (p *SMSPlugin) setup() {
|
||||||
log.Fatal().Err(err).Msgf("could not create sms table")
|
log.Fatal().Err(err).Msgf("could not create sms table")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) deleteCmd(r bot.Request) bool {
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
if err := p.delete(r.Msg.User.Name); err != nil {
|
||||||
|
p.b.Send(r.Conn, bot.Message, ch, "Something went wrong.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.b.Send(r.Conn, bot.Message, ch, "Okay.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) sendCmd(r bot.Request) bool {
|
||||||
|
if r.Msg.User.Name == p.c.Get("nick", "") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
chName := r.Msg.ChannelName
|
||||||
|
c := r.Conn
|
||||||
|
if r.Values["name"] == "" || r.Values["body"] == "" {
|
||||||
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message. Your request makes no sense."))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
user, body := r.Values["name"], fmt.Sprintf("#%s: %s", chName, r.Values["body"])
|
||||||
|
err := p.Send(user, body)
|
||||||
|
if err != nil {
|
||||||
|
p.b.Send(c, bot.Message, ch, fmt.Sprintf("I didn't send the message, %s", err))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.b.Send(c, bot.Message, ch, "I sent a message to them.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) registerOtherCmd(r bot.Request) bool {
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
if r.Values["name"] == "" || r.Values["number"] == "" {
|
||||||
|
p.b.Send(r.Conn, bot.Message, ch, fmt.Sprintf("if you're trying to register somebody, give me a "+
|
||||||
|
"message of the format: `%s`", regSomeoneRegex))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.reg(r.Conn, ch, r.Values["name"], r.Values["number"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SMSPlugin) registerSelfCmd(r bot.Request) bool {
|
||||||
|
ch := r.Msg.Channel
|
||||||
|
who := r.Msg.User.Name
|
||||||
|
if r.Values["number"] == "" {
|
||||||
|
p.b.Send(r.Conn, bot.Message, ch, fmt.Sprintf("if you're trying to register a number, give me a "+
|
||||||
|
"message of the format: `%s`", regSelfRegex))
|
||||||
|
}
|
||||||
|
return p.reg(r.Conn, ch, who, r.Values["number"])
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
|
@ -1,128 +0,0 @@
|
||||||
// © 2016 the CatBase Authors under the WTFPL license. See AUTHORS for the list of authors.
|
|
||||||
|
|
||||||
// Package zork implements a zork plugin for catbase.
|
|
||||||
package zork
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"go/build"
|
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"github.com/velour/catbase/bot"
|
|
||||||
"github.com/velour/catbase/bot/msg"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ZorkPlugin is a catbase plugin for playing zork.
|
|
||||||
type ZorkPlugin struct {
|
|
||||||
bot bot.Bot
|
|
||||||
sync.Mutex
|
|
||||||
// zorks is a map from channels to their corresponding zork instances.
|
|
||||||
zorks map[string]io.WriteCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(b bot.Bot) bot.Plugin {
|
|
||||||
z := &ZorkPlugin{
|
|
||||||
bot: b,
|
|
||||||
zorks: make(map[string]io.WriteCloser),
|
|
||||||
}
|
|
||||||
b.Register(z, bot.Message, z.message)
|
|
||||||
b.Register(z, bot.Help, z.help)
|
|
||||||
return z
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ZorkPlugin) runZork(c bot.Connector, ch string) error {
|
|
||||||
const importString = "github.com/velour/catbase/plugins/zork"
|
|
||||||
pkgPath := ""
|
|
||||||
pkg, err := build.Import(importString, "", build.FindOnly)
|
|
||||||
if err == nil {
|
|
||||||
pkgPath = pkg.Dir
|
|
||||||
}
|
|
||||||
zorkPath := p.bot.Config().GetString("zork.path", pkgPath)
|
|
||||||
zorkdat := filepath.Join(zorkPath, "ZORK1.DAT")
|
|
||||||
zorkFlags := p.bot.Config().GetArray("zork.args", []string{"-p"})
|
|
||||||
zorkExec := p.bot.Config().GetString("zork.binary", "frotz")
|
|
||||||
zorkFlags = append(zorkFlags, zorkdat)
|
|
||||||
cmd := exec.Command(zorkExec, zorkFlags...)
|
|
||||||
|
|
||||||
var r io.ReadCloser
|
|
||||||
r, cmd.Stdout = io.Pipe()
|
|
||||||
cmd.Stderr = cmd.Stdout
|
|
||||||
|
|
||||||
var w io.WriteCloser
|
|
||||||
cmd.Stdin, w = io.Pipe()
|
|
||||||
|
|
||||||
log.Info().Msgf("zork running %v", cmd)
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
w.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
defer r.Close()
|
|
||||||
s := bufio.NewScanner(r)
|
|
||||||
// Scan until the next prompt.
|
|
||||||
s.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
||||||
if atEOF && len(data) == 0 {
|
|
||||||
return 0, nil, nil
|
|
||||||
}
|
|
||||||
if i := bytes.Index(data, []byte{'\n', '>'}); i > 0 {
|
|
||||||
return i + 1, data[:i], nil
|
|
||||||
}
|
|
||||||
if atEOF {
|
|
||||||
return len(data), data, nil
|
|
||||||
}
|
|
||||||
return 0, nil, nil
|
|
||||||
})
|
|
||||||
for s.Scan() {
|
|
||||||
// Remove > and quote the whole thing.
|
|
||||||
m := strings.Replace(s.Text(), ">", "", -1)
|
|
||||||
m = strings.Replace(m, "\n", "\n>", -1)
|
|
||||||
m = ">" + m + "\n"
|
|
||||||
p.bot.Send(c, bot.Message, ch, m)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
log.Error().Err(err).Msg("zork exited")
|
|
||||||
}
|
|
||||||
p.Lock()
|
|
||||||
p.zorks[ch] = nil
|
|
||||||
p.Unlock()
|
|
||||||
}()
|
|
||||||
log.Info().Msgf("zork is running in %s\n", ch)
|
|
||||||
p.zorks[ch] = w
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ZorkPlugin) message(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
||||||
m := strings.ToLower(message.Body)
|
|
||||||
log.Debug().Msgf("got message [%s]", m)
|
|
||||||
if ts := strings.Fields(m); len(ts) < 1 || ts[0] != "zork" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m = strings.TrimSpace(strings.TrimPrefix(m, "zork"))
|
|
||||||
ch := message.Channel
|
|
||||||
|
|
||||||
p.Lock()
|
|
||||||
defer p.Unlock()
|
|
||||||
if p.zorks[ch] == nil {
|
|
||||||
if err := p.runZork(c, ch); err != nil {
|
|
||||||
p.bot.Send(c, bot.Message, ch, "failed to run zork: "+err.Error())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debug().Msgf("zorking, [%s]", m)
|
|
||||||
io.WriteString(p.zorks[ch], m+"\n")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ZorkPlugin) help(c bot.Connector, kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
||||||
p.bot.Send(c, bot.Message, message.Channel, "Play zork using 'zork <zork command>'.")
|
|
||||||
return true
|
|
||||||
}
|
|
Loading…
Reference in New Issue