move bot to cmd/

This commit is contained in:
Cadey Ratio 2017-08-25 07:46:50 -07:00
parent 931404890e
commit 07651ae4a7
No known key found for this signature in database
GPG Key ID: D607EE27C2E7F89A
10 changed files with 402 additions and 1 deletions

1
.gitignore vendored
View File

@ -1,2 +1 @@
.env
vyvanse

BIN
cmd/vyvanse/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
vyvanse

27
cmd/vyvanse/dice.go Normal file
View File

@ -0,0 +1,27 @@
package main
import (
"context"
"errors"
"github.com/bwmarrin/discordgo"
"github.com/justinian/dice"
opentracing "github.com/opentracing/opentracing-go"
)
func roll(ctx context.Context, s *discordgo.Session, m *discordgo.Message, parv []string) error {
sp, ctx := opentracing.StartSpanFromContext(ctx, "dice")
defer sp.Finish()
if len(parv) != 2 {
return errors.New("not enough parameters (expected 1)")
}
text, _, err := dice.Roll(parv[1])
if err != nil {
return err
}
_, err = s.ChannelMessageSend(m.ChannelID, text.String())
return err
}

13
cmd/vyvanse/gops.go Normal file
View File

@ -0,0 +1,13 @@
package main
import (
"log"
"github.com/google/gops/agent"
)
func init() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
}

52
cmd/vyvanse/hipster.go Normal file
View File

@ -0,0 +1,52 @@
package main
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"github.com/Xe/ln"
"github.com/bwmarrin/discordgo"
opentracing "github.com/opentracing/opentracing-go"
)
func hipster(ctx context.Context, s *discordgo.Session, m *discordgo.Message, parv []string) error {
sp, ctx := opentracing.StartSpanFromContext(ctx, "hipster")
defer sp.Finish()
msg, err := getHipsterText(ctx)
if err != nil {
ln.Error(ctx, err, ln.F{"action": "get hipster text"})
return err
}
_, err = s.ChannelMessageSend(m.ChannelID, msg)
return err
}
func getHipsterText(ctx context.Context) (string, error) {
req, err := http.NewRequest(http.MethodGet, "http://hipsterjesus.com/api/?type=hipster-centric&html=false&paras=1", nil)
req = req.WithContext(ctx)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
textStruct := &struct {
Text string `json:"text"`
}{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
json.Unmarshal(body, textStruct)
text := strings.Split(textStruct.Text, ". ")[0]
return text, nil
}

127
cmd/vyvanse/main.go Normal file
View File

@ -0,0 +1,127 @@
package main
import (
"context"
"fmt"
"log"
"net/http"
"git.xeserv.us/xena/vyvanse/bot"
"github.com/Xe/ln"
"github.com/bwmarrin/discordgo"
_ "github.com/joho/godotenv/autoload"
"github.com/namsral/flag"
xkcd "github.com/nishanths/go-xkcd"
opentracing "github.com/opentracing/opentracing-go"
otlog "github.com/opentracing/opentracing-go/log"
zipkin "github.com/openzipkin/zipkin-go-opentracing"
"github.com/robfig/cron"
)
var lastXKCD int
var (
pesterChannel = flag.String("upload-channel", "", "Discord channel ID to upload and announce new XKCD items to")
token = flag.String("token", "", "discord bot token")
zipkinURL = flag.String("zipkin-url", "", "URL for Zipkin traces")
)
func main() {
flag.Parse()
xk := xkcd.NewClient()
dg, err := discordgo.New("Bot " + *token)
if err != nil {
log.Fatal(err)
}
c := cron.New()
comic, err := xk.Latest()
if err != nil {
log.Fatal(err)
}
lastXKCD = comic.Number
c.AddFunc("@daily", func() {
sp, ctx := opentracing.StartSpanFromContext(context.Background(), "daily.xkcd.fetch")
comic, err := xk.Latest()
if err != nil {
log.Println(err)
return
}
if comic.Number > lastXKCD {
sp.LogFields(otlog.String("image.url", comic.ImageURL), otlog.String("target", *pesterChannel))
req, err := http.NewRequest(http.MethodGet, comic.ImageURL, nil)
if err != nil {
ln.Error(ctx, err, ln.F{"action": "make request"})
sp.LogFields(otlog.Error(err))
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
ln.Error(ctx, err, ln.F{"action": "http get", "url": comic.ImageURL})
sp.LogFields(otlog.Error(err))
return
}
fname := fmt.Sprintf("%d - %s.png", comic.Number, comic.Title)
msg := fmt.Sprintf("New XKCD comic uploaded: %d - %s\n\n*%s*", comic.Number, comic.Title, comic.Alt)
_, err = dg.ChannelFileSendWithMessage(*pesterChannel, msg, fname, resp.Body)
if err != nil {
ln.Error(ctx, err, ln.F{"action": "send xkcd upload", "to": *pesterChannel})
sp.LogFields(otlog.Error(err))
return
}
lastXKCD = comic.Number
}
})
c.Start()
if *zipkinURL != "" {
collector, err := zipkin.NewHTTPCollector(*zipkinURL)
if err != nil {
ln.FatalErr(context.Background(), err)
}
tracer, err := zipkin.NewTracer(
zipkin.NewRecorder(collector, false, "vyvanse:5000", "vyvanse"))
if err != nil {
ln.FatalErr(context.Background(), err)
}
opentracing.SetGlobalTracer(tracer)
}
cs := bot.NewCommandSet()
cs.Prefix = ">"
cs.AddCmd("hipster", "generates hipster-sounding text", bot.NoPermissions, hipster)
cs.AddCmd("printerfact", "facts about printers", bot.NoPermissions, printerFact)
cs.AddCmd("dice", "roll the dice", bot.NoPermissions, roll)
cs.AddCmd("splattus", "splatoon 2 map rotation status", bot.NoPermissions, spla2nMaps)
dg.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
err := cs.Run(s, m.Message)
if err != nil {
ln.Error(context.Background(), err, ln.F{"action": "run commandSet on message"})
}
})
// Open the websocket and begin listening.
err = dg.Open()
if err != nil {
fmt.Println("error opening connection,", err)
return
}
fmt.Println("Bot is now running. Press CTRL-C to exit.")
// Simple way to keep program running until CTRL-C is pressed.
<-make(chan struct{})
return
}

