Switch all the plugins to use the new Process function.

Expand sms to run Process for each plugin, add a "homestead" plugin while here!
\o/
This commit is contained in:
Aaron Bieber 2021-04-01 16:15:25 -06:00
parent 5e0a3c2e12
commit d6673169be
25 changed files with 344 additions and 178 deletions

View File

@ -33,11 +33,16 @@ func (h *Beat) SetStore(_ PluginStore) {}
// RespondText to beat request events // RespondText to beat request events
func (h *Beat) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *Beat) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
return SendText(c, ev.RoomID, h.Process("", ""))
}
// Process does the heavy lifting of calculating .beat
func (h *Beat) Process(from, msg string) string {
n := time.Now() n := time.Now()
utc1 := n.Unix() + 3600 utc1 := n.Unix() + 3600
r := utc1 % 86400 r := utc1 % 86400
bt := float32(r) / 86.4 bt := float32(r) / 86.4
return SendText(c, ev.RoomID, fmt.Sprintf("@%03d", int32(bt))) return fmt.Sprintf("@%03d", int32(bt))
} }
// Name beat // Name beat

View File

@ -115,9 +115,9 @@ func (h *Beer) pretty(b BeerResp, random bool) string {
// SetStore we don't need a store here. // SetStore we don't need a store here.
func (h *Beer) SetStore(_ PluginStore) {} func (h *Beer) SetStore(_ PluginStore) {}
// RespondText to looking up of beer requests func (h *Beer) Process(from, msg string) string {
func (h *Beer) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { beer := h.fix(msg)
beer := h.fix(post) resp := "¯\\_(ツ)_/¯"
if beer != "" { if beer != "" {
var beers = &BeerResp{} var beers = &BeerResp{}
u := fmt.Sprintf("%s%s", u := fmt.Sprintf("%s%s",
@ -131,19 +131,23 @@ func (h *Beer) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post strin
} }
err := req.DoJSON() err := req.DoJSON()
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look for beer. (%s)", ev.Sender, err)) return fmt.Sprintf("sorry %s, I can't look for beer. (%s)", from, err)
} }
switch { switch {
case beers.Nhits == 0:
return SendText(c, ev.RoomID, "¯\\_(ツ)_/¯")
case beers.Nhits == 1: case beers.Nhits == 1:
return SendText(c, ev.RoomID, h.pretty(*beers, false)) resp = h.pretty(*beers, false)
case beers.Nhits > 1: case beers.Nhits > 1:
return SendText(c, ev.RoomID, fmt.Sprintf("Found %d beers, here is a random one:\n%s", beers.Nhits, h.pretty(*beers, true))) resp = fmt.Sprintf("Found %d beers, here is a random one:\n%s", beers.Nhits, h.pretty(*beers, true))
} }
} }
return nil return resp
}
// RespondText to looking up of beer requests
func (h *Beer) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name Beer! // Name Beer!

View File

