2024-01-01 16:52:18 +00:00
// Package random contains helpers to aid with randomness
2021-11-19 21:53:30 +00:00
package random
import (
"crypto/md5" // #nosec G501 // Unly used to convert a string into a numer, no need for cryptographic safety
"fmt"
"math"
"math/rand"
"github.com/pkg/errors"
2021-11-25 22:48:16 +00:00
2022-11-02 21:38:14 +00:00
"github.com/Luzifer/twitch-bot/v3/plugins"
2021-11-19 21:53:30 +00:00
)
2024-01-01 16:52:18 +00:00
// Register provides the plugins.RegisterFunc
2021-11-19 21:53:30 +00:00
func Register ( args plugins . RegistrationArguments ) error {
2023-08-25 21:37:37 +00:00
args . RegisterTemplateFunction ( "randomString" , plugins . GenericTemplateFunctionGetter ( randomString ) , plugins . TemplateFuncDocumentation {
Description : "Randomly picks a string from a list of strings" ,
Syntax : "randomString <string> [...string]" ,
Example : & plugins . TemplateFuncDocumentationExample {
Template : ` {{ randomString "a" "b" "c" "d" }} ` ,
FakedOutput : "a" ,
} ,
} )
args . RegisterTemplateFunction ( "seededRandom" , plugins . GenericTemplateFunctionGetter ( stableRandomFromSeed ) , plugins . TemplateFuncDocumentation {
Description : "Returns a float value stable for the given seed" ,
Syntax : "seededRandom <string-seed>" ,
Example : & plugins . TemplateFuncDocumentationExample {
Template : ` Your int this hour: {{ printf "%.0f" ( mulf ( seededRandom ( list "int" .username ( now | date "2006-01-02 15" ) | join ":" ) ) 100 ) }} % ` ,
} ,
} )
2021-11-19 21:53:30 +00:00
return nil
}
2022-08-16 15:55:23 +00:00
func randomString ( lst ... string ) ( string , error ) {
if len ( lst ) == 0 {
return "" , errors . New ( "empty list given" )
}
2022-09-05 22:35:20 +00:00
return lst [ rand . Intn ( len ( lst ) ) ] , nil // #nosec:G404 // This is used to select a random string from a list, no crypto-use
2022-08-16 15:55:23 +00:00
}
2021-11-19 21:53:30 +00:00
func stableRandomFromSeed ( seed string ) ( float64 , error ) {
seedValue , err := stringToSeed ( seed )
if err != nil {
return 0 , errors . Wrap ( err , "generating seed" )
}
2022-09-05 22:35:20 +00:00
return rand . New ( rand . NewSource ( seedValue ) ) . Float64 ( ) , nil // #nosec:G404 // Only used for generating a random number from static string, no need for cryptographic safety
2021-11-19 21:53:30 +00:00
}
func stringToSeed ( s string ) ( int64 , error ) {
2022-09-05 22:35:20 +00:00
hash := md5 . New ( ) // #nosec:G401 // Unly used to convert a string into a numer, no need for cryptographic safety
2021-11-19 21:53:30 +00:00
if _ , err := fmt . Fprint ( hash , s ) ; err != nil {
return 0 , errors . Wrap ( err , "writing string to hasher" )
}
var (
hashSum = hash . Sum ( nil )
sum int64
)
for i := 0 ; i < len ( hashSum ) ; i ++ {
2024-06-09 10:44:41 +00:00
sum += int64 ( float64 ( hashSum [ len ( hashSum ) - 1 - i ] % 10 ) * math . Pow ( 10 , float64 ( i ) ) ) //nolint:mnd // No need to put the 10 of 10**i into a constant named "ten"
2021-11-19 21:53:30 +00:00
}
return sum , nil
}