206 lines
5.4 KiB
Go
206 lines
5.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
"syscall"
|
||
|
"time"
|
||
|
|
||
|
"apigo.cc/gojs"
|
||
|
|
||
|
_ "apigo.cc/ai/llm"
|
||
|
_ "apigo.cc/gojs/client"
|
||
|
_ "apigo.cc/gojs/console"
|
||
|
_ "apigo.cc/gojs/db"
|
||
|
_ "apigo.cc/gojs/file"
|
||
|
_ "apigo.cc/gojs/http"
|
||
|
_ "apigo.cc/gojs/log"
|
||
|
_ "apigo.cc/gojs/service"
|
||
|
_ "apigo.cc/gojs/util"
|
||
|
|
||
|
_ "apigo.cc/ai/llm/openai"
|
||
|
_ "apigo.cc/ai/llm/zhipu"
|
||
|
"github.com/ssgo/log"
|
||
|
_ "github.com/ssgo/s"
|
||
|
"github.com/ssgo/u"
|
||
|
_ "modernc.org/sqlite"
|
||
|
)
|
||
|
|
||
|
var appName = "tests"
|
||
|
var appVersion = "v0.0.1"
|
||
|
var idFixMatcher = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
||
|
|
||
|
// TODO embed .CacheFiles
|
||
|
|
||
|
func init() {
|
||
|
gojs.Alias("ai/llm", "apigo.cc/ai/llm")
|
||
|
gojs.Alias("client", "apigo.cc/gojs/client")
|
||
|
gojs.Alias("console", "apigo.cc/gojs/console")
|
||
|
gojs.Alias("db", "apigo.cc/gojs/db")
|
||
|
gojs.Alias("file", "apigo.cc/gojs/file")
|
||
|
gojs.Alias("http", "apigo.cc/gojs/http")
|
||
|
gojs.Alias("log", "apigo.cc/gojs/log")
|
||
|
gojs.Alias("service", "apigo.cc/gojs/service")
|
||
|
gojs.Alias("util", "apigo.cc/gojs/util")
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
if appName == "" {
|
||
|
appName = filepath.Base(os.Args[0])
|
||
|
appName = strings.TrimSuffix(appName, ".exe")
|
||
|
}
|
||
|
|
||
|
if appVersion == "" {
|
||
|
appVersion = "0.0.1"
|
||
|
}
|
||
|
|
||
|
args := os.Args[1:]
|
||
|
if len(args) > 0 {
|
||
|
if args[0] == "help" || args[0] == "--help" || args[0] == "-h" {
|
||
|
printUsage()
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if args[0] == "version" || args[0] == "--version" || args[0] == "-v" {
|
||
|
fmt.Println(appName, appVersion)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if args[0] == "export" || args[0] == "-e" {
|
||
|
gojs.ExportForDev()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cmd := ""
|
||
|
if len(args) > 0 && (args[0] == "start" || args[0] == "stop" || args[0] == "restart") {
|
||
|
cmd = args[0]
|
||
|
args = args[1:]
|
||
|
}
|
||
|
|
||
|
id := ""
|
||
|
if len(args) > 1 && args[0] == "-id" {
|
||
|
id = strings.TrimSpace(args[1])
|
||
|
args = args[2:]
|
||
|
}
|
||
|
|
||
|
mainFile := "main.js"
|
||
|
if len(args) > 1 && args[0] == "-main" {
|
||
|
mainFile = strings.TrimSpace(args[1])
|
||
|
args = args[2:]
|
||
|
}
|
||
|
if !u.FileExists(mainFile) {
|
||
|
log.DefaultLogger.Error("main file not found", "mainFile", mainFile)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if id == "" {
|
||
|
id = fmt.Sprintf("%s_%s_%s", appName, mainFile, appVersion)
|
||
|
}
|
||
|
|
||
|
id = idFixMatcher.ReplaceAllString(id, "_")
|
||
|
homeDir, _ := os.UserHomeDir()
|
||
|
pidFile := filepath.Join(homeDir, ".pids", id+".pid")
|
||
|
pid := u.Int(u.ReadFileN(pidFile))
|
||
|
fmt.Println(appName, appVersion, mainFile, id, pidFile, pid)
|
||
|
switch cmd {
|
||
|
case "start":
|
||
|
if pid > 0 && checkProcess(pid) {
|
||
|
log.DefaultLogger.Info("process already started", "pid", pid)
|
||
|
} else {
|
||
|
startProcess(pidFile, mainFile)
|
||
|
}
|
||
|
case "stop":
|
||
|
if pid > 0 {
|
||
|
killProcess(pid, mainFile)
|
||
|
_ = os.Remove(pidFile)
|
||
|
}
|
||
|
case "restart":
|
||
|
if pid > 0 {
|
||
|
killProcess(pid, mainFile)
|
||
|
_ = os.Remove(pidFile)
|
||
|
}
|
||
|
startProcess(pidFile, mainFile)
|
||
|
default:
|
||
|
gojs.RunFile(mainFile, u.ToInterfaceArray(args)...)
|
||
|
gojs.WaitAll()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func startProcess(pidFile string, mainFile string) {
|
||
|
var cmd *exec.Cmd
|
||
|
cmd = exec.Command(os.Args[0], "-main", mainFile)
|
||
|
cmd.Stdout = os.Stdout
|
||
|
cmd.Stderr = os.Stderr
|
||
|
if err := cmd.Start(); err == nil {
|
||
|
u.WriteFile(pidFile, u.String(cmd.Process.Pid))
|
||
|
log.DefaultLogger.Info("started", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", cmd.Process.Pid)
|
||
|
} else {
|
||
|
log.DefaultLogger.Error("start failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "err", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// func killProcess1(pid int) error {
|
||
|
// switch runtime.GOOS {
|
||
|
// case "windows":
|
||
|
// // Windows 系统使用 taskkill 命令
|
||
|
// cmd := exec.Command("taskkill", "/F", "/PID", fmt.Sprintf("%d", pid))
|
||
|
// return cmd.Run()
|
||
|
// case "linux", "darwin":
|
||
|
// // Linux 和 macOS 系统使用 syscall.Kill
|
||
|
// return syscall.Kill(pid, syscall.SIGKILL)
|
||
|
// default:
|
||
|
// return fmt.Errorf("unsupported platform")
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
func kill(pid int, sig os.Signal) error {
|
||
|
if proc, err := os.FindProcess(pid); err == nil {
|
||
|
return proc.Signal(sig)
|
||
|
} else {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func killProcess(pid int, mainFile string) {
|
||
|
if err := kill(pid, syscall.SIGTERM); err == nil {
|
||
|
log.DefaultLogger.Info("killing", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||
|
t1 := time.Now().UnixMilli()
|
||
|
for i := 0; i < 100; i++ {
|
||
|
if !checkProcess(pid) {
|
||
|
log.DefaultLogger.Info("killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "usedTime", (time.Duration(time.Now().UnixMilli()-t1) * time.Millisecond).String())
|
||
|
return
|
||
|
}
|
||
|
time.Sleep(100 * time.Millisecond)
|
||
|
}
|
||
|
err := kill(pid, syscall.SIGKILL)
|
||
|
if checkProcess(pid) {
|
||
|
log.DefaultLogger.Error("fource kill failed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid, "err", err)
|
||
|
} else {
|
||
|
log.DefaultLogger.Info("fource killed", "appName", appName, "appVersion", appVersion, "mainFile", mainFile, "pid", pid)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func checkProcess(pid int) bool {
|
||
|
// return kill(pid, 0) == nil
|
||
|
_, err := os.FindProcess(pid)
|
||
|
return err == nil
|
||
|
}
|
||
|
|
||
|
func printUsage() {
|
||
|
fmt.Println(appName, appVersion)
|
||
|
fmt.Println("Usage:")
|
||
|
fmt.Println(" ", appName, "[-main mainFile] ...", "run script")
|
||
|
fmt.Println(" ", appName, "version", "- show version")
|
||
|
fmt.Println(" ", appName, "export", "- export for development")
|
||
|
fmt.Println(" ", appName, "start [-id id] [-main mainFile]", "start server")
|
||
|
fmt.Println(" ", appName, "stop [-id id]", "stop server")
|
||
|
fmt.Println(" ", appName, "restart [-id id] [-main mainFile]", "restart server")
|
||
|
fmt.Println(" ", appName, "help", "- show help")
|
||
|
}
|