@ -28,7 +28,11 @@ func (h *BotSnack) Match(_, msg string) bool {
return re.MatchString(msg) return re.MatchString(msg)
} }
func (h *BotSnack) resp() string { // SetStore we don't need a store, so just return
func (h *BotSnack) SetStore(_ PluginStore) {}
// Process does the heavy lifting
func (h *BotSnack) Process(from, msg string) string {
a := []string{ a := []string{
"omm nom nom nom", "omm nom nom nom",
"*puke*", "*puke*",
@ -38,17 +42,13 @@ func (h *BotSnack) resp() string {
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
return a[rand.Intn(len(a))] return a[rand.Intn(len(a))]
} }
// SetStore we don't need a store, so just return
func (h *BotSnack) SetStore(_ PluginStore) {}
// RespondText to botsnack events // RespondText to botsnack events
func (h *BotSnack) RespondText(c *gomatrix.Client, ev *gomatrix.Event, user, post string) error { func (h *BotSnack) RespondText(c *gomatrix.Client, ev *gomatrix.Event, user, post string) error {
u := NameRE.ReplaceAllString(user, "$1") u := NameRE.ReplaceAllString(user, "$1")
if ToMe(u, post) { if ToMe(u, post) {
return SendText(c, ev.RoomID, h.resp()) return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
return nil return nil
} }

View File

@ -43,9 +43,9 @@ func (h *Covid) Match(_, msg string) bool {
// SetStore we don't need a store here. // SetStore we don't need a store here.
func (h *Covid) SetStore(_ PluginStore) {} func (h *Covid) SetStore(_ PluginStore) {}
// RespondText to looking up of beer requests // Process does the heavy lifting
func (h *Covid) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (h *Covid) Process(from, msg string) string {
state := h.fix(post) state := h.fix(msg)
if state != "" { if state != "" {
var states = make(map[string]State) var states = make(map[string]State)
req := HTTPRequest{ req := HTTPRequest{
@ -66,9 +66,15 @@ func (h *Covid) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post stri
state = i state = i
} }
} }
return SendMD(c, ev.RoomID, fmt.Sprintf("_%s_: confirmed cases: **%d**, recovered: _%d_, deaths: _%d_", state, s.Confirmed, s.Recovered, s.Deaths)) return fmt.Sprintf("_%s_: confirmed cases: **%d**, recovered: _%d_, deaths: _%d_", state, s.Confirmed, s.Recovered, s.Deaths)
} }
return nil return fmt.Sprintf("invalid state: %q", state)
}
// RespondText to looking up of beer requests
func (h *Covid) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendMD(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name Covid! // Name Covid!

View File

@ -86,8 +86,7 @@ func (p *DMR) query(msg string) string {
return re.ReplaceAllString(msg, "$3") return re.ReplaceAllString(msg, "$3")
} }
// RespondText to looking up of DMR info func (p *DMR) Process(from, post string) string {
func (p *DMR) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
mode := p.mode(post) mode := p.mode(post)
param := p.param(post) param := p.param(post)
search := p.query(post) search := p.query(post)
@ -111,11 +110,11 @@ func (p *DMR) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
req.ResBody = res req.ResBody = res
err := req.DoJSON() err := req.DoJSON()
if err != nil { if err != nil {
return err return err.Error()
} }
if res.Count == 0 { if res.Count == 0 {
return SendMD(c, ev.RoomID, fmt.Sprintf("nothing found for '%s'", params.Encode())) return fmt.Sprintf("nothing found for '%s'", params.Encode())
} }
var s []string var s []string
@ -124,18 +123,18 @@ func (p *DMR) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
s = append(s, fmt.Sprintf("**Frequency**: %s", res.Results[0].Frequency)) s = append(s, fmt.Sprintf("**Frequency**: %s", res.Results[0].Frequency))
s = append(s, fmt.Sprintf("**Offset**: %s", res.Results[0].Offset)) s = append(s, fmt.Sprintf("**Offset**: %s", res.Results[0].Offset))
return SendMD(c, ev.RoomID, strings.Join(s, ", ")) return strings.Join(s, ", ")
case "user": case "user":
var res = &DMRUser{} var res = &DMRUser{}
req.ResBody = res req.ResBody = res
err := req.DoJSON() err := req.DoJSON()
if err != nil { if err != nil {
return err return err.Error()
} }
if res.Count == 0 { if res.Count == 0 {
return SendMD(c, ev.RoomID, fmt.Sprintf("nothing found for '%s'", params.Encode())) return fmt.Sprintf("nothing found for '%s'", params.Encode())
} }
var s []string var s []string
@ -143,9 +142,14 @@ func (p *DMR) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
s = append(s, fmt.Sprintf("**ID**: %d", res.Results[0].ID)) s = append(s, fmt.Sprintf("**ID**: %d", res.Results[0].ID))
s = append(s, fmt.Sprintf("**Callsign**: %s", res.Results[0].Callsign)) s = append(s, fmt.Sprintf("**Callsign**: %s", res.Results[0].Callsign))
return SendMD(c, ev.RoomID, strings.Join(s, ", ")) return strings.Join(s, ", ")
} }
return nil return fmt.Sprintf("invalid mode: %q", mode)
}
// RespondText to looking up of DMR info
func (p *DMR) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendMD(c, ev.RoomID, p.Process(ev.Sender, post))
} }
// Name DMR! // Name DMR!

View File

