进程管理程序
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/main.go

297 lines
7.4 KiB

package main
import (
"flag"
"fmt"
"github.com/rs/xid"
"hupeh.vip/pm/cmd"
"hupeh.vip/pm/db"
"os"
"os/exec"
"strconv"
)
var allowPMTs = map[string]int{
"start": 1,
"restart": 1,
//"list": 1,
//"shell": 1,
}
func main() {
var sign string // all
var pmt string // all
var id int // start,restart
var daemon bool // start,restart
flag.StringVar(&sign, "sign", "", "sign token")
flag.StringVar(&pmt, "pmt", "", "task name")
flag.IntVar(&id, "id", 0, "app id")
flag.BoolVar(&daemon, "daemon", false, "daemon mode")
flag.Parse()
// 命令行模式
if v, ok := allowPMTs[pmt]; !ok || v != 1 {
runCli()
return
}
// 验证签名
if _, err := xid.FromString(sign); err != nil {
fmt.Println(cmd.Red("bad sign token"))
return
}
switch pmt {
// 启动应用
case "start":
// 开启守护模式
if !daemon {
subProcess(append(os.Args, "-daemon")...)
fmt.Printf("[*] Daemon running in pid: %d PPID: %d\n", os.Getpid(), os.Getppid())
os.Exit(0)
}
if id <= 0 {
fmt.Println(cmd.Red("missing app id"))
return
}
// 查询 app
app, err := db.FindApp(db.WithAppID(uint(id)))
if err != nil {
fmt.Println(cmd.Red("failed to find app"))
fmt.Println(" " + cmd.Red(err.Error()))
return
}
// 创建进程处理器
proc := db.NewProc(app)
// 忽略运行中的
if proc.IsAlive() {
return
}
// 启动失败
if err = proc.Start(); err != nil {
fmt.Println(cmd.Yellow(app.Name) + " - " + cmd.Red("start fail"))
fmt.Println(" " + cmd.Red(err.Error()))
return
}
// 启动成功
fmt.Println(cmd.Yellow(app.Name) + " - " + cmd.Green("start success"))
// 重启脚本
case "restart":
// 开启守护模式
if !daemon {
subProcess(append(os.Args, "-daemon")...)
fmt.Printf("[*] Daemon running in pid: %d PPID: %d\n", os.Getpid(), os.Getppid())
os.Exit(0)
}
if id <= 0 {
fmt.Println(cmd.Red("missing app id"))
return
}
// 查询 app
app, err := db.FindApp(db.WithAppID(uint(id)))
if err != nil {
fmt.Println(cmd.Red("failed to find app"))
fmt.Println(" " + cmd.Red(err.Error()))
return
}
// 创建进程处理器
proc := db.NewProc(app)
// 重启失败
if err = proc.Restart(); err != nil {
fmt.Println(cmd.Yellow(app.Name) + " - " + cmd.Red("restart fail"))
fmt.Println(" " + cmd.Red(err.Error()))
return
}
// 重启成功
fmt.Println(cmd.Yellow(app.Name) + " - " + cmd.Green("restart success"))
}
}
func runCli() {
cmd.New("pm").
Name("pm").
Description("description").
// start 命令
Command("start", "Start program(s) in daemon").
Argument("[names:...string]", "file/name/id").
Option("-w, --watch <watch:boolean>", "Watches folder changes").
Option("-c, --cwd <cwd:string>", "Sets working directory "+cmd.Yellow("Sets working directory")+" Sets working directory "+cmd.Yellow("Sets working directory")+" Sets working directory "+cmd.Yellow(" Sets working directory")+" Sets working directory "+cmd.Yellow("Sets working directory")+" Sets working directory "+cmd.Yellow("Sets working directory")+" End ...").
Option("-n, --name", "Sets program name").
Option("-e, --env", "Sets current environment name").
Option("-i, --interpreter", "Sets interpreter name").
Action(func(c *cmd.Command, m map[string]any, a ...any) error {
var apps []*db.App
var err error
if len(a) != 1 {
apps, err = db.FindApps(db.WithAppStatus(db.StatusStopped))
if err != nil {
fmt.Println(cmd.Red("load all apps fail"))
fmt.Println(" " + cmd.Red(err.Error()))
return err
}
} else {
scripts := a[0].([]string)
for _, script := range scripts {
loads, err := db.ParseInput(script)
if err != nil {
fmt.Println(cmd.Red("load all apps fail"))
fmt.Println(" " + cmd.Red(err.Error()))
return err
}
apps = append(apps, loads...)
}
}
if len(apps) == 0 {
fmt.Println("No app found")
return nil
}
for _, app := range apps {
if app.Status == db.StatusRunning {
fmt.Println(cmd.Yellow(app.Name), cmd.Green("running"))
continue
}
if app.ID == 0 {
if err := db.SaveApp(app); err != nil {
fmt.Println(cmd.Yellow(app.Name), cmd.Red("failed to saving"))
fmt.Println(" " + cmd.Red(err.Error()))
continue
}
}
// todo options
proc := subProcess(
"-id="+strconv.Itoa(int(app.ID)),
"-pmt=start",
"-sign="+xid.New().String(),
)
if err := proc.Wait(); err != nil {
fmt.Println(cmd.Yellow(app.Name), cmd.Red("failed"))
fmt.Println(" ", err.Error())
} else {
fmt.Println(cmd.Yellow(app.Name), cmd.Green("success"))
}
}
fmt.Println("over")
return nil
}).
// restart 命令
Command("restart", "Restarts program(s)").
Argument("<names:...string>", "file/name/id").
Action(func(c *cmd.Command, m map[string]any, a ...any) error {
var apps []*db.App
if len(a) != 0 {
c.ShowHelp()
return nil
}
scripts := a[0].([]string)
for _, script := range scripts {
loads, err := db.ParseInput(script)
if err != nil {
fmt.Println(cmd.Red("load all apps fail"))
fmt.Println(" " + cmd.Red(err.Error()))
return err
}
apps = append(apps, loads...)
}
if len(apps) == 0 {
fmt.Println("No app found")
return nil
}
for _, app := range apps {
if app.ID == 0 {
if err := db.SaveApp(app); err != nil {
fmt.Println(cmd.Yellow(app.Name), cmd.Red("failed to saving"))
fmt.Println(" " + cmd.Red(err.Error()))
continue
}
}
// todo options
proc := subProcess(
"-id="+strconv.Itoa(int(app.ID)),
"-pmt=restart",
"-sign="+xid.New().String(),
)
if err := proc.Wait(); err != nil {
fmt.Println(cmd.Yellow(app.Name), cmd.Red("failed"))
fmt.Println(" ", err.Error())
} else {
fmt.Println(cmd.Yellow(app.Name), cmd.Green("success"))
}
}
fmt.Println("over")
return nil
}).
// stop 命令
Command("stop", "Stops a program").
Argument("<names:...string>", "file/name/id").
Action(func(c *cmd.Command, m map[string]any, a ...any) error {
if len(a) != 1 {
return c.ShowHelp()
}
var apps []*db.App
scripts := a[0].([]string)
for _, script := range scripts {
loads, err := db.ParseInput(script)
if err != nil {
return err
}
apps = append(apps, loads...)
}
if len(apps) == 0 {
fmt.Println("No app found")
return nil
}
for _, app := range apps {
if app.PID <= 0 {
fmt.Println(cmd.Yellow(app.Name), "not running")
return nil
}
proc := db.NewProc(app)
err := proc.Stop()
if err != nil {
fmt.Println(cmd.Yellow(app.Name), cmd.Red("failed to stop"))
fmt.Println(" " + cmd.Red(err.Error()))
return err
}
fmt.Println(cmd.Yellow(app.Name), cmd.Green("stopped"))
return nil
}
fmt.Println("over")
return nil
}).
// 执行程序
Run()
}
func subProcess(args ...string) *exec.Cmd {
cmd := exec.Command(os.Args[0], args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
fmt.Fprintf(os.Stderr, "[-] Error: %s\n", err)
}
return cmd
}
// 移除不需要的参数
func strip(slice []string, remove string) []string {
for i := 0; i < len(slice); {
if slice[i] == remove {
if i != len(slice)-1 {
slice = append(slice[:i], slice[i+1:]...)
} else {
slice = slice[:i]
}
} else {
i++
}
}
return slice
}