This commit is contained in:
wjqserver 2025-06-20 16:33:27 +08:00
commit b10790c212
40 changed files with 4149 additions and 0 deletions

170
apic/run.go Normal file
View file

@ -0,0 +1,170 @@
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"})
}
}