caddydash/apic/run.go
wjqserver b10790c212 init
2025-06-20 16:33:27 +08:00

170 lines
4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package apic
import (
"caddydash/config"
"context"
"log"
"os"
"os/exec"
"sync"
"time"
"github.com/infinite-iroha/touka"
)
type CaddyRunning struct {
running bool
mu sync.Mutex
}
func (c *CaddyRunning) IsRunning() bool {
c.mu.Lock()
defer c.mu.Unlock()
return c.running
}
func (c *CaddyRunning) SetRunning(running bool) {
c.mu.Lock()
defer c.mu.Unlock()
c.running = running
}
var caddyRunning = &CaddyRunning{}
func RunCaddy(cfg *config.Config) error {
if caddyRunning.IsRunning() {
return nil
}
ctx, cancel := context.WithCancel(context.Background())
caddyPath := cfg.Server.CaddyDir + "caddy"
cmd := exec.CommandContext(ctx, caddyPath, "run", "--config", "Caddyfile")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
caddyRunning.SetRunning(true)
err := cmd.Start()
if err != nil {
cancel()
return err
}
go func() {
waitErr := cmd.Wait()
caddyRunning.SetRunning(false)
log.Printf("Caddy process exited with error: %v", waitErr)
cancel()
if waitErr != nil {
// 如果 Caddy 非正常退出例如崩溃Wait() 会返回 *exec.ExitError
// 对于优雅关闭,如果 Caddy 接收到 SIGTERM 并正常退出Wait() 返回 nil
// 只有当进程以非零状态码退出时Wait() 才返回非 nil 的 ExitError
// 这里的日志输出应由外部日志库处理而不是标准库log
if exitErr, ok := waitErr.(*exec.ExitError); ok {
log.Printf("Caddy process exited with non-zero status: %v", exitErr)
} else {
log.Printf("Caddy process exited with error: %v", waitErr)
}
} else {
log.Println("Caddy process exited gracefully.")
}
}()
return nil
}
func StartCaddy(cfg *config.Config) touka.HandlerFunc {
return func(c *touka.Context) {
if caddyRunning.IsRunning() {
c.JSON(200, map[string]string{"message": "Caddy is already running"})
return
}
go func() {
err := RunCaddy(cfg)
if err != nil {
c.Errorf("Failed to start Caddy: %v", err)
c.JSON(500, map[string]string{"error": err.Error()})
return
}
}()
c.JSON(200, map[string]string{"message": "Caddy is starting"})
}
}
func IsCaddyRunning() touka.HandlerFunc {
return func(c *touka.Context) {
if caddyRunning.IsRunning() {
c.JSON(200, map[string]string{"message": "Caddy is running"})
} else {
c.JSON(200, map[string]string{"message": "Caddy is not running"})
}
}
}
func StopCaddy() touka.HandlerFunc {
return func(c *touka.Context) {
if !caddyRunning.IsRunning() {
c.JSON(200, map[string]string{"message": "Caddy is not running"})
return
}
client := c.GetHTTPC()
rb := client.NewRequestBuilder("POST", "http://127.0.0.1:2019/stop")
resp, err := rb.Execute()
if err != nil {
c.JSON(500, map[string]string{"error": err.Error()})
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
c.JSON(resp.StatusCode, map[string]string{"error": "Failed to stop Caddy"})
return
}
caddyRunning.SetRunning(false)
c.JSON(200, map[string]string{"message": "Caddy stopped successfully"})
}
}
func RestartCaddy(cfg *config.Config) touka.HandlerFunc {
return func(c *touka.Context) {
if !caddyRunning.IsRunning() {
c.JSON(200, map[string]string{"message": "Caddy is not running, starting it now"})
go func() {
err := RunCaddy(cfg)
if err != nil {
c.Errorf("Failed to start Caddy: %v", err)
}
}()
return
}
// StopCaddy
client := c.GetHTTPC()
rb := client.NewRequestBuilder("POST", "http://127.0.0.1:2019/stop")
resp, err := rb.Execute()
if err != nil {
c.JSON(500, map[string]string{"error": err.Error()})
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
c.JSON(resp.StatusCode, map[string]string{"error": "Failed to stop Caddy for restart"})
return
}
// 等待caddy关闭
for caddyRunning.IsRunning() {
time.Sleep(500 * time.Millisecond) // 等待500ms
}
// StartCaddy
go func() {
err := RunCaddy(cfg)
if err != nil {
c.Errorf("Failed to restart Caddy: %v", err)
}
}()
c.JSON(200, map[string]string{"message": "Caddy is restarting"})
}
}