@ -50,13 +50,12 @@ func (h *Feder) Match(_, msg string) bool {
// SetStore we don't need a store here. // SetStore we don't need a store here.
func (h *Feder) SetStore(_ PluginStore) {} func (h *Feder) SetStore(_ PluginStore) {}
// RespondText to looking up of federation check requests func (h *Feder) Process(from, post string) string {
func (h *Feder) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
homeServer := h.fix(post) homeServer := h.fix(post)
if homeServer != "" { if homeServer != "" {
u, err := url.Parse(fmt.Sprintf("https://%s", homeServer)) u, err := url.Parse(fmt.Sprintf("https://%s", homeServer))
if err != nil { if err != nil {
return SendText(c, ev.RoomID, "that's not a real host name.") return fmt.Sprintf("that's not a real host name: %q", homeServer)
} }
homeServer = u.Hostname() homeServer = u.Hostname()
@ -76,7 +75,7 @@ func (h *Feder) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post stri
err = req.DoJSON() err = req.DoJSON()
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look up the federation status (%s)", ev.Sender, err)) return fmt.Sprintf("sorry %s, I can't look up the federation status (%s)", from, err)
} }
stat := "broken" stat := "broken"
@ -85,14 +84,17 @@ func (h *Feder) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post stri
} }
if fed.Info.Error != "" { if fed.Info.Error != "" {
return SendText(c, ev.RoomID, fmt.Sprintf("%s seems to be broken, maybe it isn't a homeserver?\n%s", return fmt.Sprintf("%s seems to be broken, maybe it isn't a homeserver?\n%s", homeServer, fed.Info.Error)
homeServer, fed.Info.Error))
} else { } else {
return SendText(c, ev.RoomID, fmt.Sprintf("%s is running %s (%s) and is %s.", return fmt.Sprintf("%s is running %s (%s) and is %s.", homeServer, fed.Info.Name, fed.Info.Version, stat)
homeServer, fed.Info.Name, fed.Info.Version, stat))
} }
} }
return nil return "invalid hostname"
}
// RespondText to looking up of federation check requests
func (h *Feder) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name Feder! // Name Feder!

View File

@ -1,10 +1,11 @@
package plugins package plugins
import ( import (
"github.com/matrix-org/gomatrix"
"math/rand" "math/rand"
"regexp" "regexp"
"time" "time"
"github.com/matrix-org/gomatrix"
) )
// Groan responds to groans. // Groan responds to groans.
@ -30,7 +31,7 @@ func (h *Groan) Match(user, msg string) bool {
return re.MatchString(msg) return re.MatchString(msg)
} }
func (h *Groan) resp() string { func (h *Groan) Process(_, _ string) string {
a := []string{ a := []string{
"Ugh.", "Ugh.",
"ugh", "ugh",
@ -47,7 +48,7 @@ func (h *Groan) resp() string {
// RespondText to groan events // RespondText to groan events
func (h *Groan) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (h *Groan) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.resp()) return SendText(c, ev.RoomID, h.Process("", ""))
} }
// Name returns the name of the Groan plugin // Name returns the name of the Groan plugin

View File

@ -78,8 +78,8 @@ func (h *Ham) pretty(resp *LicenseResp) string {
return strings.Join(s, " ") return strings.Join(s, " ")
} }
// RespondText to looking up of federation check requests // Process does the heavy lifting
func (h *Ham) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (h *Ham) Process(from, post string) string {
call := h.fix(post) call := h.fix(post)
if call != "" { if call != "" {
furl := fmt.Sprintf("http://api.hamdb.org/v1/%s/json/mcchunkie", furl := fmt.Sprintf("http://api.hamdb.org/v1/%s/json/mcchunkie",
@ -96,17 +96,22 @@ func (h *Ham) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
err := req.DoJSON() err := req.DoJSON()
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look things up in ULS (%s)", ev.Sender, err)) return fmt.Sprintf("sorry %s, I can't look things up in ULS (%s)", from, err)
} }
if res.Hamdb.Messages.Status == "OK" { if res.Hamdb.Messages.Status == "OK" {
return SendText(c, ev.RoomID, h.pretty(res)) return h.pretty(res)
} }
return SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look things up in ULS. The response was not OK.", ev.Sender)) return fmt.Sprintf("sorry %s, I can't look things up in ULS. The response was not OK.", from)
} }
return nil return "invalid callsign"
}
// RespondText to looking up of federation check requests
func (h *Ham) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name Ham! // Name Ham!

View File

@ -30,11 +30,15 @@ func (h *Hi) Match(user, msg string) bool {
// SetStore we don't need a store here // SetStore we don't need a store here
func (h *Hi) SetStore(_ PluginStore) {} func (h *Hi) SetStore(_ PluginStore) {}
// RespondText to hi events // Process does the lifting
func (h *Hi) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *Hi) Process(from, post string) string {
s := NameRE.ReplaceAllString(ev.Sender, "$1") s := NameRE.ReplaceAllString(from, "$1")
return fmt.Sprintf("hi %s!", s)
}
return SendText(c, ev.RoomID, fmt.Sprintf("hi %s!", s)) // RespondText to hi events
func (h *Hi) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name hi // Name hi

View File

@ -3,7 +3,6 @@ package plugins
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"time"
"github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrix"
) )
@ -39,24 +38,26 @@ func (h *HighFive) Match(user, msg string) bool {
return ToMe(user, msg) && re.MatchString(msg) return ToMe(user, msg) && re.MatchString(msg)
} }
// RespondText to high five events func (h *HighFive) Process(from, post string) string {
func (h *HighFive) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { s := NameRE.ReplaceAllString(from, "$1")
s := NameRE.ReplaceAllString(ev.Sender, "$1")
rm := regexp.MustCompile(rightFive()) rm := regexp.MustCompile(rightFive())
lm := regexp.MustCompile(leftFive()) lm := regexp.MustCompile(leftFive())
if rm.MatchString(post) { if rm.MatchString(post) {
_ = SendText(c, ev.RoomID, fmt.Sprintf("\\o %s", s)) return fmt.Sprintf("\\o %s", s)
time.Sleep(time.Second * 5)
return SendText(c, ev.RoomID, fmt.Sprintf("now go wash your hands, %s", s))
} }
if lm.MatchString(post) { if lm.MatchString(post) {
_ = SendText(c, ev.RoomID, fmt.Sprintf("%s o/", s)) return fmt.Sprintf("%s o/", s)
time.Sleep(time.Second * 5)
return SendText(c, ev.RoomID, fmt.Sprintf("now go wash your hands, %s", s))
} }
return nil
return "\\o/"
}
// RespondText to high five events
func (h *HighFive) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name returns the name of the HighFive plugin // Name returns the name of the HighFive plugin

