From da1322b7cb42e8aff2df86f88c8cb5deb86a2b73 Mon Sep 17 00:00:00 2001 From: Sebastian Frank Date: Wed, 11 Aug 2021 11:46:05 +0200 Subject: [PATCH] mail, context --- config.yml | 31 ++++++++++-- go.mod | 2 +- go.sum | 4 +- main.go | 145 +++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 149 insertions(+), 33 deletions(-) diff --git a/config.yml b/config.yml index 0e7ac79..82dc9e5 100644 --- a/config.yml +++ b/config.yml @@ -1,3 +1,6 @@ +mail: + host: localhost:25 + directories: - path: /tmp/foo recursive: false @@ -5,7 +8,9 @@ directories: pollingInterval: 60 regex: "/[^\\.][^/]+.xml$" actions: - - type: http + - id: postXML + description: POST xml + type: http method: post url: http://localhost:8080/api/v1/_/renz_einfo/xml header: @@ -13,12 +18,32 @@ directories: ContentType: application/xml # content: PLAIN IS FILECONTENT onError: - - type: move + - id: moveXMLError + description: MOVE xml to error dir + type: move 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 onSuccess: - - type: delete + - id: deleteXML + description: DELETE xml after POST + type: delete - path: /tmp/foo recursive: false diff --git a/go.mod b/go.mod index e4c7213..55ab5d2 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module gitbase.de/apairon/fstrigger go 1.16 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/rjeczalik/notify v0.9.2 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 1da1ac7..bf34a32 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/domodwyer/mailyak/v3 v3.3.3 h1:E9cjqDUiwY1QSE5G2CbWHM7EJV5FybKPHnGovc2iaA8= +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/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/main.go b/main.go index 6808c71..01808ee 100644 --- a/main.go +++ b/main.go @@ -13,13 +13,16 @@ import ( "sync" "time" + "github.com/domodwyer/mailyak/v3" "github.com/flosch/pongo2/v4" "github.com/rjeczalik/notify" "gopkg.in/yaml.v3" ) type ActionConfig struct { - Type string + Id string + Type string + Description string // http Method *string @@ -30,6 +33,12 @@ type ActionConfig struct { // move To *string + // mail + // To *string + Subject *string + Body *string + From *string + Stop bool OnSuccess []ActionConfig `yaml:"onSuccess"` OnError []ActionConfig `yaml:"onError"` @@ -45,10 +54,17 @@ type DirectoryConfig struct { Actions []ActionConfig } +type MailConfig struct { + Host *string +} + type Config struct { + Mail MailConfig Directories []DirectoryConfig } +var conf = Config{} + var wg sync.WaitGroup type pollInfo struct { @@ -68,6 +84,8 @@ func (p pollInfo) Sys() interface{} { return nil } +type actionCtx map[string]map[string]interface{} + func startWatcher(directory *DirectoryConfig) { c := make(chan notify.EventInfo, 1000) monitoredEvents := []notify.Event{} @@ -140,10 +158,14 @@ func startWatcher(directory *DirectoryConfig) { if eventInfo != nil { 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) { for _, action := range directory.Actions { - contin, _ := runAction(&action, eventInfo) + contin, _ := runAction(&action, eventInfo, nil) if !contin { 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 - 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 { case "http": - err = actionHttp(action, eventInfo) + err = actionHttp(action, eventInfo, ctx) case "move": - err = actionMove(action, eventInfo) + err = actionMove(action, eventInfo, ctx) case "delete": - err = actionDelete(action, eventInfo) + err = actionDelete(action, eventInfo, ctx) case "log": - err = actionLog(action, eventInfo) + err = actionLog(action, eventInfo, ctx) + case "mail": + err = actionMail(action, eventInfo, ctx) default: err = fmt.Errorf("action type %s unknown", action.Type) } 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 { - _c, errE := runAction(&aE, eventInfo) + _c, _ := runAction(&aE, eventInfo, ctx) 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 { break } } } else { for _, aS := range action.OnSuccess { - _c, errS := runAction(&aS, eventInfo) + _c, errS := runAction(&aS, eventInfo, ctx) contin = contin && _c if errS != nil { - log.Printf("path: %s; action: %s; onSuccess %s, error %s", eventInfo.Path(), action.Type, aS.Type, errS) err = errS } if !contin { @@ -226,10 +253,19 @@ func runAction(action *ActionConfig, eventInfo notify.EventInfo) (contin bool, e 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" if action.Method != nil { - m, err := tpl2String(*action.Method, action, eventInfo) + m, err := tpl2String(*action.Method, action, eventInfo, ctx) if err != nil { return err } @@ -238,7 +274,7 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { if action.URL == nil { 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 { return err } @@ -253,7 +289,7 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { } postData = bytes.NewBuffer(postBytes) } else { - p, err := tpl2String(*action.Content, action, eventInfo) + p, err := tpl2String(*action.Content, action, eventInfo, ctx) if err != nil { return err } @@ -281,6 +317,12 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { fmt.Println(string(body)) defer resp.Body.Close() + add2Ctx(action, ctx, "response", map[string]interface{}{ + "Status": resp.Status, + "StatusCode": resp.StatusCode, + "Body": string(body), + }) + if resp.StatusCode >= 400 { return fmt.Errorf("response status %s", resp.Status) } @@ -288,12 +330,12 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { return nil } -func actionMove(action *ActionConfig, eventInfo notify.EventInfo) error { +func actionMove(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error { if action.To == nil { 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 { return err } @@ -302,11 +344,11 @@ func actionMove(action *ActionConfig, eventInfo notify.EventInfo) error { 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()) } -func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error { +func actionLog(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error { var logstr string if action.Content != nil { logstr = *action.Content @@ -317,7 +359,55 @@ func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error { 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) if err != nil { return "", err @@ -328,13 +418,14 @@ func tpl2String(tpl string, action *ActionConfig, eventInfo notify.EventInfo) (s "path": p, "dirname": filepath.Dir(p), "filename": filepath.Base(p), + "event": eventInfo.Event().String(), + "action": action, + "context": ctx, }) } func main() { - conf := Config{} - confDat, err := ioutil.ReadFile("./config.yml") if err != nil { log.Fatalf("error %v", err)