configui/file.go

113 lines
2.2 KiB
Go
Raw Normal View History

2021-10-18 08:49:16 +00:00
package configui
import (
2021-11-11 01:58:36 +00:00
"bytes"
2021-10-18 10:59:09 +00:00
"errors"
2021-11-11 01:58:36 +00:00
"fmt"
2021-10-18 08:49:16 +00:00
"os"
"os/exec"
"runtime"
"sync"
2021-10-21 08:04:57 +00:00
"time"
2021-10-18 08:49:16 +00:00
)
type File struct {
Path string `json:"path"`
Name string `json:"name"`
Cmd string `json:"cmd"`
// RO is readonly
RO bool `json:"ro"`
Lang string `json:"lang"`
// Order order of the display on ui
Order int `json:"order"`
2021-10-18 08:49:16 +00:00
// used for parsing post data
2021-11-09 03:41:41 +00:00
Data string `json:"data,omitempty"`
2021-10-18 08:49:16 +00:00
2021-11-11 01:58:36 +00:00
lock sync.RWMutex `json:"-"`
owner *ConfigUI `json:"-"`
run chan struct{} `json:"-"`
pid int `json:"-"`
// deprecated
Action string `json:"action,omitempty"`
2021-10-18 08:49:16 +00:00
}
func (f *File) Read() ([]byte, error) {
f.lock.RLock()
defer f.lock.RUnlock()
data, err := os.ReadFile(f.Path)
if err != nil {
2021-11-03 19:35:51 +00:00
f.owner.log.Error(err)
2021-10-18 08:49:16 +00:00
return nil, err
}
return data, nil
}
func (f *File) Write(data []byte) error {
2021-10-18 10:59:09 +00:00
if f.RO {
return errors.New("this file has readonly set")
}
2021-10-18 08:49:16 +00:00
f.lock.Lock()
defer f.lock.Unlock()
info, err := os.Stat(f.Path)
if err != nil {
return err
}
return os.WriteFile(f.Path, data, info.Mode())
}
2021-11-12 15:09:32 +00:00
func (f *File) Do(CmdTimeout time.Duration, report chan int) (string, error) {
if f.Cmd == "" {
2021-10-18 08:49:16 +00:00
return "", nil
}
f.lock.RLock()
defer f.lock.RUnlock()
2021-11-11 01:58:36 +00:00
// limit running instance to 1
if cap(f.run) == 0 {
f.run = make(chan struct{}, 1)
}
select {
case f.run <- struct{}{}:
defer func() { <-f.run }()
default:
f.owner.log.Error("task is running: ", f.Name)
return "", fmt.Errorf("another task of %s is running with pid: %d", f.Name, f.pid)
}
// prepare cmd
2021-10-21 08:04:57 +00:00
cmd := &exec.Cmd{}
2021-10-18 08:49:16 +00:00
if runtime.GOOS == "windows" {
2021-11-12 15:09:32 +00:00
cmd = exec.Command(f.owner.SHELL, "/c", f.Cmd)
2021-10-21 08:04:57 +00:00
} else {
2021-11-12 15:09:32 +00:00
cmd = exec.Command(f.owner.SHELL, "-c", f.Cmd)
2021-10-21 08:04:57 +00:00
}
f.owner.log.Info("DO: ", f.Cmd)
done := make(chan string, 1)
2021-11-12 06:29:47 +00:00
var b bytes.Buffer
cmd.Stdout = &b
cmd.Stderr = &b
err := cmd.Start()
if err != nil {
f.owner.log.Error("cmd start error: ", err)
panic(err)
}
2021-10-21 08:04:57 +00:00
go func() {
2021-11-11 01:58:36 +00:00
f.pid = cmd.Process.Pid
2021-11-12 15:09:32 +00:00
report <- cmd.Process.Pid
2021-11-11 01:58:36 +00:00
cmd.Wait()
done <- b.String()
2021-10-21 08:04:57 +00:00
}()
select {
2021-11-03 10:08:37 +00:00
case <-time.After(CmdTimeout):
2021-10-21 08:04:57 +00:00
cmd.Process.Kill()
2021-11-03 19:35:51 +00:00
f.owner.log.Error("timeout")
2021-10-21 08:04:57 +00:00
return "", errors.New("command timeout")
case out := <-done:
2021-11-03 19:35:51 +00:00
f.owner.log.Info("\n", out)
return out, nil
2021-10-18 08:49:16 +00:00
}
}