mail, context

This commit is contained in:
Sebastian Frank 2021-08-11 11:46:05 +02:00
parent f5e83ef690
commit da1322b7cb
Signed by: apairon
GPG Key ID: A0E05A8199CE3F57
4 changed files with 149 additions and 33 deletions

View File

@ -1,3 +1,6 @@
mail:
host: localhost:25
directories: directories:
- path: /tmp/foo - path: /tmp/foo
recursive: false recursive: false
@ -5,7 +8,9 @@ directories:
pollingInterval: 60 pollingInterval: 60
regex: "/[^\\.][^/]+.xml$" regex: "/[^\\.][^/]+.xml$"
actions: actions:
- type: http - id: postXML
description: POST xml
type: http
method: post method: post
url: http://localhost:8080/api/v1/_/renz_einfo/xml url: http://localhost:8080/api/v1/_/renz_einfo/xml
header: header:
@ -13,12 +18,32 @@ directories:
ContentType: application/xml ContentType: application/xml
# content: PLAIN IS FILECONTENT # content: PLAIN IS FILECONTENT
onError: onError:
- type: move - id: moveXMLError
description: MOVE xml to error dir
type: move
to: /tmp/error/{{ filename }} to: /tmp/error/{{ filename }}
- id: mailXMLError
description: eInfo Import ERROR on POST xml
type: mail
to: sebastian@webmakers.de
subject: "{{ action.Description }}"
body: |
path: {{ path }}
event: {{ event }}
http status: {{ context.postXML.response.Status }}
http response body
------------------
{{ context.postXML.response.Body }}
from: noreply@webmakers.de
stop: true stop: true
onSuccess: onSuccess:
- type: delete - id: deleteXML
description: DELETE xml after POST
type: delete
- path: /tmp/foo - path: /tmp/foo
recursive: false recursive: false

2
go.mod
View File

