173 lines
3.3 KiB
Go
173 lines
3.3 KiB
Go
package reveil
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha512"
|
|
"fmt"
|
|
"io/fs"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.nemunai.re/nemunaire/reveil/config"
|
|
)
|
|
|
|
type RoutineStep struct {
|
|
Delay uint64 `json:"delay"`
|
|
Action string `json:"action"`
|
|
Args []string `json:"args,omitempty"`
|
|
}
|
|
|
|
func (s *RoutineStep) GetAction(cfg *config.Config) (*Action, error) {
|
|
return LoadAction(cfg, s.Action)
|
|
}
|
|
|
|
type Routine struct {
|
|
Id Identifier `json:"id"`
|
|
Name string `json:"name"`
|
|
Path string `json:"path"`
|
|
Steps []RoutineStep `json:"steps"`
|
|
}
|
|
|
|
func LoadRoutine(path string, cfg *config.Config) ([]RoutineStep, error) {
|
|
ds, err := ioutil.ReadDir(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
actionsDir, err := filepath.Abs(cfg.ActionsDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var steps []RoutineStep
|
|
|
|
for _, f := range ds {
|
|
fullpath := filepath.Join(path, f.Name())
|
|
if f.Mode()&os.ModeSymlink == 0 {
|
|
continue
|
|
}
|
|
|
|
dst, err := os.Readlink(fullpath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if adst, err := filepath.Abs(filepath.Join(path, dst)); err == nil {
|
|
dst = adst
|
|
}
|
|
|
|
args := strings.Split(f.Name(), "_")
|
|
|
|
delay, err := strconv.ParseUint(args[0], 10, 64)
|
|
|
|
step := RoutineStep{
|
|
Delay: delay,
|
|
Action: strings.TrimPrefix(dst, actionsDir+"/"),
|
|
}
|
|
if len(args) > 1 {
|
|
step.Args = args[1:]
|
|
}
|
|
|
|
steps = append(steps, step)
|
|
}
|
|
|
|
return steps, nil
|
|
}
|
|
|
|
func LoadRoutineFromId(id Identifier, cfg *config.Config) (*Routine, error) {
|
|
routines, err := LoadRoutines(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, routine := range routines {
|
|
if bytes.Equal(routine.Id, id) {
|
|
return routine, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("Unable to find routine %x", id)
|
|
}
|
|
|
|
func LoadRoutines(cfg *config.Config) (routines []*Routine, err error) {
|
|
err = filepath.Walk(cfg.RoutinesDir, func(path string, d fs.FileInfo, err error) error {
|
|
if d.IsDir() && path != cfg.RoutinesDir {
|
|
hash := sha512.Sum512([]byte(path))
|
|
|
|
// Explore directory
|
|
steps, err := LoadRoutine(path, cfg)
|
|
if err != nil {
|
|
log.Printf("Invalid routine directory (trying to walk through %s): %s", path, err.Error())
|
|
// Ignore invalid routines
|
|
return nil
|
|
}
|
|
|
|
routines = append(routines, &Routine{
|
|
Id: hash[:],
|
|
Name: d.Name(),
|
|
Path: path,
|
|
Steps: steps,
|
|
})
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
func (r *Routine) Rename(newName string) error {
|
|
newPath := filepath.Join(filepath.Dir(r.Path), newName)
|
|
|
|
err := os.Rename(
|
|
r.Path,
|
|
newPath,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r.Path = newPath
|
|
return nil
|
|
}
|
|
|
|
func (a *Routine) Remove() error {
|
|
return os.Remove(a.Path)
|
|
}
|
|
|
|
func (a *Routine) Launch(cfg *config.Config) error {
|
|
for _, s := range a.Steps {
|
|
act, err := s.GetAction(cfg)
|
|
if err != nil {
|
|
log.Printf("Unable to get action: %s: %s", s.Action, err.Error())
|
|
continue
|
|
}
|
|
|
|
settings, err := ReadSettings(cfg.SettingsFile)
|
|
if err != nil {
|
|
log.Printf("Unable to read settings: %s", err.Error())
|
|
continue
|
|
}
|
|
|
|
time.Sleep(time.Duration(s.Delay) * time.Second)
|
|
|
|
cmd, err := act.Launch(settings)
|
|
if err != nil {
|
|
log.Printf("Unable to launch the action %q: %s", s.Action, err.Error())
|
|
continue
|
|
}
|
|
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
log.Printf("Something goes wrong when waiting for the action %q's end: %s", s.Action, err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|