twitch-bot/internal/actors/respond/actor.go
Knut Ahlers 0a937a65d0
prepare release v3.0.0
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2022-11-02 22:54:52 +01:00

137 lines
3.9 KiB
Go

package respond
import (
"fmt"
"strings"
"github.com/go-irc/irc"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/Luzifer/twitch-bot/v3/plugins"
)
const actorName = "respond"
var (
formatMessage plugins.MsgFormatter
send plugins.SendMessageFunc
ptrBoolFalse = func(v bool) *bool { return &v }(false)
ptrStringEmpty = func(s string) *string { return &s }("")
)
func Register(args plugins.RegistrationArguments) error {
formatMessage = args.FormatMessage
send = args.SendMessage
args.RegisterActor(actorName, func() plugins.Actor { return &actor{} })
args.RegisterActorDocumentation(plugins.ActionDocumentation{
Description: "Respond to message with a new message",
Name: "Respond to Message",
Type: "respond",
Fields: []plugins.ActionDocumentationField{
{
Default: "",
Description: "Message text to send",
Key: "message",
Long: true,
Name: "Message",
Optional: false,
SupportTemplate: true,
Type: plugins.ActionDocumentationFieldTypeString,
},
{
Default: "",
Description: "Fallback message text to send if message cannot be generated",
Key: "fallback",
Name: "Fallback",
Optional: true,
SupportTemplate: true,
Type: plugins.ActionDocumentationFieldTypeString,
},
{
Default: "false",
Description: "Send message as a native Twitch-reply to the original message",
Key: "as_reply",
Name: "As Reply",
Optional: true,
SupportTemplate: false,
Type: plugins.ActionDocumentationFieldTypeBool,
},
{
Default: "",
Description: "Send message to a different channel than the original message",
Key: "to_channel",
Name: "To Channel",
Optional: true,
SupportTemplate: false,
Type: plugins.ActionDocumentationFieldTypeString,
},
},
})
return nil
}
type actor struct{}
func (a actor) Execute(c *irc.Client, m *irc.Message, r *plugins.Rule, eventData *plugins.FieldCollection, attrs *plugins.FieldCollection) (preventCooldown bool, err error) {
msg, err := formatMessage(attrs.MustString("message", nil), m, r, eventData)
if err != nil {
if !attrs.CanString("fallback") || attrs.MustString("fallback", nil) == "" {
return false, errors.Wrap(err, "preparing response")
}
log.WithError(err).Error("Response message processing caused error, trying fallback")
if msg, err = formatMessage(attrs.MustString("fallback", nil), m, r, eventData); err != nil {
return false, errors.Wrap(err, "preparing response fallback")
}
}
toChannel := plugins.DeriveChannel(m, eventData)
if attrs.CanString("to_channel") && attrs.MustString("to_channel", nil) != "" {
toChannel = fmt.Sprintf("#%s", strings.TrimLeft(attrs.MustString("to_channel", nil), "#"))
}
ircMessage := &irc.Message{
Command: "PRIVMSG",
Params: []string{
toChannel,
msg,
},
}
if attrs.MustBool("as_reply", ptrBoolFalse) {
id, ok := m.GetTag("id")
if ok {
if ircMessage.Tags == nil {
ircMessage.Tags = make(irc.Tags)
}
ircMessage.Tags["reply-parent-msg-id"] = irc.TagValue(id)
}
}
return false, errors.Wrap(
send(ircMessage),
"sending response",
)
}
func (a actor) IsAsync() bool { return false }
func (a actor) Name() string { return actorName }
func (a actor) Validate(tplValidator plugins.TemplateValidatorFunc, attrs *plugins.FieldCollection) (err error) {
if v, err := attrs.String("message"); err != nil || v == "" {
return errors.New("message must be non-empty string")
}
for _, field := range []string{"message", "fallback"} {
if err = tplValidator(attrs.MustString(field, ptrStringEmpty)); err != nil {
return errors.Wrapf(err, "validating %s template", field)
}
}
return nil
}