113
plugins/homestead.go Normal file
View File

@ -0,0 +1,113 @@
package plugins
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"regexp"
"strconv"
"strings"
"github.com/matrix-org/gomatrix"
)
// HomesteadResp is the json returned from our api
type HomesteadResp struct {
Status string `json:"status"`
Data struct {
Resulttype string `json:"resultType"`
Result []struct {
Metric struct {
Instance string `json:"instance"`
Job string `json:"job"`
Name string `json:"name"`
} `json:"metric"`
Value []interface{} `json:"value"`
} `json:"result"`
} `json:"data"`
}
// Homestead is our plugin type
type Homestead struct {
db PluginStore
}
// SetStore is the setup function for a plugin
func (h *Homestead) SetStore(s PluginStore) {
h.db = s
}
func (h *Homestead) get(loc string) (*HomesteadResp, error) {
u := "https://graph.tapenet.org/pub"
resp, err := http.Get(u)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var w = &HomesteadResp{}
err = json.Unmarshal(body, w)
if err != nil {
return nil, err
}
return w, nil
}
// Descr describes this plugin
func (h *Homestead) Descr() string {
return "Display weather information for the Homestead"
}
// Re is what our weather matches
func (h *Homestead) Re() string {
return `(?i)^home:|^homestead:\s?(\w+)?$`
}
// Match checks for "home: name?" messages
func (h *Homestead) Match(_, msg string) bool {
re := regexp.MustCompile(h.Re())
return re.MatchString(msg)
}
func (h *Homestead) fix(msg string) string {
re := regexp.MustCompile(h.Re())
return re.ReplaceAllString(msg, "$1")
}
func (h *Homestead) Process(from, post string) string {
weather := h.fix(post)
var s []string
wd, err := h.get(weather)
if err != nil {
return fmt.Sprintf("sorry %s, I can't connect to the homestead. %q", from, err)
}
for _, e := range wd.Data.Result {
if temp, err := strconv.ParseFloat(e.Value[1].(string), 64); err == nil {
s = append(s, fmt.Sprintf("%s: %.2fC (%.2fF)", e.Metric.Name, temp, (temp*1.8000)+32.00))
} else {
log.Fatal(err)
}
}
return strings.Join(s, ", ")
}
// RespondText to looking up of weather lookup requests
func (h *Homestead) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
}
// Name Homestead!
func (h *Homestead) Name() string {
return "Homestead"
}

View File

