From 13a6dd5695121f7240cdc6d0d11cef1089daf35d Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Tue, 29 Jun 2021 14:08:26 +0200 Subject: [PATCH] Add support for dynamic variables Signed-off-by: Knut Ahlers --- action_setvar.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ functions.go | 7 +++++++ store.go | 35 +++++++++++++++++++++++++++++++---- wiki/Home.md | 6 ++++++ 4 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 action_setvar.go diff --git a/action_setvar.go b/action_setvar.go new file mode 100644 index 0000000..7b109a6 --- /dev/null +++ b/action_setvar.go @@ -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" } diff --git a/functions.go b/functions.go index ad53fc3..9026475 100644 --- a/functions.go +++ b/functions.go @@ -62,4 +62,11 @@ func init() { tplFuncs.Register("toUpper", genericTemplateFunctionGetter(strings.ToUpper)) tplFuncs.Register("followDate", genericTemplateFunctionGetter(twitch.GetFollowDate)) 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 + })) } diff --git a/store.go b/store.go index 0ea8ec3..7e89d42 100644 --- a/store.go +++ b/store.go @@ -11,8 +11,9 @@ import ( ) type storageFile struct { - Counters map[string]int64 `json:"counters"` - Timers map[string]timerEntry `json:"timers"` + Counters map[string]int64 `json:"counters"` + Timers map[string]timerEntry `json:"timers"` + Variables map[string]string `json:"variables"` inMem bool lock *sync.RWMutex @@ -20,8 +21,9 @@ type storageFile struct { func newStorageFile(inMemStore bool) *storageFile { return &storageFile{ - Counters: map[string]int64{}, - Timers: map[string]timerEntry{}, + Counters: map[string]int64{}, + Timers: map[string]timerEntry{}, + Variables: map[string]string{}, inMem: inMemStore, lock: new(sync.RWMutex), @@ -35,6 +37,13 @@ func (s *storageFile) GetCounterValue(counter string) int64 { 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 { s.lock.RLock() 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") } +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 { s.lock.Lock() defer s.lock.Unlock() diff --git a/wiki/Home.md b/wiki/Home.md index 295e183..f9dd6e4 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -69,6 +69,11 @@ rules: # See below for examples # Issue a timeout on the user who wrote the chat-line - 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!) # 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 @@ -154,6 +159,7 @@ Additionally there are some functions available in the templates: - `tag ` - Takes the message sent to the channel, returns the value of the tag specified - `toLower ` - Converts the given string to lower-case - `toUpper ` - Converts the given string to upper-case +- `variable [default]` - Returns the variable value or default in case it is empty ## Command executions