2023-09-01 16:35:28 +00:00
package main
import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"math/big"
"os"
"text/template"
2023-09-01 16:59:21 +00:00
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
2023-09-01 16:35:28 +00:00
"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"
)
2023-09-01 16:59:21 +00:00
func initApp ( ) error {
2023-09-01 16:35:28 +00:00
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 }} ` ,
} )
2023-09-01 16:59:21 +00:00
2023-09-01 16:35:28 +00:00
if err := rconfig . ParseAndValidate ( & cfg ) ; err != nil {
2023-09-01 16:59:21 +00:00
return errors . Wrap ( err , "parsing cli options" )
2023-09-01 16:35:28 +00:00
}
2023-09-01 16:59:21 +00:00
l , err := logrus . ParseLevel ( cfg . LogLevel )
if err != nil {
return errors . Wrap ( err , "parsing log-level" )
2023-09-01 16:35:28 +00:00
}
2023-09-01 16:59:21 +00:00
logrus . SetLevel ( l )
2023-09-01 16:35:28 +00:00
2023-09-01 16:59:21 +00:00
return nil
2023-09-01 16:35:28 +00:00
}
func main ( ) {
var (
2023-09-01 16:59:21 +00:00
err error
2023-09-01 16:35:28 +00:00
results [ ] int64
sum int64
)
2023-09-01 16:59:21 +00:00
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 )
}
2023-09-01 16:35:28 +00:00
switch cfg . Type {
case "coin" :
2023-09-01 16:59:21 +00:00
results , sum = getResults ( 2 , cfg . Count ) //nolint:gomnd // Makes no sense to extract
2023-09-01 16:35:28 +00:00
case "dice" :
if cfg . Sides == 0 {
// There is no [0..0] dice.
2023-09-01 16:59:21 +00:00
logrus . Fatal ( "there is no 0-sided dice" )
2023-09-01 16:35:28 +00:00
}
results , sum = getResults ( cfg . Sides , cfg . Count )
default :
2023-09-01 16:59:21 +00:00
logrus . WithField ( "type" , cfg . Type ) . Fatal ( "don't know how to throw that" )
2023-09-01 16:35:28 +00:00
}
t , err := template . New ( "output" ) . Parse ( cfg . Template )
if err != nil {
2023-09-01 16:59:21 +00:00
logrus . WithError ( err ) . Fatal ( "parsing template" )
2023-09-01 16:35:28 +00:00
}
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 {
2023-09-01 16:59:21 +00:00
logrus . WithError ( err ) . Fatal ( "executing template" )
2023-09-01 16:35:28 +00:00
}
if ! cfg . BotRespond {
2023-09-01 16:59:21 +00:00
fmt . Println ( text . String ( ) ) //nolint:forbidigo // This is an expected stdout output
2023-09-01 16:35:28 +00:00
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 {
2023-09-01 16:59:21 +00:00
logrus . WithError ( err ) . Fatal ( "encoding bot response" )
2023-09-01 16:35:28 +00:00
}
}
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
}