进程管理程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pmt/db/config.go

138 lines
5.3 KiB

package db
import (
"encoding/json"
"encoding/xml"
"fmt"
"github.com/pelletier/go-toml/v2"
"gopkg.in/ini.v1"
"gopkg.in/yaml.v3"
"os"
"strconv"
"strings"
)
// AppConfig 程序启动配置
type AppConfig struct {
Name string `json:"name,omitempty" yaml:"name,omitempty" toml:"name,multiline,omitempty" xml:"name,omitempty" ini:"name,omitempty"` // 应用名称
Description string `json:"description,omitempty" yaml:"description,omitempty" toml:"description,multiline,omitempty" xml:"description,omitempty" ini:"description,omitempty"` // 应用描述
Script string `json:"script,omitempty" yaml:"script,omitempty" toml:"script,multiline,omitempty" xml:"script,omitempty" ini:"script,omitempty"` // 执行脚本
Args []string `json:"args,omitempty" yaml:"args,omitempty" toml:"args,multiline,omitempty" xml:"args,omitempty" ini:"args,omitempty"` // 启动参数
Stdin string `json:"stdin,omitempty" yaml:"stdin,omitempty" toml:"stdin,multiline,omitempty" xml:"stdin,omitempty" ini:"stdin,omitempty"` // 标准输入数据
Cwd string `json:"Cwd,omitempty" yaml:"Cwd,omitempty" toml:"Cwd,multiline,omitempty" xml:"Cwd,omitempty" ini:"cwd,omitempty"` // 工作目录
Env map[string]string `json:"env,omitempty" yaml:"env,omitempty" toml:"env,multiline,omitempty" xml:"env,omitempty" ini:"env,omitempty"` // 自定义环境变量
Interpreter string `json:"interpreter,omitempty" yaml:"interpreter,omitempty" toml:"interpreter,multiline,omitempty" xml:"interpreter,omitempty" ini:"interpreter,omitempty"` // 脚本解释程序
InterpreterArgs []string `json:"interpreter_args,omitempty" yaml:"interpreter_args,omitempty" toml:"interpreter_args,multiline,omitempty" xml:"interpreter_args,omitempty" ini:"interpreterArgs,omitempty"` // 解释程序参数
RerunOnError *RerunOnError `json:"rerunOnError" yaml:"rerunOnError,omitempty" toml:"rerunOnError,multiline,omitempty" xml:"rerunOnError,omitempty" ini:"rerunOnError,omitempty"` // 错误重启策略
Custom map[string]any `json:"custom,omitempty" yaml:"custom,omitempty" toml:"custom,multiline,omitempty" xml:"custom,omitempty" ini:"custom,omitempty"` // 其它自定义参数
}
type Unmarshaller func(data []byte, v any) error
func ParseInput(input string) ([]*App, error) {
var configs []AppConfig
var err error
var app *App
if IsAppID(input) {
var id int
if id, err = strconv.Atoi(input); err != nil {
return nil, fmt.Errorf("invalid identifier")
}
app, err = FindApp(WithAppID(uint(id)))
} else if strings.HasSuffix(input, ".pmt.json") {
configs, err = Unmarshal(input, json.Unmarshal)
} else if strings.HasSuffix(input, ".pmt.toml") {
configs, err = Unmarshal(input, toml.Unmarshal)
} else if strings.HasSuffix(input, ".pmt.yaml") {
configs, err = Unmarshal(input, yaml.Unmarshal)
} else if strings.HasSuffix(input, ".pmt.xml") {
configs, err = Unmarshal(input, xml.Unmarshal)
} else if strings.HasSuffix(input, ".pmt.ini") {
configs, err = Unmarshal(input, func(data []byte, v any) error {
if info, err := ini.Load(data); err != nil {
return err
} else {
return info.MapTo(v)
}
})
} else if file, ex := os.Stat(input); ex == nil {
if file.IsDir() {
return nil, fmt.Errorf("unsupported directoty entry")
}
if app, err = scriptToApp(input); err != nil {
return nil, err
}
} else {
app, err = FindApp(WithAppName(input))
}
if err != nil {
return nil, err
}
if app != nil {
return []*App{app}, nil
}
if len(configs) == 0 {
return nil, fmt.Errorf("not found")
}
var apps []*App
for _, cfg := range configs {
apps = append(apps, optionsToApp(&cfg))
}
return apps, err
}
func scriptToApp(script string) (*App, error) {
name := ToSnakeCase(script)
app, err := FindApp(WithAppName(name))
if err == nil {
if app.Script != script {
return nil, fmt.Errorf("应用 %s 已存在", script)
}
return app, nil
}
return &App{
PID: -1,
Name: name,
Script: script,
}, nil
}
func optionsToApp(opts *AppConfig) *App {
return &App{
PID: -1,
Name: opts.Name,
Description: opts.Description,
Script: opts.Script,
Command: nil,
Arguments: opts.Args,
Stdin: opts.Stdin,
Cwd: opts.Cwd,
Environments: opts.Env,
Interpreter: opts.Interpreter,
InterpreterArgs: opts.InterpreterArgs,
RerunOnError: opts.RerunOnError,
Options: opts.Custom,
}
}
// Unmarshal 读取配置文件
func Unmarshal(file string, unmarshal Unmarshaller) ([]AppConfig, error) {
bts, err := os.ReadFile(file)
if err != nil {
return nil, err
}
var config AppConfig
if err = unmarshal(bts, &config); err == nil {
return []AppConfig{config}, nil
}
var configs []AppConfig
if unmarshal(bts, &configs) == nil {
return configs, nil
}
return nil, err
}