@ -28,7 +28,8 @@ func (h *LoveYou) Match(user, msg string) bool {
return re.MatchString(msg) && ToMe(user, msg) return re.MatchString(msg) && ToMe(user, msg)
} }
func (h *LoveYou) resp() string { // Process does the heavy lifting
func (h *LoveYou) Process(from, post string) string {
a := []string{ a := []string{
"I am not ready for this kind of relationship!", "I am not ready for this kind of relationship!",
"ಠ_ಠ", "ಠ_ಠ",
@ -47,7 +48,7 @@ func (h *LoveYou) SetStore(_ PluginStore) {}
// RespondText to love events // RespondText to love events
func (h *LoveYou) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *LoveYou) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
return SendText(c, ev.RoomID, h.resp()) return SendText(c, ev.RoomID, h.Process("", ""))
} }
// Name i love you // Name i love you

View File

@ -50,14 +50,17 @@ func (h *OpenBSDMan) Match(_, msg string) bool {
// SetStore does nothing in OpenBSDMan // SetStore does nothing in OpenBSDMan
func (h *OpenBSDMan) SetStore(_ PluginStore) {} func (h *OpenBSDMan) SetStore(_ PluginStore) {}
// RespondText sends back a man page. func (h *OpenBSDMan) Process(from, post string) string {
func (h *OpenBSDMan) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
page := h.fix(post) page := h.fix(post)
if page != "" { if page != "" {
return SendText(c, ev.RoomID, fmt.Sprintf("https://man.openbsd.org/%s", page)) return fmt.Sprintf("https://man.openbsd.org/%s", page)
} }
return "..."
}
return nil // RespondText sends back a man page.
func (h *OpenBSDMan) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name OpenBSDMan! // Name OpenBSDMan!

View File

@ -56,6 +56,10 @@ func isEdge(x, y int) bool {
return false return false
} }
func (h *Palette) Process(_, _ string) string {
return "not supported"
}
// RespondText to color request events // RespondText to color request events
func (h *Palette) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (h *Palette) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
const width, height = 56, 56 const width, height = 56, 56

View File

@ -41,8 +41,7 @@ func (p *PGP) fix(msg string) string {
return strings.ToUpper(re.ReplaceAllString(msg, "$1")) return strings.ToUpper(re.ReplaceAllString(msg, "$1"))
} }
// RespondText to looking up of PGP info func (p *PGP) Process(from, post string) string {
func (p *PGP) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
search := p.fix(post) search := p.fix(post)
searchURL := "https://keys.openpgp.org//vks/v1/by-fingerprint/%s" searchURL := "https://keys.openpgp.org//vks/v1/by-fingerprint/%s"
@ -52,23 +51,21 @@ func (p *PGP) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
escSearch, err := url.Parse(search) escSearch, err := url.Parse(search)
if err != nil { if err != nil {
return err return err.Error()
} }
u := fmt.Sprintf(searchURL, escSearch) u := fmt.Sprintf(searchURL, escSearch)
resp, err := http.Get(u) resp, err := http.Get(u)
if err != nil { if err != nil {
_ = SendText(c, ev.RoomID, fmt.Sprintf("Can't search keys.openpgp.org: %s", err)) return err.Error()
return err
} }
defer resp.Body.Close() defer resp.Body.Close()
kr, err := openpgp.ReadArmoredKeyRing(resp.Body) kr, err := openpgp.ReadArmoredKeyRing(resp.Body)
if err != nil { if err != nil {
_ = SendText(c, ev.RoomID, fmt.Sprintf("Can't parse key ring: %s", err)) return err.Error()
return err
} }
var ids []string var ids []string
@ -81,9 +78,14 @@ func (p *PGP) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string
hex.EncodeToString(entity.PrimaryKey.Fingerprint[:]))) hex.EncodeToString(entity.PrimaryKey.Fingerprint[:])))
} }
return SendMD(c, ev.RoomID, fmt.Sprintf("%s\n\n%s", return fmt.Sprintf("%s\n\n%s",
strings.Join(ids, "\n"), strings.Join(ids, "\n"),
strings.Join(fps, "\n"))) strings.Join(fps, "\n"))
}
// RespondText to looking up of PGP info
func (p *PGP) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendMD(c, ev.RoomID, p.Process(ev.Sender, post))
} }
// Name PGP! // Name PGP!

View File