View File

@ -0,0 +1,47 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/bwmarrin/discordgo"
opentracing "github.com/opentracing/opentracing-go"
)
func printerFact(ctx context.Context, s *discordgo.Session, m *discordgo.Message, parv []string) error {
sp, ctx := opentracing.StartSpanFromContext(ctx, "printer.fact")
defer sp.Finish()
fact, err := getPrinterFact()
if err != nil {
return err
}
s.ChannelMessageSend(m.ChannelID, fact)
return nil
}
func getPrinterFact() (string, error) {
resp, err := http.Get("https://xena.stdlib.com/printerfacts")
if err != nil {
return "", err
}
factStruct := &struct {
Facts []string `json:"facts"`
}{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
json.Unmarshal(body, factStruct)
text := fmt.Sprintf("%s", factStruct.Facts[0])
return text, nil
}

114
cmd/vyvanse/spla2n.go Normal file
View File

@ -0,0 +1,114 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/bwmarrin/discordgo"
opentracing "github.com/opentracing/opentracing-go"
otlog "github.com/opentracing/opentracing-go/log"
)
func spla2nMaps(ctx context.Context, s *discordgo.Session, msg *discordgo.Message, parv []string) error {
sp, ctx := opentracing.StartSpanFromContext(ctx, "spla2nMaps")
defer sp.Finish()
resp, err := http.Get("https://splatoon.ink/schedule2")
if err != nil {
sp.LogFields(otlog.Error(err), otlog.String("step", "http get"))
return err
}
st := &splattus{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
sp.LogFields(otlog.Error(err), otlog.String("step", "http response read"))
return err
}
json.Unmarshal(body, st)
var modeInfo []string
for _, mode := range st.Modes.Regular {
if mode.Active() {
modeInfo = append(modeInfo, mode.String())
}
}
for _, mode := range st.Modes.Gachi {
if mode.Active() {
modeInfo = append(modeInfo, mode.String())
}
}
for _, mode := range st.Modes.League {
if mode.Active() {
modeInfo = append(modeInfo, mode.String())
}
}
text := strings.Join(modeInfo, "\n")
_, err = s.ChannelMessageSend(msg.ChannelID, text)
return err
}
type splatoonMode struct {
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
Maps []string `json:"maps"`
Rule splatoonRule `json:"rule"`
Mode splatoonGameMode `json:"mode"`
}
func (sm splatoonMode) Active() bool {
beg := time.Unix(sm.StartTime, 0)
end := time.Unix(sm.EndTime, 0)
now := time.Now()
return now.After(beg) && now.Before(end)
}
func (sm splatoonMode) String() string {
maps := strings.Join(sm.Maps, ", ")
end := time.Unix(sm.EndTime, 0)
now := time.Now()
diff := end.Sub(now)
return fmt.Sprintf("%s:\nRotation ends at %s (in %s)\nMaps: %s\nRule: %s\n", sm.Mode, end.Format(time.RFC3339), diff, maps, sm.Rule)
}
type splatoonGameMode struct {
Key string `json:"key"`
Name string `json:"name"`
}
func (sgm splatoonGameMode) String() string {
return sgm.Name
}
type splatoonRule struct {
Key string `json:"key"`
MultilineName string `json:"multiline_name"`
Name string `json:"name"`
}
func (sr splatoonRule) String() string {
return sr.Name
}
type splattus struct {
UpdateTime int64 `json:"updateTime"`
Modes struct {
League []splatoonMode `json:"league"`
Regular []splatoonMode `json:"regular"`
Gachi []splatoonMode `json:"gachi"`
} `json:"modes"`
}

View File

@ -1,6 +1,9 @@
version: "3"
services:
# Persistence layers and dev tools
# http://127.0.0.1:9411
zipkin:
image: openzipkin/zipkin
environment:
@ -8,8 +11,26 @@ services:
ports:
- "9411:9411"
# message queue
mq:
image: drone/mq
# database
rqlite:
restart: always
image: rqlite/rqlite:4.0.2
volumes:
- rqlite:/rqlite/file
command: -on-disk -http-adv-addr rqlite:4001
# the bot and event sourcing ingress
vyvanse:
image: xena/vyvanse
env_file: ./.env
depends_on:
- zipkin
- mq
- rqlite
volumes:
rqlite: