Add support for dynamic variables

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2021-06-29 14:08:26 +02:00
parent 50a155ddb2
commit 13a6dd5695
Signed by: luzifer
GPG key ID: 0066F03ED215AD7D
4 changed files with 91 additions and 4 deletions

47
action_setvar.go Normal file
View file

@ -0,0 +1,47 @@
package main
import (
"github.com/go-irc/irc"
"github.com/pkg/errors"
)
func init() {
registerAction(func() Actor { return &ActorSetVariable{} })
}
type ActorSetVariable struct {
Variable string `json:"variable" yaml:"variable"`
Clear bool `json:"clear" yaml:"clear"`
Set string `json:"set" yaml:"set"`
}
func (a ActorSetVariable) Execute(c *irc.Client, m *irc.Message, r *Rule) error {
if a.Variable == "" {
return nil
}
varName, err := formatMessage(a.Variable, m, r, nil)
if err != nil {
return errors.Wrap(err, "preparing variable name")
}
if a.Clear {
return errors.Wrap(
store.RemoveVariable(varName),
"removing variable",
)
}
value, err := formatMessage(a.Set, m, r, nil)
if err != nil {
return errors.Wrap(err, "preparing value")
}
return errors.Wrap(
store.SetVariable(varName, value),
"setting variable",
)
}
func (a ActorSetVariable) IsAsync() bool { return false }
func (a ActorSetVariable) Name() string { return "setvariable" }

View file

@ -62,4 +62,11 @@ func init() {
tplFuncs.Register("toUpper", genericTemplateFunctionGetter(strings.ToUpper)) tplFuncs.Register("toUpper", genericTemplateFunctionGetter(strings.ToUpper))
tplFuncs.Register("followDate", genericTemplateFunctionGetter(twitch.GetFollowDate)) tplFuncs.Register("followDate", genericTemplateFunctionGetter(twitch.GetFollowDate))
tplFuncs.Register("concat", genericTemplateFunctionGetter(func(delim string, parts ...string) string { return strings.Join(parts, delim) })) tplFuncs.Register("concat", genericTemplateFunctionGetter(func(delim string, parts ...string) string { return strings.Join(parts, delim) }))
tplFuncs.Register("variable", genericTemplateFunctionGetter(func(name string, defVal ...string) string {
value := store.GetVariable(name)
if value == "" && len(defVal) > 0 {
return defVal[0]
}
return value
}))
} }

View file

@ -11,8 +11,9 @@ import (
) )
type storageFile struct { type storageFile struct {
Counters map[string]int64 `json:"counters"` Counters map[string]int64 `json:"counters"`
Timers map[string]timerEntry `json:"timers"` Timers map[string]timerEntry `json:"timers"`
Variables map[string]string `json:"variables"`
inMem bool inMem bool
lock *sync.RWMutex lock *sync.RWMutex
@ -20,8 +21,9 @@ type storageFile struct {
func newStorageFile(inMemStore bool) *storageFile { func newStorageFile(inMemStore bool) *storageFile {
return &storageFile{ return &storageFile{
Counters: map[string]int64{}, Counters: map[string]int64{},
Timers: map[string]timerEntry{}, Timers: map[string]timerEntry{},
Variables: map[string]string{},
inMem: inMemStore, inMem: inMemStore,
lock: new(sync.RWMutex), lock: new(sync.RWMutex),
@ -35,6 +37,13 @@ func (s *storageFile) GetCounterValue(counter string) int64 {
return s.Counters[counter] return s.Counters[counter]
} }
func (s *storageFile) GetVariable(key string) string {
s.lock.RLock()
defer s.lock.RUnlock()
return s.Variables[key]
}
func (s *storageFile) HasTimer(id string) bool { func (s *storageFile) HasTimer(id string) bool {
s.lock.RLock() s.lock.RLock()
defer s.lock.RUnlock() defer s.lock.RUnlock()
@ -121,6 +130,24 @@ func (s *storageFile) SetTimer(kind timerType, id string, expiry time.Time) erro
return errors.Wrap(s.Save(), "saving store") return errors.Wrap(s.Save(), "saving store")
} }
func (s *storageFile) SetVariable(key, value string) error {
s.lock.Lock()
defer s.lock.Unlock()
s.Variables[key] = value
return errors.Wrap(s.Save(), "saving store")
}
func (s *storageFile) RemoveVariable(key string) error {
s.lock.Lock()
defer s.lock.Unlock()
delete(s.Variables, key)
return errors.Wrap(s.Save(), "saving store")
}
func (s *storageFile) UpdateCounter(counter string, value int64, absolute bool) error { func (s *storageFile) UpdateCounter(counter string, value int64, absolute bool) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()

View file

@ -69,6 +69,11 @@ rules: # See below for examples
# Issue a timeout on the user who wrote the chat-line # Issue a timeout on the user who wrote the chat-line
- timeout: 1s # Duration value: 1s / 1m / 1h - timeout: 1s # Duration value: 1s / 1m / 1h
# Set a variable to value defined for later usage
- variable: myvar # String, name of the variable to set (applies templating)
clear: false # Boolean, clear the variable
set: '{{ .channel }}' # String, value to set the variable to (applies templating)
# Send a whisper (ATTENTION: You need to have a known / verified bot for this!) # Send a whisper (ATTENTION: You need to have a known / verified bot for this!)
# Without being known / verified your whisper will just silently get dropped by Twitch # Without being known / verified your whisper will just silently get dropped by Twitch
# Go here to get that verification: https://dev.twitch.tv/limit-increase # Go here to get that verification: https://dev.twitch.tv/limit-increase
@ -154,6 +159,7 @@ Additionally there are some functions available in the templates:
- `tag <tagname>` - Takes the message sent to the channel, returns the value of the tag specified - `tag <tagname>` - Takes the message sent to the channel, returns the value of the tag specified
- `toLower <string>` - Converts the given string to lower-case - `toLower <string>` - Converts the given string to lower-case
- `toUpper <string>` - Converts the given string to upper-case - `toUpper <string>` - Converts the given string to upper-case
- `variable <name> [default]` - Returns the variable value or default in case it is empty
## Command executions ## Command executions