131 lines
3.3 KiB
Go
131 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"text/template"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/Luzifer/rconfig/v2"
|
|
"github.com/Luzifer/twitch-bot/v3/plugins"
|
|
)
|
|
|
|
var (
|
|
cfg = struct {
|
|
BotRespond bool `flag:"bot-respond,b" default:"false" description:"Wrap output in a respond directive for twitch-bot"`
|
|
Count int64 `flag:"count,c" default:"1" description:"How many dice to throw?"`
|
|
LogLevel string `flag:"log-level" default:"info" description:"Log level (debug, info, warn, error, fatal)"`
|
|
Sides int64 `flag:"sides,s" default:"6" description:"How many sides does the dice have?"`
|
|
Template string `flag:"template" vardefault:"tpl" description:"Template to format the result with"`
|
|
Type string `flag:"type,t" default:"dice" description:"What to throw (coin, dice)"`
|
|
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
|
}{}
|
|
|
|
version = "dev"
|
|
)
|
|
|
|
func initApp() error {
|
|
rconfig.AutoEnv(true)
|
|
rconfig.SetVariableDefaults(map[string]string{
|
|
"tpl": `I threw {{.count}}x {{if eq .type "coin"}}coin{{else}}W{{.sides}}{{end}} for you and got:{{ range .results}} {{ if eq $.type "coin" }}{{ if eq . 1 }}Head{{ else }}Number{{ end }}{{ else }}{{ . }}{{ end }}{{ end }}`,
|
|
})
|
|
|
|
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
|
return errors.Wrap(err, "parsing cli options")
|
|
}
|
|
|
|
l, err := logrus.ParseLevel(cfg.LogLevel)
|
|
if err != nil {
|
|
return errors.Wrap(err, "parsing log-level")
|
|
}
|
|
logrus.SetLevel(l)
|
|
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
var (
|
|
err error
|
|
results []int64
|
|
sum int64
|
|
)
|
|
|
|
if err = initApp(); err != nil {
|
|
logrus.WithError(err).Fatal("initializing app")
|
|
}
|
|
|
|
if cfg.VersionAndExit {
|
|
logrus.WithField("version", version).Info("twitch-bot-tools/dice")
|
|
os.Exit(0)
|
|
}
|
|
|
|
switch cfg.Type {
|
|
case "coin":
|
|
results, sum = getResults(2, cfg.Count) //nolint:gomnd // Makes no sense to extract
|
|
|
|
case "dice":
|
|
if cfg.Sides == 0 {
|
|
// There is no [0..0] dice.
|
|
logrus.Fatal("there is no 0-sided dice")
|
|
}
|
|
results, sum = getResults(cfg.Sides, cfg.Count)
|
|
|
|
default:
|
|
logrus.WithField("type", cfg.Type).Fatal("don't know how to throw that")
|
|
}
|
|
|
|
t, err := template.New("output").Parse(cfg.Template)
|
|
if err != nil {
|
|
logrus.WithError(err).Fatal("parsing template")
|
|
}
|
|
|
|
text := new(bytes.Buffer)
|
|
if err = t.Execute(text, map[string]interface{}{
|
|
"count": cfg.Count,
|
|
"results": results,
|
|
"sides": cfg.Sides,
|
|
"sum": sum,
|
|
"type": cfg.Type,
|
|
}); err != nil {
|
|
logrus.WithError(err).Fatal("executing template")
|
|
}
|
|
|
|
if !cfg.BotRespond {
|
|
fmt.Println(text.String()) //nolint:forbidigo // This is an expected stdout output
|
|
return
|
|
}
|
|
|
|
output := []plugins.RuleAction{
|
|
{
|
|
Type: "respond",
|
|
Attributes: plugins.FieldCollectionFromData(map[string]any{
|
|
"message": text.String(),
|
|
}),
|
|
},
|
|
}
|
|
|
|
if err = json.NewEncoder(os.Stdout).Encode(output); err != nil {
|
|
logrus.WithError(err).Fatal("encoding bot response")
|
|
}
|
|
}
|
|
|
|
func getRandomNumber(sides int64) int64 {
|
|
n, _ := rand.Int(rand.Reader, big.NewInt(sides))
|
|
return n.Int64()
|
|
}
|
|
|
|
func getResults(sides, count int64) (res []int64, sum int64) {
|
|
for i := int64(0); i < count; i++ {
|
|
v := getRandomNumber(sides) + 1
|
|
res = append(res, v)
|
|
sum += v
|
|
}
|
|
|
|
return res, sum
|
|
}
|