This commit is contained in:
Sebastian Frank 2021-08-10 18:31:29 +02:00
parent 70255bc2a2
commit f5e83ef690
Signed by: apairon
GPG Key ID: A0E05A8199CE3F57
4 changed files with 147 additions and 58 deletions

View File

@ -2,6 +2,7 @@ directories:
- path: /tmp/foo - path: /tmp/foo
recursive: false recursive: false
events: ["CLOSE_WRITE", "MOVED_TO"] events: ["CLOSE_WRITE", "MOVED_TO"]
pollingInterval: 60
regex: "/[^\\.][^/]+.xml$" regex: "/[^\\.][^/]+.xml$"
actions: actions:
- type: http - type: http
@ -12,25 +13,31 @@ directories:
ContentType: application/xml ContentType: application/xml
# content: PLAIN IS FILECONTENT # content: PLAIN IS FILECONTENT
onError: onError:
type: move - type: move
to: /tmp/error/{{ filename }} to: /tmp/error/{{ filename }}
stop: true stop: true
onSuccess:
- type: delete
- path: /tmp/foo
recursive: false
events: ["CLOSE_WRITE", "MOVED_TO"]
regex: "/[^\\.][^/]+.(png|jpe?g|pdf)$"
actions:
- type: http - type: http
method: post method: post
url: http://localhost:8080/api/v1/_/renz_einfo/operation-file url: http://localhost:8080/api/v1/_/renz_einfo/operation-file
header: header:
Token: abc Token: Ksi02vcaHHasd1sjYxiq4J
ContentType: application/json Content-Type: application/json
content: | content: |
{ {
"filename": "{{ .Name }}" "filename": "{{ filename }}"
} }
onError: onError:
type: move - type: move
to: /tmp/error/{{ filename }} to: /tmp/error/{{ filename }}
stop: true stop: true
- type: delete
- type: log - type: log

1
go.mod
View File

@ -3,6 +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/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

2
go.sum
View File

@ -1,3 +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/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=

113
main.go
View File