@ -43,7 +43,7 @@ type Plugin interface {
// Process is the processed response from the plugin. This is useful for // Process is the processed response from the plugin. This is useful for
// running the plugins outside of the context of Matrix. // running the plugins outside of the context of Matrix.
Process(from, message string) (string, error) Process(from, message string) string
// SetStore exposes the top level MCStore to a plugin // SetStore exposes the top level MCStore to a plugin
SetStore(s PluginStore) SetStore(s PluginStore)
@ -280,6 +280,7 @@ var Plugs = Plugins{
&Snap{}, &Snap{},
&Source{}, &Source{},
&Thanks{}, &Thanks{},
&Homestead{},
&Toki{}, &Toki{},
&Version{}, &Version{},
&Wb{}, &Wb{},

View File

@ -30,15 +30,20 @@ func (h *RFC) Match(_, msg string) bool {
// SetStore does nothing in RFC // SetStore does nothing in RFC
func (h *RFC) SetStore(_ PluginStore) {} func (h *RFC) SetStore(_ PluginStore) {}
// RespondText sends back a man page. // Process does the heavy lifting
func (h *RFC) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (h *RFC) Process(from, post string) string {
re := regexp.MustCompile(h.Re()) re := regexp.MustCompile(h.Re())
rfcNum := re.ReplaceAllString(post, "$1") rfcNum := re.ReplaceAllString(post, "$1")
if rfcNum != "" { if rfcNum != "" {
return SendText(c, ev.RoomID, fmt.Sprintf("https://tools.ietf.org/html/rfc%s", rfcNum)) return fmt.Sprintf("https://tools.ietf.org/html/rfc%s", rfcNum)
} }
return nil return "that's not an RFC."
}
// RespondText sends back a man page.
func (h *RFC) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name RFC // Name RFC

View File

@ -32,20 +32,25 @@ func (p *Snap) Match(_, msg string) bool {
// SetStore we don't need a store here. // SetStore we don't need a store here.
func (p *Snap) SetStore(_ PluginStore) {} func (p *Snap) SetStore(_ PluginStore) {}
// RespondText to looking up of federation check requests // Process does the heavy lifting
func (p *Snap) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (p *Snap) Process(from, post string) string {
resp, err := http.Get("https://ftp.usa.openbsd.org/pub/OpenBSD/snapshots/amd64/BUILDINFO") resp, err := http.Get("https://ftp.usa.openbsd.org/pub/OpenBSD/snapshots/amd64/BUILDINFO")
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("%s", err)) return fmt.Sprintf("%s", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("%s", err)) return fmt.Sprintf("%s", err)
} }
return SendText(c, ev.RoomID, string(body)) return string(body)
}
// RespondText to looking up of federation check requests
func (p *Snap) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
return SendText(c, ev.RoomID, p.Process("", ""))
} }
// Name Snap! // Name Snap!

View File

@ -30,11 +30,15 @@ func (h *Source) Match(user, msg string) bool {
// SetStore does nothing in here // SetStore does nothing in here
func (h *Source) SetStore(_ PluginStore) {} func (h *Source) SetStore(_ PluginStore) {}
// Process does the heavy lifting
func (h *Source) Process(from, post string) string {
s := NameRE.ReplaceAllString(from, "$1")
return fmt.Sprintf("%s: %s ;D", s, "https://git.sr.ht/~qbit/mcchunkie")
}
// RespondText to questions about TheSource™©®⑨ // RespondText to questions about TheSource™©®⑨
func (h *Source) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *Source) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
s := NameRE.ReplaceAllString(ev.Sender, "$1") return SendText(c, ev.RoomID, h.Process(ev.Sender, ""))
return SendText(c, ev.RoomID, fmt.Sprintf("%s: %s ;D", s, "https://git.sr.ht/~qbit/mcchunkie"))
} }
// Name Source // Name Source

View File

@ -32,9 +32,9 @@ func (h *Thanks) Match(user, msg string) bool {
// SetStore we don't need a store here // SetStore we don't need a store here
func (h *Thanks) SetStore(_ PluginStore) {} func (h *Thanks) SetStore(_ PluginStore) {}
// RespondText to welcome back events // Process
func (h *Thanks) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *Thanks) Process(from, post string) string {
s := NameRE.ReplaceAllString(ev.Sender, "$1") s := NameRE.ReplaceAllString(from, "$1")
a := []string{ a := []string{
fmt.Sprintf("welcome %s", s), fmt.Sprintf("welcome %s", s),
"welcome", "welcome",
@ -45,7 +45,12 @@ func (h *Thanks) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
return SendText(c, ev.RoomID, a[rand.Intn(len(a))]) return a[rand.Intn(len(a))]
}
// RespondText to welcome back events
func (h *Thanks) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, ""))
} }
// Name Thanks // Name Thanks

View File

