package main import ( "bytes" "fmt" "regexp" "strings" "text/template" "time" "github.com/Luzifer/go_helpers/fieldcollection" "gopkg.in/irc.v4" "github.com/Luzifer/twitch-bot/v3/plugins" ) var ( // Compile-time assertion _ plugins.MsgFormatter = formatMessage stripNewline = regexp.MustCompile(`(?m)\s*\n\s*`) formatMessageFieldSetters = []func(compiledFields *fieldcollection.FieldCollection, m *irc.Message, fields *fieldcollection.FieldCollection){ formatMessageFieldChannel, formatMessageFieldMessage, formatMessageFieldMessageID, formatMessageFieldUserID, formatMessageFieldUsername, } ) func formatMessage(tplString string, m *irc.Message, r *plugins.Rule, fields *fieldcollection.FieldCollection) (string, error) { compiledFields := fieldcollection.NewFieldCollection() if config != nil { configLock.RLock() compiledFields.SetFromData(config.Variables) compiledFields.Set("permitTimeout", int64(config.PermitTimeout/time.Second)) configLock.RUnlock() } compiledFields.SetFromData(fields.Data()) for _, fn := range formatMessageFieldSetters { fn(compiledFields, m, fields) } // Template in frontend supports newlines, messages do not tplString = stripNewline.ReplaceAllString(tplString, " ") // Parse and execute template tpl, err := template. New(tplString). Funcs(tplFuncs.GetFuncMap(m, r, compiledFields)). Parse(tplString) if err != nil { return "", fmt.Errorf("parse template: %w", err) } buf := new(bytes.Buffer) if err = tpl.Execute(buf, compiledFields.Data()); err != nil { return "", fmt.Errorf("execute template: %w", err) } return strings.TrimSpace(buf.String()), nil } func formatMessageFieldChannel(compiledFields *fieldcollection.FieldCollection, m *irc.Message, fields *fieldcollection.FieldCollection) { compiledFields.Set(eventFieldChannel, plugins.DeriveChannel(m, fields)) } func formatMessageFieldMessage(compiledFields *fieldcollection.FieldCollection, m *irc.Message, _ *fieldcollection.FieldCollection) { if m == nil { return } compiledFields.Set("msg", m) } func formatMessageFieldMessageID(compiledFields *fieldcollection.FieldCollection, m *irc.Message, _ *fieldcollection.FieldCollection) { if m == nil { return } if uid := m.Tags["id"]; uid != "" { compiledFields.Set(eventFieldMessageID, uid) } } func formatMessageFieldUserID(compiledFields *fieldcollection.FieldCollection, m *irc.Message, _ *fieldcollection.FieldCollection) { if m == nil { return } if uid := m.Tags["user-id"]; uid != "" { compiledFields.Set(eventFieldUserID, uid) } } func formatMessageFieldUsername(compiledFields *fieldcollection.FieldCollection, m *irc.Message, fields *fieldcollection.FieldCollection) { compiledFields.Set("username", plugins.DeriveUser(m, fields)) } func validateTemplate(tplString string) error { // Template in frontend supports newlines, messages do not tplString = stripNewline.ReplaceAllString(tplString, " ") if _, err := template. New(tplString). Funcs(tplFuncs.GetFuncMap(nil, nil, fieldcollection.NewFieldCollection())). Parse(tplString); err != nil { return fmt.Errorf("parsing template: %w", err) } return nil }