2021-08-10 16:56:44 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2021-12-22 10:50:15 +01:00
|
|
|
"io"
|
2021-08-10 16:56:44 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2021-12-22 12:04:24 +01:00
|
|
|
"os/exec"
|
2021-08-10 16:56:44 +02:00
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2021-09-07 18:24:30 +02:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
2021-08-11 11:46:05 +02:00
|
|
|
"github.com/domodwyer/mailyak/v3"
|
2021-08-10 16:56:44 +02:00
|
|
|
"github.com/flosch/pongo2/v4"
|
|
|
|
"github.com/rjeczalik/notify"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ActionConfig struct {
|
2021-08-11 11:46:05 +02:00
|
|
|
Id string
|
|
|
|
Type string
|
|
|
|
Description string
|
2021-08-10 16:56:44 +02:00
|
|
|
|
|
|
|
// http
|
|
|
|
Method *string
|
|
|
|
URL *string
|
|
|
|
Content *string
|
|
|
|
Header map[string]string
|
|
|
|
|
2021-12-22 10:50:15 +01:00
|
|
|
// move, copy
|
|
|
|
To *string
|
|
|
|
FileMode *os.FileMode
|
2021-08-10 16:56:44 +02:00
|
|
|
|
2021-08-12 16:48:38 +02:00
|
|
|
// mdir
|
|
|
|
Path *string
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
// mail
|
|
|
|
// To *string
|
|
|
|
Subject *string
|
|
|
|
Body *string
|
|
|
|
From *string
|
|
|
|
|
2021-12-22 12:04:24 +01:00
|
|
|
// command
|
|
|
|
Command *string
|
|
|
|
Args []string
|
|
|
|
|
2021-12-22 12:25:33 +01:00
|
|
|
// sleep
|
|
|
|
Duration *int
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
Stop bool
|
2021-08-10 18:31:29 +02:00
|
|
|
OnSuccess []ActionConfig `yaml:"onSuccess"`
|
|
|
|
OnError []ActionConfig `yaml:"onError"`
|
2021-08-12 16:48:38 +02:00
|
|
|
|
2021-09-07 18:11:31 +02:00
|
|
|
Directory *DirectoryConfig `yaml:"-"`
|
|
|
|
Parent *ActionConfig `yaml:"-"`
|
|
|
|
Error error `yaml:"-"`
|
|
|
|
ErrorString string `yaml:"-"`
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type DirectoryConfig struct {
|
2021-08-10 18:31:29 +02:00
|
|
|
Path string
|
|
|
|
Recursive bool
|
|
|
|
Events []string
|
|
|
|
PollingInterval *int64 `yaml:"pollingInterval"`
|
|
|
|
Regex *string
|
2021-09-07 18:24:30 +02:00
|
|
|
IgnoreMissing bool `yaml:"ignoreMissing"`
|
2021-08-10 18:31:29 +02:00
|
|
|
_regex *regexp.Regexp
|
2021-08-12 16:48:38 +02:00
|
|
|
_regexMatches []string
|
2021-08-10 18:31:29 +02:00
|
|
|
Actions []ActionConfig
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
type MailConfig struct {
|
|
|
|
Host *string
|
|
|
|
}
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
type Config struct {
|
2021-08-11 11:46:05 +02:00
|
|
|
Mail MailConfig
|
2021-08-10 16:56:44 +02:00
|
|
|
Directories []DirectoryConfig
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
var conf = Config{}
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
2021-08-10 18:31:29 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
type actionCtx map[string]map[string]interface{}
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
func startWatcher(directory *DirectoryConfig) {
|
2021-08-10 18:31:29 +02:00
|
|
|
c := make(chan notify.EventInfo, 1000)
|
2021-08-10 16:56:44 +02:00
|
|
|
monitoredEvents := []notify.Event{}
|
|
|
|
for _, e := range directory.Events {
|
|
|
|
switch e {
|
|
|
|
case "CREATE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.Create)
|
|
|
|
case "REMOVE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.Remove)
|
|
|
|
case "WRITE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.Write)
|
|
|
|
case "RENAME":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.Rename)
|
|
|
|
case "ACCESS":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InAccess)
|
|
|
|
case "MODIFY":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InModify)
|
|
|
|
case "ATTRIB":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InAttrib)
|
|
|
|
case "CLOSE_WRITE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InCloseWrite)
|
|
|
|
case "CLOSE_NOWRITE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InCloseNowrite)
|
|
|
|
case "OPEN":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InOpen)
|
|
|
|
case "MOVED_FROM":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InMovedFrom)
|
|
|
|
case "MOVED_TO":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InMovedTo)
|
|
|
|
case "DELETE":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InDelete)
|
|
|
|
case "DELETE_SELF":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InDeleteSelf)
|
|
|
|
case "MOVE_SELF":
|
|
|
|
monitoredEvents = append(monitoredEvents, notify.InMoveSelf)
|
|
|
|
default:
|
|
|
|
log.Fatalf("event %s unknown", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if directory.Regex != nil {
|
|
|
|
directory._regex = regexp.MustCompile(*directory.Regex)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
go func(directory *DirectoryConfig, monitoredEvents []notify.Event) {
|
|
|
|
defer wg.Done()
|
|
|
|
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ INFO ] path=\"%s\" watching=\"%v\" regex \"%s\"\n", directory.Path, directory.Events, *directory.Regex)
|
2021-08-10 16:56:44 +02:00
|
|
|
|
|
|
|
if err := notify.Watch(directory.Path, c, monitoredEvents...); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer notify.Stop(c)
|
|
|
|
|
2021-08-10 18:31:29 +02:00
|
|
|
firstRun := true
|
2021-08-10 16:56:44 +02:00
|
|
|
for {
|
2021-08-10 18:31:29 +02:00
|
|
|
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
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-10 18:31:29 +02:00
|
|
|
firstRun = false // do polling as init
|
2021-08-10 16:56:44 +02:00
|
|
|
} else {
|
2021-08-10 18:31:29 +02:00
|
|
|
eventInfo = <-c
|
|
|
|
}
|
|
|
|
|
|
|
|
if eventInfo != nil {
|
|
|
|
p := eventInfo.Path()
|
2021-08-11 11:46:05 +02:00
|
|
|
eventStr := eventInfo.Event().String()
|
|
|
|
if eventInfo.Event() == 0 {
|
|
|
|
eventStr = "POLLING"
|
|
|
|
}
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ INFO ] path=\"%s\" event=\"%s\"\n", p, eventStr)
|
2021-08-12 16:48:38 +02:00
|
|
|
if directory._regex != nil {
|
|
|
|
directory._regexMatches = directory._regex.FindStringSubmatch(p)
|
|
|
|
}
|
|
|
|
if directory._regex == nil || directory._regexMatches != nil {
|
2021-09-07 18:15:55 +02:00
|
|
|
var missing bool
|
2021-09-07 18:09:05 +02:00
|
|
|
if directory.IgnoreMissing {
|
2021-09-07 18:15:55 +02:00
|
|
|
if _, statErr := os.Stat(p); os.IsNotExist(statErr) {
|
|
|
|
missing = true
|
|
|
|
log.Printf("[ INFO ] path=\"%s\" missing=\"true\"\n", p)
|
|
|
|
}
|
2021-09-07 18:09:05 +02:00
|
|
|
}
|
2021-09-07 18:15:55 +02:00
|
|
|
if directory.IgnoreMissing || !missing {
|
2021-09-07 18:09:05 +02:00
|
|
|
for _, action := range directory.Actions {
|
|
|
|
action.Directory = directory
|
|
|
|
contin, _ := runAction(&action, eventInfo, nil)
|
|
|
|
if !contin {
|
|
|
|
break
|
|
|
|
}
|
2021-08-10 18:31:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ INFO ] path=\"%s\" info=\"no regex match\"\n", p)
|
2021-08-10 18:31:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if directory.PollingInterval != nil && len(c) == 0 {
|
|
|
|
// polling only while queue is empty
|
|
|
|
files, err := ioutil.ReadDir(directory.Path)
|
|
|
|
if err != nil {
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ ERROR ] path=\"%s\" polling=\"true\" error=\"%s\"", directory.Path, err)
|
2021-08-10 18:31:29 +02:00
|
|
|
}
|
|
|
|
for _, f := range files {
|
|
|
|
p := directory.Path + "/" + f.Name()
|
|
|
|
if directory._regex == nil || directory._regex.MatchString(p) {
|
2021-08-16 20:30:00 +02:00
|
|
|
if time.Now().Add(-1 * time.Minute).After(f.ModTime()) {
|
|
|
|
pollI := pollInfo{
|
|
|
|
path: p,
|
|
|
|
event: 0,
|
|
|
|
}
|
|
|
|
select {
|
|
|
|
case c <- pollI:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Printf("[ INFO ] path=\"%s\" polling=\"true\" info=\"ignoring, too young\"\n", p)
|
2021-08-10 18:31:29 +02:00
|
|
|
}
|
|
|
|
} else {
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ INFO ] path=\"%s\" polling=\"true\" info=\"no regex match\"\n", p)
|
2021-08-10 18:31:29 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}(directory, monitoredEvents)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
func runAction(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) (contin bool, err error) {
|
|
|
|
if ctx == nil {
|
|
|
|
ctx = make(actionCtx)
|
|
|
|
}
|
|
|
|
add2Ctx(action, ctx, "action", action)
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
contin = !action.Stop
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ INFO ] path=\"%s\" action=\"%s\" stop=\"%v\"\n", eventInfo.Path(), action.Id, !contin)
|
2021-08-10 16:56:44 +02:00
|
|
|
|
|
|
|
switch action.Type {
|
|
|
|
case "http":
|
2021-08-11 11:46:05 +02:00
|
|
|
err = actionHttp(action, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
case "move":
|
2021-08-11 11:46:05 +02:00
|
|
|
err = actionMove(action, eventInfo, ctx)
|
2021-12-22 10:50:15 +01:00
|
|
|
case "copy":
|
|
|
|
err = actionCopy(action, eventInfo, ctx)
|
2021-08-12 16:48:38 +02:00
|
|
|
case "mkdir":
|
|
|
|
err = actionMkDir(action, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
case "delete":
|
2021-08-11 11:46:05 +02:00
|
|
|
err = actionDelete(action, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
case "log":
|
2021-08-11 11:46:05 +02:00
|
|
|
err = actionLog(action, eventInfo, ctx)
|
|
|
|
case "mail":
|
|
|
|
err = actionMail(action, eventInfo, ctx)
|
2021-12-22 12:04:24 +01:00
|
|
|
case "command":
|
|
|
|
err = actionCommand(action, eventInfo, ctx)
|
2021-12-22 12:25:33 +01:00
|
|
|
case "sleep":
|
|
|
|
err = actionSleep(action, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
default:
|
|
|
|
err = fmt.Errorf("action type %s unknown", action.Type)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2021-08-11 11:46:05 +02:00
|
|
|
add2Ctx(action, ctx, "error", err.Error())
|
2021-08-12 17:07:56 +02:00
|
|
|
action.Error = err
|
2021-09-07 18:11:31 +02:00
|
|
|
if err != nil {
|
|
|
|
action.ErrorString = err.Error()
|
|
|
|
}
|
2021-08-11 11:46:05 +02:00
|
|
|
|
2021-08-12 17:28:41 +02:00
|
|
|
log.Printf("[ ERROR ] path=\"%s\" action=\"%s\" error=\"%s\"", eventInfo.Path(), action.Id, err)
|
2021-08-10 18:31:29 +02:00
|
|
|
for _, aE := range action.OnError {
|
2021-08-12 17:07:56 +02:00
|
|
|
aE.Directory = action.Directory
|
2021-08-12 16:55:37 +02:00
|
|
|
aE.Parent = action
|
2021-08-11 11:46:05 +02:00
|
|
|
_c, _ := runAction(&aE, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
contin = contin && _c
|
2021-08-10 18:31:29 +02:00
|
|
|
if !contin {
|
|
|
|
break
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-10 18:31:29 +02:00
|
|
|
} else {
|
|
|
|
for _, aS := range action.OnSuccess {
|
2021-08-12 17:07:56 +02:00
|
|
|
aS.Directory = action.Directory
|
2021-08-12 16:55:37 +02:00
|
|
|
aS.Parent = action
|
2021-08-11 11:46:05 +02:00
|
|
|
_c, errS := runAction(&aS, eventInfo, ctx)
|
2021-08-10 18:31:29 +02:00
|
|
|
contin = contin && _c
|
|
|
|
if errS != nil {
|
|
|
|
err = errS
|
|
|
|
}
|
|
|
|
if !contin {
|
|
|
|
break
|
|
|
|
}
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return contin, err
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
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 {
|
2021-08-10 16:56:44 +02:00
|
|
|
method := "POST"
|
|
|
|
if action.Method != nil {
|
2021-08-11 11:46:05 +02:00
|
|
|
m, err := tpl2String(*action.Method, action, eventInfo, ctx)
|
2021-08-10 18:31:29 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
method = strings.ToUpper(m)
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
if action.URL == nil {
|
|
|
|
return fmt.Errorf("missing url in http action")
|
|
|
|
}
|
2021-08-11 11:46:05 +02:00
|
|
|
url, err := tpl2String(*action.URL, action, eventInfo, ctx)
|
2021-08-10 18:31:29 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-10 16:56:44 +02:00
|
|
|
|
|
|
|
postData := bytes.NewBuffer([]byte{})
|
|
|
|
if method != "GET" {
|
|
|
|
if action.Content == nil {
|
|
|
|
// read file
|
|
|
|
postBytes, err := ioutil.ReadFile(eventInfo.Path())
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
postData = bytes.NewBuffer(postBytes)
|
2021-08-10 18:31:29 +02:00
|
|
|
} else {
|
2021-08-11 11:46:05 +02:00
|
|
|
p, err := tpl2String(*action.Content, action, eventInfo, ctx)
|
2021-08-10 18:31:29 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Println("BODY: ", p)
|
|
|
|
postData = bytes.NewBufferString(p)
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-16 20:13:41 +02:00
|
|
|
// log.Printf("%s %s", method, url)
|
2021-08-10 18:31:29 +02:00
|
|
|
req, err := http.NewRequest(method, url, postData)
|
2021-08-10 16:56:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for key, val := range action.Header {
|
|
|
|
req.Header.Set(key, val)
|
|
|
|
}
|
|
|
|
client := &http.Client{}
|
|
|
|
client.Timeout = time.Second * 20
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
2021-08-16 20:13:41 +02:00
|
|
|
// fmt.Println(string(body))
|
2021-08-10 16:56:44 +02:00
|
|
|
defer resp.Body.Close()
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
add2Ctx(action, ctx, "response", map[string]interface{}{
|
|
|
|
"Status": resp.Status,
|
|
|
|
"StatusCode": resp.StatusCode,
|
|
|
|
"Body": string(body),
|
|
|
|
})
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
if resp.StatusCode >= 400 {
|
|
|
|
return fmt.Errorf("response status %s", resp.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
func actionMove(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
2021-08-10 16:56:44 +02:00
|
|
|
if action.To == nil {
|
|
|
|
return fmt.Errorf("missing to: as destination for move action")
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
to, err := tpl2String(*action.To, action, eventInfo, ctx)
|
2021-08-10 16:56:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = os.Rename(eventInfo.Path(), to)
|
2021-12-22 10:50:15 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if action.FileMode != nil {
|
|
|
|
err = os.Chmod(to, *action.FileMode)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func actionCopy(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
|
|
|
if action.To == nil {
|
|
|
|
return fmt.Errorf("missing to: as destination for copy action")
|
|
|
|
}
|
|
|
|
|
|
|
|
to, err := tpl2String(*action.To, action, eventInfo, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
in, err := os.Open(eventInfo.Path())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer in.Close()
|
|
|
|
|
|
|
|
out, err := os.Create(to)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer out.Close()
|
|
|
|
|
|
|
|
_, err = io.Copy(out, in)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if action.FileMode != nil {
|
|
|
|
err = os.Chmod(to, *action.FileMode)
|
|
|
|
}
|
|
|
|
|
2021-08-10 16:56:44 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
func actionDelete(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
2021-08-10 18:31:29 +02:00
|
|
|
return os.Remove(eventInfo.Path())
|
2021-08-10 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
2021-08-12 16:48:38 +02:00
|
|
|
func actionMkDir(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
|
|
|
if action.Path == nil {
|
|
|
|
return fmt.Errorf(("missing path: for mkdir action"))
|
|
|
|
}
|
|
|
|
|
|
|
|
path, err := tpl2String(*action.Path, action, eventInfo, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return os.MkdirAll(path, 0755)
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
func actionLog(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
2021-08-10 16:56:44 +02:00
|
|
|
var logstr string
|
|
|
|
if action.Content != nil {
|
2021-08-12 16:48:38 +02:00
|
|
|
var err error
|
|
|
|
logstr, err = tpl2String(*action.Content, action, eventInfo, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-10 16:56:44 +02:00
|
|
|
} else {
|
|
|
|
logstr = eventInfo.Path()
|
|
|
|
}
|
|
|
|
log.Printf("LOG: %s", logstr)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2021-12-22 12:25:33 +01:00
|
|
|
func actionSleep(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
|
|
|
if action.Duration != nil {
|
|
|
|
time.Sleep(time.Duration(*action.Duration) * time.Millisecond)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-22 12:04:24 +01:00
|
|
|
func actionCommand(action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) error {
|
|
|
|
if action.Command == nil {
|
|
|
|
return fmt.Errorf("missing command")
|
|
|
|
}
|
|
|
|
args := make([]string, len(action.Args))
|
|
|
|
for idx, a := range action.Args {
|
|
|
|
var err error
|
|
|
|
args[idx], err = tpl2String(a, action, eventInfo, ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out, err := exec.Command(*action.Command, action.Args...).Output()
|
|
|
|
log.Println("COMMAND OUTPUT: ", string(out))
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-08-11 11:46:05 +02:00
|
|
|
func tpl2String(tpl string, action *ActionConfig, eventInfo notify.EventInfo, ctx actionCtx) (string, error) {
|
2021-08-10 16:56:44 +02:00
|
|
|
_tpl, err := pongo2.FromString(tpl)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
p := eventInfo.Path()
|
|
|
|
return _tpl.Execute(pongo2.Context{
|
2021-08-12 16:48:38 +02:00
|
|
|
"path": p,
|
|
|
|
"dirname": filepath.Dir(p),
|
|
|
|
"filename": filepath.Base(p),
|
|
|
|
"event": eventInfo.Event().String(),
|
|
|
|
"action": action,
|
2021-08-12 17:07:56 +02:00
|
|
|
"directory": action.Directory,
|
|
|
|
"regexMatches": action.Directory._regexMatches,
|
2021-08-12 16:48:38 +02:00
|
|
|
"context": ctx,
|
2021-08-10 16:56:44 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
|
|
|
confDat, err := ioutil.ReadFile("./config.yml")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("error %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(confDat, &conf)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("error %v", err)
|
|
|
|
}
|
2021-09-07 18:24:30 +02:00
|
|
|
spew.Dump(conf)
|
2021-08-10 16:56:44 +02:00
|
|
|
|
|
|
|
for _, directory := range conf.Directories {
|
2021-08-10 18:31:29 +02:00
|
|
|
directory := directory
|
2021-08-10 16:56:44 +02:00
|
|
|
startWatcher(&directory)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
log.Println("fstrigger exit")
|
|
|
|
}
|