Improve config handling and move types to types.go

This commit is contained in:
Elara 2023-08-19 06:56:42 -07:00
parent bc91986e6c
commit 53cc18e382
3 changed files with 57 additions and 50 deletions

View File

@ -12,7 +12,7 @@ import (
"go.elara.ws/pcre" "go.elara.ws/pcre"
) )
type Config struct { type ConfigFile struct {
Lemmy struct { Lemmy struct {
InstanceURL string `toml:"instanceURL"` InstanceURL string `toml:"instanceURL"`
Account struct { Account struct {
@ -28,16 +28,16 @@ type Reply struct {
Msg string `toml:"msg"` Msg string `toml:"msg"`
} }
var ( type Config struct {
cfg = Config{} ConfigFile *ConfigFile
compiledRegexes = map[string]*pcre.Regexp{} Regexes map[string]*pcre.Regexp
compiledTmpls = map[string]*template.Template{} Tmpls map[string]*template.Template
) }
func loadConfig(path string) error { func loadConfig(path string) (Config, error) {
fi, err := os.Stat(path) fi, err := os.Stat(path)
if err != nil { if err != nil {
return err return Config{}, err
} }
if fi.Mode().Perm() != 0o600 { if fi.Mode().Perm() != 0o600 {
@ -46,24 +46,29 @@ func loadConfig(path string) error {
fl, err := os.Open(path) fl, err := os.Open(path)
if err != nil { if err != nil {
return err return Config{}, err
} }
err = toml.NewDecoder(fl).Decode(&cfg) cfgFile := &ConfigFile{}
err = toml.NewDecoder(fl).Decode(cfgFile)
if err != nil { if err != nil {
return err return Config{}, err
} }
err = compileReplies(cfg.Replies) compiledRegexes, compiledTmpls, err := compileReplies(cfgFile.Replies)
if err != nil { if err != nil {
return err return Config{}, err
} }
validateConfig() cfg := Config{cfgFile, compiledRegexes, compiledTmpls}
return nil validateConfig(cfg)
return cfg, nil
} }
func compileReplies(replies []Reply) error { func compileReplies(replies []Reply) (map[string]*pcre.Regexp, map[string]*template.Template, error) {
compiledRegexes := map[string]*pcre.Regexp{}
compiledTmpls := map[string]*template.Template{}
for i, reply := range replies { for i, reply := range replies {
if _, ok := compiledRegexes[reply.Regex]; ok { if _, ok := compiledRegexes[reply.Regex]; ok {
continue continue
@ -71,7 +76,7 @@ func compileReplies(replies []Reply) error {
re, err := pcre.Compile(reply.Regex) re, err := pcre.Compile(reply.Regex)
if err != nil { if err != nil {
return err return nil, nil, err
} }
compiledRegexes[reply.Regex] = re compiledRegexes[reply.Regex] = re
@ -80,21 +85,22 @@ func compileReplies(replies []Reply) error {
Funcs(sprig.TxtFuncMap()). Funcs(sprig.TxtFuncMap()).
Parse(reply.Msg) Parse(reply.Msg)
if err != nil { if err != nil {
return err return nil, nil, err
} }
compiledTmpls[reply.Regex] = tmpl compiledTmpls[reply.Regex] = tmpl
} }
return nil
return compiledRegexes, compiledTmpls, nil
} }
func validateConfig() { func validateConfig(cfg Config) {
_, err := url.Parse(cfg.Lemmy.InstanceURL) _, err := url.Parse(cfg.ConfigFile.Lemmy.InstanceURL)
if err != nil { if err != nil {
log.Fatal("Lemmy instance URL is not valid").Err(err).Send() log.Fatal("Lemmy instance URL is not valid").Err(err).Send()
} }
for i, reply := range cfg.Replies { for i, reply := range cfg.ConfigFile.Replies {
re := compiledRegexes[reply.Regex] re := cfg.Regexes[reply.Regex]
if re.MatchString(reply.Msg) { if re.MatchString(reply.Msg) {
log.Fatal("Regular expression matches message. This may create an infinite loop. Refusing to start.").Int("reply-index", i).Send() log.Fatal("Regular expression matches message. This may create an infinite loop. Refusing to start.").Int("reply-index", i).Send()

39
main.go
View File

@ -19,21 +19,6 @@ import (
_ "modernc.org/sqlite" _ "modernc.org/sqlite"
) )
type Submatches []string
func (sm Submatches) Item(i int) string {
return sm[i]
}
type TmplContext struct {
Matches []Submatches
Type string
}
func (tc TmplContext) Match(i, j int) string {
return tc.Matches[i][j]
}
//go:embed sql/schema.sql //go:embed sql/schema.sql
var schema string var schema string
@ -61,19 +46,19 @@ func main() {
ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) ctx, cancel := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer cancel() defer cancel()
err := loadConfig(*configPath) cfg, err := loadConfig(*configPath)
if err != nil { if err != nil {
log.Fatal("Error loading config file").Err(err).Send() log.Fatal("Error loading config file").Err(err).Send()
} }
c, err := lemmy.New(cfg.Lemmy.InstanceURL) c, err := lemmy.New(cfg.ConfigFile.Lemmy.InstanceURL)
if err != nil { if err != nil {
log.Fatal("Error creating new Lemmy API client").Err(err).Send() log.Fatal("Error creating new Lemmy API client").Err(err).Send()
} }
err = c.ClientLogin(ctx, types.Login{ err = c.ClientLogin(ctx, types.Login{
UsernameOrEmail: cfg.Lemmy.Account.UserOrEmail, UsernameOrEmail: cfg.ConfigFile.Lemmy.Account.UserOrEmail,
Password: cfg.Lemmy.Account.Password, Password: cfg.ConfigFile.Lemmy.Account.Password,
}) })
if err != nil { if err != nil {
log.Fatal("Error logging in to Lemmy instance").Err(err).Send() log.Fatal("Error logging in to Lemmy instance").Err(err).Send()
@ -87,10 +72,10 @@ func main() {
go commentReplyWorker(ctx, c, replyCh) go commentReplyWorker(ctx, c, replyCh)
} }
commentWorker(ctx, c, replyCh) commentWorker(ctx, c, cfg, replyCh)
} }
func commentWorker(ctx context.Context, c *lemmy.Client, replyCh chan<- replyJob) { func commentWorker(ctx context.Context, c *lemmy.Client, cfg Config, replyCh chan<- replyJob) {
db, err := sql.Open("sqlite", "replied.db") db, err := sql.Open("sqlite", "replied.db")
if err != nil { if err != nil {
log.Fatal("Error opening reply database").Err(err).Send() log.Fatal("Error opening reply database").Err(err).Send()
@ -128,8 +113,8 @@ func commentWorker(ctx context.Context, c *lemmy.Client, replyCh chan<- replyJob
continue continue
} }
for i, reply := range cfg.Replies { for i, reply := range cfg.ConfigFile.Replies {
re := compiledRegexes[reply.Regex] re := cfg.Regexes[reply.Regex]
if !re.MatchString(c.Comment.Content) { if !re.MatchString(c.Comment.Content) {
continue continue
} }
@ -145,7 +130,7 @@ func commentWorker(ctx context.Context, c *lemmy.Client, replyCh chan<- replyJob
} }
matches := re.FindAllStringSubmatch(c.Comment.Content, -1) matches := re.FindAllStringSubmatch(c.Comment.Content, -1)
job.Content, err = executeTmpl(compiledTmpls[reply.Regex], TmplContext{ job.Content, err = executeTmpl(cfg.Tmpls[reply.Regex], TmplContext{
Matches: toSubmatches(matches), Matches: toSubmatches(matches),
Type: "comment", Type: "comment",
}) })
@ -197,8 +182,8 @@ func commentWorker(ctx context.Context, c *lemmy.Client, replyCh chan<- replyJob
} }
body := p.Post.URL.ValueOr("") + "\n\n" + p.Post.Body.ValueOr("") body := p.Post.URL.ValueOr("") + "\n\n" + p.Post.Body.ValueOr("")
for i, reply := range cfg.Replies { for i, reply := range cfg.ConfigFile.Replies {
re := compiledRegexes[reply.Regex] re := cfg.Regexes[reply.Regex]
if !re.MatchString(body) { if !re.MatchString(body) {
continue continue
} }
@ -211,7 +196,7 @@ func commentWorker(ctx context.Context, c *lemmy.Client, replyCh chan<- replyJob
job := replyJob{PostID: p.Post.ID} job := replyJob{PostID: p.Post.ID}
matches := re.FindAllStringSubmatch(body, -1) matches := re.FindAllStringSubmatch(body, -1)
job.Content, err = executeTmpl(compiledTmpls[reply.Regex], TmplContext{ job.Content, err = executeTmpl(cfg.Tmpls[reply.Regex], TmplContext{
Matches: toSubmatches(matches), Matches: toSubmatches(matches),
Type: "post", Type: "post",
}) })

16
types.go Normal file
View File

@ -0,0 +1,16 @@
package main
type Submatches []string
func (sm Submatches) Item(i int) string {
return sm[i]
}
type TmplContext struct {
Matches []Submatches
Type string
}
func (tc TmplContext) Match(i, j int) string {
return tc.Matches[i][j]
}