@ -3,7 +3,7 @@ module gitbase.de/apairon/fstrigger
go 1.16 go 1.16
require ( require (
github.com/davecgh/go-spew v1.1.1 github.com/domodwyer/mailyak/v3 v3.3.3
github.com/flosch/pongo2/v4 v4.0.2 github.com/flosch/pongo2/v4 v4.0.2
github.com/rjeczalik/notify v0.9.2 github.com/rjeczalik/notify v0.9.2
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b

4
go.sum
View File

@ -1,5 +1,5 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/domodwyer/mailyak/v3 v3.3.3 h1:E9cjqDUiwY1QSE5G2CbWHM7EJV5FybKPHnGovc2iaA8=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/domodwyer/mailyak/v3 v3.3.3/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=

145
main.go
View File

@ -13,13 +13,16 @@ import (
"sync" "sync"
"time" "time"
"github.com/domodwyer/mailyak/v3"
"github.com/flosch/pongo2/v4" "github.com/flosch/pongo2/v4"
"github.com/rjeczalik/notify" "github.com/rjeczalik/notify"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
type ActionConfig struct { type ActionConfig struct {
Type string Id string
Type string
Description string
// http // http
Method *string Method *string
@ -30,6 +33,12 @@ type ActionConfig struct {
// move // move
To *string To *string
// mail
// To *string
Subject *string
Body *string
From *string
Stop bool Stop bool
OnSuccess []ActionConfig `yaml:"onSuccess"` OnSuccess []ActionConfig `yaml:"onSuccess"`
OnError []ActionConfig `yaml:"onError"` OnError []ActionConfig `yaml:"onError"`
@ -45,10 +54,17 @@ type DirectoryConfig struct {
Actions []ActionConfig Actions []ActionConfig
} }
type MailConfig struct {
Host *string
}
type Config struct { type Config struct {
Mail MailConfig
Directories []DirectoryConfig Directories []DirectoryConfig
} }
var conf = Config{}
var wg sync.WaitGroup var wg sync.WaitGroup
type pollInfo struct { type pollInfo struct {
@ -68,6 +84,8 @@ func (p pollInfo) Sys() interface{} {
return nil return nil
} }
type actionCtx map[string]map[string]interface{}
func startWatcher(directory *DirectoryConfig) { func startWatcher(directory *DirectoryConfig) {
c := make(chan notify.EventInfo, 1000) c := make(chan notify.EventInfo, 1000)
monitoredEvents := []notify.Event{} monitoredEvents := []notify.Event{}
@ -140,10 +158,14 @@ func startWatcher(directory *DirectoryConfig) {
if eventInfo != nil { if eventInfo != nil {
p := eventInfo.Path() p := eventInfo.Path()
log.Printf("path: %s; event: %s\n", p, eventInfo.Event().String()) eventStr := eventInfo.Event().String()
if eventInfo.Event() == 0 {
eventStr = "POLLING"
}
log.Printf("path: %s; event: %s\n", p, eventStr)
if directory._regex == nil || directory._regex.MatchString(p) { if directory._regex == nil || directory._regex.MatchString(p) {
for _, action := range directory.Actions { for _, action := range directory.Actions {
contin, _ := runAction(&action, eventInfo) contin, _ := runAction(&action, eventInfo, nil)
if !contin { if !contin {
break break
} }
@ -180,41 +202,46 @@ func startWatcher(directory *DirectoryConfig) {
} }
func runAction(action *ActionConfig, eventInfo notify.EventInfo) (contin bool, err error) { func runAction(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) (contin bool, err error) {
if ctx == nil {
ctx = make(actionCtx)
}
add2Ctx(action, ctx, "action", action)
contin = !action.Stop contin = !action.Stop
log.Printf("path: %s; action: %s; stop: %v\n", eventInfo.Path(), action.Type, !contin) log.Printf("path: %s; action: %s; stop: %v\n", eventInfo.Path(), action.Id, !contin)
switch action.Type { switch action.Type {
case "http": case "http":
err = actionHttp(action, eventInfo) err = actionHttp(action, eventInfo, ctx)
case "move": case "move":
err = actionMove(action, eventInfo) err = actionMove(action, eventInfo, ctx)
case "delete": case "delete":
err = actionDelete(action, eventInfo) err = actionDelete(action, eventInfo, ctx)
case "log": case "log":
err = actionLog(action, eventInfo) err = actionLog(action, eventInfo, ctx)
case "mail":
err = actionMail(action, eventInfo, ctx)
default: default:
err = fmt.Errorf("action type %s unknown", action.Type) err = fmt.Errorf("action type %s unknown", action.Type)
} }
if err != nil { if err != nil {
log.Printf("path: %s; action: %s; error %s", eventInfo.Path(), action.Type, err) add2Ctx(action, ctx, "error", err.Error())
log.Printf("path: %s; action: %s; error %s", eventInfo.Path(), action.Id, err)
for _, aE := range action.OnError { for _, aE := range action.OnError {
_c, errE := runAction(&aE, eventInfo) _c, _ := runAction(&aE, eventInfo, ctx)
contin = contin && _c contin = contin && _c
if errE != nil {
log.Printf("path: %s; action: %s; onError %s, error %s", eventInfo.Path(), action.Type, aE.Type, errE)
}
if !contin { if !contin {
break break
} }
} }
} else { } else {
for _, aS := range action.OnSuccess { for _, aS := range action.OnSuccess {
_c, errS := runAction(&aS, eventInfo) _c, errS := runAction(&aS, eventInfo, ctx)
contin = contin && _c contin = contin && _c
if errS != nil { if errS != nil {
log.Printf("path: %s; action: %s; onSuccess %s, error %s", eventInfo.Path(), action.Type, aS.Type, errS)
err = errS err = errS
} }
if !contin { if !contin {
@ -226,10 +253,19 @@ func runAction(action *ActionConfig, eventInfo notify.EventInfo) (contin bool, e
return contin, err return contin, err
} }
func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { func add2Ctx(action *ActionConfig, ctx actionCtx, key string, val interface{}) {
if action.Id != "" {
if ctx[action.Id] == nil {
ctx[action.Id] = make(map[string]interface{})
}
ctx[action.Id][key] = val
}
}
func actionHttp(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
method := "POST" method := "POST"
if action.Method != nil { if action.Method != nil {
m, err := tpl2String(*action.Method, action, eventInfo) m, err := tpl2String(*action.Method, action, eventInfo, ctx)
if err != nil { if err != nil {
return err return err
} }
@ -238,7 +274,7 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
if action.URL == nil { if action.URL == nil {
return fmt.Errorf("missing url in http action") return fmt.Errorf("missing url in http action")
} }
url, err := tpl2String(*action.URL, action, eventInfo) url, err := tpl2String(*action.URL, action, eventInfo, ctx)
if err != nil { if err != nil {
return err return err
} }
@ -253,7 +289,7 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
} }
postData = bytes.NewBuffer(postBytes) postData = bytes.NewBuffer(postBytes)
} else { } else {
p, err := tpl2String(*action.Content, action, eventInfo) p, err := tpl2String(*action.Content, action, eventInfo, ctx)
if err != nil { if err != nil {
return err return err
} }
@ -281,6 +317,12 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
fmt.Println(string(body)) fmt.Println(string(body))
defer resp.Body.Close() defer resp.Body.Close()
add2Ctx(action, ctx, "response", map[string]interface{}{
"Status": resp.Status,
"StatusCode": resp.StatusCode,
"Body": string(body),
})
if resp.StatusCode >= 400 { if resp.StatusCode >= 400 {
return fmt.Errorf("response status %s", resp.Status) return fmt.Errorf("response status %s", resp.Status)
} }
@ -288,12 +330,12 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
return nil return nil
} }
func actionMove(action *ActionConfig, eventInfo notify.EventInfo) error { func actionMove(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
if action.To == nil { if action.To == nil {
return fmt.Errorf("missing to: as destination for move action") return fmt.Errorf("missing to: as destination for move action")
} }
to, err := tpl2String(*action.To, action, eventInfo) to, err := tpl2String(*action.To, action, eventInfo, ctx)
if err != nil { if err != nil {
return err return err
} }
@ -302,11 +344,11 @@ func actionMove(action *ActionConfig, eventInfo notify.EventInfo) error {
return err return err
} }
func actionDelete(action *ActionConfig, eventInfo notify.EventInfo) error { func actionDelete(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
return os.Remove(eventInfo.Path()) return os.Remove(eventInfo.Path())
} }
func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error { func actionLog(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
var logstr string var logstr string
if action.Content != nil { if action.Content != nil {
logstr = *action.Content logstr = *action.Content
@ -317,7 +359,55 @@ func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error {
return nil return nil
} }
func tpl2String(tpl string, action *ActionConfig, eventInfo notify.EventInfo) (string, error) { func actionMail(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
if conf.Mail.Host == nil {
return fmt.Errorf("missing host in mail: config")
}
if action.To == nil {
return fmt.Errorf("missing to: as recipient mail address")
}
if action.Subject == nil {
return fmt.Errorf("missing subject: action")
}
if action.Body == nil {
return fmt.Errorf("missing body: action")
}
if action.From == nil {
return fmt.Errorf("missing from: in action")
}
mail := mailyak.New(*conf.Mail.Host, nil)
to, err := tpl2String(*action.To, action, eventInfo, ctx)
if err != nil {
return err
}
mail.To(to)
from, err := tpl2String(*action.From, action, eventInfo, ctx)
if err != nil {
return err
}
mail.From(from)
mail.FromName("fstrigger")
subject, err := tpl2String(*action.Subject, action, eventInfo, ctx)
if err != nil {
return err
}
mail.Subject(subject)
body, err := tpl2String(*action.Body, action, eventInfo, ctx)
if err != nil {
return err
}
mail.Plain().Set(body)
return mail.Send()
}
func tpl2String(tpl string, action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) (string, error) {
_tpl, err := pongo2.FromString(tpl) _tpl, err := pongo2.FromString(tpl)
if err != nil { if err != nil {
return "", err return "", err
@ -328,13 +418,14 @@ func tpl2String(tpl string, action *ActionConfig, eventInfo notify.EventInfo) (s
"path": p, "path": p,
"dirname": filepath.Dir(p), "dirname": filepath.Dir(p),
"filename": filepath.Base(p), "filename": filepath.Base(p),
"event": eventInfo.Event().String(),
"action": action,
"context": ctx,
}) })
} }
func main() { func main() {
conf := Config{}
confDat, err := ioutil.ReadFile("./config.yml") confDat, err := ioutil.ReadFile("./config.yml")
if err != nil { if err != nil {
log.Fatalf("error %v", err) log.Fatalf("error %v", err)