@ -31,14 +31,15 @@ type ActionConfig struct {
To *string To *string
Stop bool Stop bool
OnSuccess *ActionConfig `yaml:"onSuccess"` OnSuccess []ActionConfig `yaml:"onSuccess"`
OnError *ActionConfig `yaml:"onError"` OnError []ActionConfig `yaml:"onError"`
} }
type DirectoryConfig struct { type DirectoryConfig struct {
Path string Path string
Recursive bool Recursive bool
Events []string Events []string
PollingInterval *int64 `yaml:"pollingInterval"`
Regex *string Regex *string
_regex *regexp.Regexp _regex *regexp.Regexp
Actions []ActionConfig Actions []ActionConfig
@ -50,8 +51,25 @@ type Config struct {
var wg sync.WaitGroup var wg sync.WaitGroup
type pollInfo struct {
path string
event notify.Event
}
func (p pollInfo) Path() string {
return p.path
}
func (p pollInfo) Event() notify.Event {
return p.event
}
func (p pollInfo) Sys() interface{} {
return nil
}
func startWatcher(directory *DirectoryConfig) { func startWatcher(directory *DirectoryConfig) {
c := make(chan notify.EventInfo, 10) c := make(chan notify.EventInfo, 1000)
monitoredEvents := []notify.Event{} monitoredEvents := []notify.Event{}
for _, e := range directory.Events { for _, e := range directory.Events {
switch e { switch e {
@ -98,15 +116,29 @@ func startWatcher(directory *DirectoryConfig) {
go func(directory *DirectoryConfig, monitoredEvents []notify.Event) { go func(directory *DirectoryConfig, monitoredEvents []notify.Event) {
defer wg.Done() defer wg.Done()
log.Printf("watching %s for %v\n", directory.Path, directory.Events) log.Printf("watching %s for %v, regex %s\n", directory.Path, directory.Events, *directory.Regex)
if err := notify.Watch(directory.Path, c, monitoredEvents...); err != nil { if err := notify.Watch(directory.Path, c, monitoredEvents...); err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer notify.Stop(c) defer notify.Stop(c)
firstRun := true
for { for {
eventInfo := <-c var eventInfo notify.EventInfo
if directory.PollingInterval != nil {
if !firstRun {
select {
case eventInfo = <-c: // event
case <-time.After(time.Second * time.Duration(*directory.PollingInterval)): // timeout for polling
}
}
firstRun = false // do polling as init
} else {
eventInfo = <-c
}
if eventInfo != nil {
p := eventInfo.Path() p := eventInfo.Path()
log.Printf("path: %s; event: %s\n", p, eventInfo.Event().String()) log.Printf("path: %s; event: %s\n", p, eventInfo.Event().String())
if directory._regex == nil || directory._regex.MatchString(p) { if directory._regex == nil || directory._regex.MatchString(p) {
@ -120,6 +152,30 @@ func startWatcher(directory *DirectoryConfig) {
log.Printf("path: %s; no regex match\n", p) log.Printf("path: %s; no regex match\n", p)
} }
} }
if directory.PollingInterval != nil && len(c) == 0 {
// polling only while queue is empty
files, err := ioutil.ReadDir(directory.Path)
if err != nil {
log.Printf("path: %s; polling error: %s", directory.Path, err)
}
for _, f := range files {
p := directory.Path + "/" + f.Name()
if directory._regex == nil || directory._regex.MatchString(p) {
pollI := pollInfo{
path: p,
event: 0,
}
select {
case c <- pollI:
default:
}
} else {
log.Printf("path: %s; no regex match (polling)\n", p)
}
}
}
}
}(directory, monitoredEvents) }(directory, monitoredEvents)
} }
@ -143,21 +199,29 @@ func runAction(action *ActionConfig, eventInfo notify.EventInfo) (contin bool, e
if err != nil { if err != nil {
log.Printf("path: %s; action: %s; error %s", eventInfo.Path(), action.Type, err) log.Printf("path: %s; action: %s; error %s", eventInfo.Path(), action.Type, err)
if action.OnError != nil { for _, aE := range action.OnError {
_c, errE := runAction(action.OnError, eventInfo) _c, errE := runAction(&aE, eventInfo)
contin = contin && _c contin = contin && _c
if errE != nil { if errE != nil {
log.Printf("path: %s; action: %s; onError %s, error %s", eventInfo.Path(), action.Type, action.OnError.Type, errE) log.Printf("path: %s; action: %s; onError %s, error %s", eventInfo.Path(), action.Type, aE.Type, errE)
}
if !contin {
break
} }
} }
} else if err == nil && action.OnSuccess != nil { } else {
_c, errS := runAction(action.OnSuccess, eventInfo) for _, aS := range action.OnSuccess {
_c, errS := runAction(&aS, eventInfo)
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, action.OnError.Type, errS) log.Printf("path: %s; action: %s; onSuccess %s, error %s", eventInfo.Path(), action.Type, aS.Type, errS)
}
err = errS err = errS
} }
if !contin {
break
}
}
}
return contin, err return contin, err
} }
@ -165,11 +229,19 @@ func runAction(action *ActionConfig, eventInfo notify.EventInfo) (contin bool, e
func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error { func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
method := "POST" method := "POST"
if action.Method != nil { if action.Method != nil {
method = strings.ToUpper(*action.Method) m, err := tpl2String(*action.Method, action, eventInfo)
if err != nil {
return err
}
method = strings.ToUpper(m)
} }
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)
if err != nil {
return err
}
postData := bytes.NewBuffer([]byte{}) postData := bytes.NewBuffer([]byte{})
if method != "GET" { if method != "GET" {
@ -180,11 +252,18 @@ func actionHttp(action *ActionConfig, eventInfo notify.EventInfo) error {
return nil return nil
} }
postData = bytes.NewBuffer(postBytes) postData = bytes.NewBuffer(postBytes)
} else {
p, err := tpl2String(*action.Content, action, eventInfo)
if err != nil {
return err
}
log.Println("BODY: ", p)
postData = bytes.NewBufferString(p)
} }
} }
log.Printf("%s %s", method, *action.URL) log.Printf("%s %s", method, url)
req, err := http.NewRequest(method, *action.URL, postData) req, err := http.NewRequest(method, url, postData)
if err != nil { if err != nil {
return err return err
} }
@ -224,8 +303,7 @@ func actionMove(action *ActionConfig, eventInfo notify.EventInfo) error {
} }
func actionDelete(action *ActionConfig, eventInfo notify.EventInfo) error { func actionDelete(action *ActionConfig, eventInfo notify.EventInfo) error {
log.Println("DELETE") return os.Remove(eventInfo.Path())
return nil
} }
func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error { func actionLog(action *ActionConfig, eventInfo notify.EventInfo) error {
@ -268,6 +346,7 @@ func main() {
} }
for _, directory := range conf.Directories { for _, directory := range conf.Directories {
directory := directory
startWatcher(&directory) startWatcher(&directory)
} }