@ -4035,8 +4035,8 @@ func (t *Toki) fix(msg string) (string, string) {
return re.ReplaceAllString(msg, "$1"), re.ReplaceAllString(msg, "$2") return re.ReplaceAllString(msg, "$1"), re.ReplaceAllString(msg, "$2")
} }
// RespondText to hi events // Process does the heavy lifting
func (t *Toki) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error { func (t *Toki) Process(from, post string) string {
cmd, w := t.fix(post) cmd, w := t.fix(post)
cmd = strings.ToLower(cmd) cmd = strings.ToLower(cmd)
switch cmd { switch cmd {
@ -4046,9 +4046,9 @@ func (t *Toki) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post strin
for _, v := range word { for _, v := range word {
defs = append(defs, v.Print(w)) defs = append(defs, v.Print(w))
} }
return SendMD(c, ev.RoomID, strings.Join(defs, "\n\n")) return strings.Join(defs, "\n\n")
} else { } else {
return SendText(c, ev.RoomID, "mi sona ala") return "mi sona ala"
} }
case "toki?": case "toki?":
st := stemmer.Stem(w) st := stemmer.Stem(w)
@ -4063,9 +4063,14 @@ func (t *Toki) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post strin
} }
} }
} }
return SendMD(c, ev.RoomID, strings.Join(words, "\n\n")) return strings.Join(words, "\n\n")
} }
return nil return "mi sona ala"
}
// RespondText to hi events
func (t *Toki) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendMD(c, ev.RoomID, t.Process(ev.Sender, post))
} }
// Name hi // Name hi

View File

@ -37,7 +37,7 @@ func (v *Version) Match(user, msg string) bool {
return re.MatchString(msg) && ToMe(user, msg) return re.MatchString(msg) && ToMe(user, msg)
} }
func (v *Version) print() string { func (v *Version) Process(_, _ string) string {
if version == "" { if version == "" {
version = "unknown version" version = "unknown version"
} }
@ -49,7 +49,7 @@ func (v *Version) SetStore(_ PluginStore) {}
// RespondText to version events // RespondText to version events
func (v *Version) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (v *Version) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
return SendMD(c, ev.RoomID, v.print()) return SendMD(c, ev.RoomID, v.Process("", ""))
} }
// Name Version // Name Version

View File

@ -162,24 +162,28 @@ func (h *Weather) fix(msg string) string {
return re.ReplaceAllString(msg, "$1") return re.ReplaceAllString(msg, "$1")
} }
// RespondText to looking up of weather lookup requests func (h *Weather) Process(from, post string) string {
func (h *Weather) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
weather := h.fix(post) weather := h.fix(post)
if weather != "" { if weather != "" {
wd, err := h.get(weather) wd, err := h.get(weather)
if err != nil { if err != nil {
return SendText(c, ev.RoomID, fmt.Sprintf("sorry %s, I can't look up the weather. %s", ev.Sender, err)) return fmt.Sprintf("sorry %s, I can't look up the weather. %s", from, err)
} }
return SendText(c, ev.RoomID, return fmt.Sprintf("%s: %s (%s) Humidity: %s%%, %s",
fmt.Sprintf("%s: %s (%s) Humidity: %s%%, %s", wd.Name,
wd.Name, wd.c(),
wd.c(), wd.f(),
wd.f(), wd.humidity(),
wd.humidity(), wd.conditions(),
wd.conditions(), )
))
} }
return nil
return "shrug."
}
// RespondText to looking up of weather lookup requests
func (h *Weather) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, post string) error {
return SendText(c, ev.RoomID, h.Process(ev.Sender, post))
} }
// Name Weather! // Name Weather!

View File

