Files
dengitool/appmodules.go
2026-05-22 18:22:43 +03:00

183 lines
3.8 KiB
Go

package main
import (
"errors"
"fmt"
"net/url"
"os/exec"
"path/filepath"
"strconv"
"strings"
)
type AppModule struct {
Name string
Folder string
CheckS string
}
type AppModuleConfig struct {
Name string `yaml:"name"`
CheckUrl *string `yaml:"check-url"`
}
type Script struct {
Name string
AbsPath string
Runner ScriptRunner
}
func (s *Script) Run() (string, error) {
args := runnerArgs(s.Runner.Runner, s.AbsPath)
if len(args) == 0 {
return "", errors.New("runner command is empty")
}
cmd := exec.Command(args[0], args[1:]...)
output, err := cmd.CombinedOutput()
return string(output), err
}
func runnerArgs(template string, scriptPath string) []string {
fields := strings.Fields(template)
for i, field := range fields {
fields[i] = strings.ReplaceAll(field, "%v", scriptPath)
}
return fields
}
func (m *AppModule) HasScript(name string, subfolder *string) (bool, *Script) {
folder := m.Folder
if subfolder != nil {
folder = filepath.Join(folder, *subfolder)
}
for _, r := range runners {
ext := r.Extension
if ext != "" && !strings.HasPrefix(ext, ".") {
ext = "." + ext
}
scriptPath := filepath.Join(folder, name+ext)
if fileExists(scriptPath) {
abs, err := filepath.Abs(scriptPath)
if err != nil {
return false, nil
}
return true, &Script{Name: name, AbsPath: abs, Runner: r}
}
}
return false, nil
}
func (m *AppModule) Check() (bool, string, error) {
if strings.HasPrefix(m.CheckS, "URL ") {
check := strings.Split(m.CheckS, " ")[1:]
if len(check) < 1 || len(check) > 3 {
return false, "", errors.New("check url is bad")
}
checkUrl := check[0]
code := ""
if len(check) > 1 {
code = check[1]
}
body := ""
if len(check) > 2 {
dBody, err := url.QueryUnescape(check[2])
if err != nil {
return false, "", errors.New("check body decode failed")
}
body = dBody
}
cCode, cBody, err := fetch(checkUrl, defaultFetchTimeout)
if err != nil {
return false, "", err
}
if code != "" && strconv.Itoa(cCode) != code {
return false, "", fmt.Errorf("code is different: expected %s, got %d", code, cCode)
}
if body != "" && body != cBody {
return false, "", errors.New("body is different")
}
return true, "", nil
} else {
exists, script := m.HasScript("check", nil)
if exists && script != nil {
output, err := script.Run()
if err != nil {
return false, output, err
} else {
return true, output, nil
}
} else {
return false, "", errors.New("check script not found")
}
}
}
func (m *AppModule) Start() (string, error) {
exists, script := m.HasScript("start", nil)
if exists && script != nil {
return script.Run()
} else {
return "", errors.New("start script not found")
}
}
func (m *AppModule) Stop() (string, error) {
exists, script := m.HasScript("stop", nil)
if exists && script != nil {
return script.Run()
} else {
return "", errors.New("stop script not found")
}
}
func (m *AppModule) Restart() (string, error) {
exists, script := m.HasScript("restart", nil)
if exists && script != nil {
return script.Run()
} else {
stopOutput, err := m.Stop()
if err != nil {
return stopOutput, err
}
startOutput, err := m.Start()
return joinOutput(stopOutput, startOutput), err
}
}
func (m *AppModule) Fix() (string, error) {
exists, script := m.HasScript("fix", nil)
if exists && script != nil {
return script.Run()
} else {
return m.Restart()
}
}
func (m *AppModule) Run(scriptN string) (string, error) {
var sub = "run"
exists, script := m.HasScript(scriptN, &sub)
if exists && script != nil {
return script.Run()
} else {
return "", errors.New("run script not found")
}
}
type Application struct {
Name string
Folder string
AppModules []AppModule
}
type AppConfig struct {
Name string `yaml:"name"`
}