configui/file.go

86 lines
1.6 KiB
Go

package configui
import (
"errors"
"os"
"os/exec"
"runtime"
"sync"
"time"
)
type File struct {
Path string `json:"path"`
Name string `json:"name"`
Action string `json:"action"`
// RO is readonly
RO bool `json:"ro"`
Lang string `json:"lang"`
// Order order of the display on ui
Order int `json:"order"`
// used for parsing post data
Data string `json:"data,omitempty"`
lock sync.RWMutex `json:"-"`
owner *ConfigUI `json:"-"`
}
func (f *File) Read() ([]byte, error) {
f.lock.RLock()
defer f.lock.RUnlock()
data, err := os.ReadFile(f.Path)
if err != nil {
f.owner.log.Error(err)
return nil, err
}
return data, nil
}
func (f *File) Write(data []byte) error {
if f.RO {
return errors.New("this file has readonly set")
}
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())
}
func (f *File) Do(CmdTimeout time.Duration) (string, error) {
if f.Action == "" {
return "", nil
}
f.lock.RLock()
defer f.lock.RUnlock()
cmd := &exec.Cmd{}
if runtime.GOOS == "windows" {
cmd = exec.Command(WIN_SHELL, "/c", f.Action)
} else {
cmd = exec.Command(UNIX_SHELL, "-c", f.Action)
}
f.owner.log.Info("DO: ", f.Action)
done := make(chan string, 1)
go func() {
out, _ := cmd.CombinedOutput()
// real cmd err is unhandled, but passed to client
// if err != nil {
// return string(out), err
// }
done <- string(out)
}()
select {
case <-time.After(CmdTimeout):
cmd.Process.Kill()
f.owner.log.Error("timeout")
return "", errors.New("command timeout")
case out := <-done:
f.owner.log.Info("\n", out)
return out, nil
}
}