@ -30,11 +30,15 @@ func (h *Wb) Match(user, msg string) bool {
// SetStore we don't need a store here // SetStore we don't need a store here
func (h *Wb) SetStore(_ PluginStore) {} func (h *Wb) SetStore(_ PluginStore) {}
func (h *Wb) Process(from, post string) string {
s := NameRE.ReplaceAllString(from, "$1")
return fmt.Sprintf("thanks %s!", s)
}
// RespondText to welcome back events // RespondText to welcome back events
func (h *Wb) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error { func (h *Wb) RespondText(c *gomatrix.Client, ev *gomatrix.Event, _, _ string) error {
s := NameRE.ReplaceAllString(ev.Sender, "$1") return SendText(c, ev.RoomID, h.Process(ev.Sender, ""))
return SendText(c, ev.RoomID, fmt.Sprintf("thanks %s!", s))
} }
// Name Wb // Name Wb

98
sms.go
View File

@ -5,14 +5,25 @@ import (
"log" "log"
"net/http" "net/http"
"strings" "strings"
"time"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"suah.dev/mcchunkie/plugins" "suah.dev/mcchunkie/plugins"
) )
func smsCanSend(number string, numbers []string) bool {
for _, s := range numbers {
if number == s {
return true
}
}
return false
}
func smsListen(store *FStore, plugins *plugins.Plugins) { func smsListen(store *FStore, plugins *plugins.Plugins) {
var smsPort, _ = store.Get("sms_listen") var smsPort, _ = store.Get("sms_listen")
var smsAllowed, _ = store.Get("sms_users")
var smsUsers = strings.Split(smsAllowed, ",")
if smsPort != "" { if smsPort != "" {
var htpass, _ = store.Get("sms_htpass") var htpass, _ = store.Get("sms_htpass")
@ -23,7 +34,7 @@ func smsListen(store *FStore, plugins *plugins.Plugins) {
user, pass, ok := r.BasicAuth() user, pass, ok := r.BasicAuth()
err := bcrypt.CompareHashAndPassword([]byte(htpass), []byte(pass)) err := bcrypt.CompareHashAndPassword([]byte(htpass), []byte(pass))
if !(ok && err == nil && user == "sms") { if !(ok && err == nil && user == "sms") {
log.Printf("SMS: failed auth '%s'\n", user) log.Printf("SMS: failed auth %q %q\n", user, pass)
w.Header().Set("WWW-Authenticate", `Basic realm="sms notify"`) w.Header().Set("WWW-Authenticate", `Basic realm="sms notify"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)
return return
@ -35,24 +46,10 @@ func smsListen(store *FStore, plugins *plugins.Plugins) {
return return
} }
/* log.Println(r.Method)
POST /_sms HTTP/1.0
X-Forwarded-For: 54.162.174.232
Host: suah.dev:443
X-Forwarded-Proto: https
X-Forwarded-Ssl: on
Connection: close
Content-Length: 407
Content-Type: application/x-www-form-urlencoded
X-Twilio-Signature: Y0YhchuDX0NZqhN7RmrdWWjg/mM=
I-Twilio-Idempotency-Token: 10152b5f-8f76-4477-95e8-ed2a7000675b
User-Agent: TwilioProxy/1.1
ToCountry=US&ToState=MI&SmsMessageSid=SM0ba92af93fd5312949198953b503a787&NumMedia=0&ToCity=&FromZip=80919&SmsSid=SM0ba92af93fd5312949198953b503a787&FromState=CO&SmsStatus=received&FromCity=COLORADO+SPRINGS&Body=New+test&FromCountry=US&To=%2B18105103020&ToZip=&NumSegments=1&MessageSid=SM0ba92af93fd5312949198953b503a787&AccountSid=ACa42644b105e1329a42ca640daa61903b&From=%2B17192103020&ApiVersion=2010-04-01
*/
switch r.Method { switch r.Method {
case http.MethodGet, http.MethodPost: case http.MethodPost:
msg = r.Form.Get("Body") msg = r.Form.Get("Body")
from = r.Form.Get("From") from = r.Form.Get("From")
default: default:
@ -64,52 +61,33 @@ func smsListen(store *FStore, plugins *plugins.Plugins) {
return return
} }
msg = strings.TrimSuffix(msg, "\n") if smsCanSend(from, smsUsers) {
msg = strings.TrimSuffix(msg, "\n")
if msg == "" { if msg == "" {
fmt.Fprintf(w, "empty message") fmt.Fprintf(w, "empty message")
return
}
for _, p := range *plugins {
if p.Match(from, msg) {
log.Printf("%s: responding to '%s'", p.Name(), from)
p.SetStore(store)
resp := p.Process(from, msg)
fmt.Fprint(w, resp)
}
}
} else {
log.Printf("number not allowed (%q)", from)
http.Error(
w,
fmt.Sprintf("number not allowed (%q)", from),
http.StatusMethodNotAllowed,
)
return return
} }
for _, p := range *plugins {
if p.Match(from, msg) {
log.Printf("%s: responding to '%s'", p.Name(), from)
p.SetStore(store)
start := time.Now()
resp, err := p.Process(from, msg)
if err != nil {
fmt.Println(err)
}
log.Println(resp)
elapsed := time.Since(start)
if verbose {
log.Printf("%s took %s to run\n", p.Name(), elapsed)
}
}
}
/*
for _, line := range strings.Split(msg, "\n") {
log.Printf("SMS: sending '%s'\n", line)
err = plugins.SendUnescNotice(cli, smsRoom, line)
if err != nil {
http.Error(
w,
fmt.Sprintf("can not send commit info: %s", err),
http.StatusInternalServerError,
)
return
}
}
*/
fmt.Fprintf(w, "ok")
}) })
log.Fatal(http.ListenAndServe(smsPort, nil)) log.Fatal(http.ListenAndServe(smsPort, nil))
} }
} }